fix: manage widgets integrations (#6331)
* wip * chore: wip * fix: preserved old component * fix * fix: seperate route added * fix * Only return user ID of project members * Return issue ID * fix: recents api integrations * fix: types * fix: types * fix: added tooltips * chore: added apis * fix: widgets fix * fix: lint * fix: integrated dashboard apis * fix: added ee dummy component for header * fix: removed logs --------- Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
This commit is contained in:
parent
edb68a1bc6
commit
0af9b09844
16 changed files with 110 additions and 74 deletions
4
packages/types/src/home.d.ts
vendored
4
packages/types/src/home.d.ts
vendored
|
|
@ -2,7 +2,7 @@ import { TLogoProps } from "./common";
|
|||
import { TIssuePriorities } from "./issues";
|
||||
|
||||
export type TRecentActivityFilterKeys = "all item" | "issue" | "page" | "project";
|
||||
export type THomeWidgetKeys = "quick_links" | "recent_activity" | "stickies";
|
||||
export type THomeWidgetKeys = "quick_links" | "recents" | "my_stickies" | "quick_tutorial" | "new_at_plane";
|
||||
|
||||
export type THomeWidgetProps = {
|
||||
workspaceSlug: string;
|
||||
|
|
@ -69,7 +69,7 @@ export type TLinkIdMap = {
|
|||
};
|
||||
|
||||
export type TWidgetEntityData = {
|
||||
key: string;
|
||||
key: THomeWidgetKeys;
|
||||
name: string;
|
||||
is_enabled: boolean;
|
||||
sort_order: number;
|
||||
|
|
|
|||
|
|
@ -12,18 +12,20 @@ import { DashboardQuickLinks } from "./widgets/links";
|
|||
import { ManageWidgetsModal } from "./widgets/manage";
|
||||
|
||||
const WIDGETS_LIST: {
|
||||
[key in THomeWidgetKeys]: { component: React.FC<THomeWidgetProps>; fullWidth: boolean };
|
||||
[key in THomeWidgetKeys]: { component: React.FC<THomeWidgetProps> | null; fullWidth: boolean };
|
||||
} = {
|
||||
quick_links: { component: DashboardQuickLinks, fullWidth: false },
|
||||
recent_activity: { component: RecentActivityWidget, fullWidth: false },
|
||||
stickies: { component: StickiesWidget, fullWidth: false },
|
||||
recents: { component: RecentActivityWidget, fullWidth: false },
|
||||
my_stickies: { component: StickiesWidget, fullWidth: false },
|
||||
new_at_plane: { component: null, fullWidth: false },
|
||||
quick_tutorial: { component: null, fullWidth: false },
|
||||
};
|
||||
|
||||
export const DashboardWidgets = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
// store hooks
|
||||
const { toggleWidgetSettings, showWidgetSettings } = useHome();
|
||||
const { toggleWidgetSettings, widgetsMap, showWidgetSettings, orderedWidgets } = useHome();
|
||||
|
||||
if (!workspaceSlug) return null;
|
||||
|
||||
|
|
@ -36,9 +38,11 @@ export const DashboardWidgets = observer(() => {
|
|||
handleOnClose={() => toggleWidgetSettings(false)}
|
||||
/>
|
||||
|
||||
{Object.entries(WIDGETS_LIST).map(([key, widget]) => {
|
||||
const WidgetComponent = widget.component;
|
||||
if (widget.fullWidth)
|
||||
{orderedWidgets.map((key) => {
|
||||
const WidgetComponent = WIDGETS_LIST[key]?.component;
|
||||
const isEnabled = widgetsMap[key]?.is_enabled;
|
||||
if (!WidgetComponent || !isEnabled) return null;
|
||||
if (WIDGETS_LIST[key]?.fullWidth)
|
||||
return (
|
||||
<div key={key} className="lg:col-span-2">
|
||||
<WidgetComponent workspaceSlug={workspaceSlug.toString()} />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// components
|
||||
import useSWR from "swr";
|
||||
import { ContentWrapper } from "@plane/ui";
|
||||
import { EmptyState } from "@/components/empty-state";
|
||||
import { TourRoot } from "@/components/onboarding";
|
||||
|
|
@ -11,7 +11,7 @@ import { PRODUCT_TOUR_COMPLETED } from "@/constants/event-tracker";
|
|||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useCommandPalette, useUserProfile, useEventTracker, useDashboard, useProject, useUser } from "@/hooks/store";
|
||||
import { useCommandPalette, useUserProfile, useEventTracker, useProject, useUser } from "@/hooks/store";
|
||||
import { useHome } from "@/hooks/store/use-home";
|
||||
import useSize from "@/hooks/use-window-size";
|
||||
import { IssuePeekOverview } from "../issues";
|
||||
|
|
@ -29,12 +29,20 @@ export const WorkspaceHomeView = observer(() => {
|
|||
const { data: currentUser } = useUser();
|
||||
const { data: currentUserProfile, updateTourCompleted } = useUserProfile();
|
||||
const { captureEvent } = useEventTracker();
|
||||
const { homeDashboardId, fetchHomeDashboardWidgets } = useDashboard();
|
||||
const { toggleWidgetSettings } = useHome();
|
||||
const { toggleWidgetSettings, fetchWidgets } = useHome();
|
||||
const { joinedProjectIds, loader } = useProject();
|
||||
|
||||
const [windowWidth] = useSize();
|
||||
|
||||
useSWR(
|
||||
workspaceSlug ? `HOME_DASHBOARD_WIDGETS_${workspaceSlug}` : null,
|
||||
workspaceSlug ? () => fetchWidgets(workspaceSlug?.toString()) : null,
|
||||
{
|
||||
revalidateIfStale: true,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: true,
|
||||
}
|
||||
);
|
||||
|
||||
const handleTourCompleted = () => {
|
||||
updateTourCompleted()
|
||||
.then(() => {
|
||||
|
|
@ -48,13 +56,6 @@ export const WorkspaceHomeView = observer(() => {
|
|||
});
|
||||
};
|
||||
|
||||
// fetch home dashboard widgets on workspace change
|
||||
useEffect(() => {
|
||||
if (!workspaceSlug) return;
|
||||
|
||||
fetchHomeDashboardWidgets(workspaceSlug?.toString());
|
||||
}, [fetchHomeDashboardWidgets, workspaceSlug]);
|
||||
|
||||
// TODO: refactor loader implementation
|
||||
return (
|
||||
<>
|
||||
|
|
@ -63,7 +64,7 @@ export const WorkspaceHomeView = observer(() => {
|
|||
<TourRoot onComplete={handleTourCompleted} />
|
||||
</div>
|
||||
)}
|
||||
{homeDashboardId && joinedProjectIds && (
|
||||
{joinedProjectIds && (
|
||||
<>
|
||||
{joinedProjectIds.length > 0 || loader ? (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -51,13 +51,13 @@ export const UserGreetingsView: FC<IUserGreetingsView> = (props) => {
|
|||
</div>
|
||||
</h6>
|
||||
</div>
|
||||
{/* <button
|
||||
<button
|
||||
onClick={handleWidgetModal}
|
||||
className="flex items-center gap-2 font-medium text-custom-text-300 justify-center border border-custom-border-200 rounded p-2 my-auto mb-0"
|
||||
>
|
||||
<Shapes size={16} />
|
||||
<div className="text-xs font-medium">Manage widgets</div>
|
||||
</button> */}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import { FC, useEffect, useState } from "react";
|
|||
import { observer } from "mobx-react";
|
||||
// computed
|
||||
import { useHome } from "@/hooks/store/use-home";
|
||||
import { EWidgetKeys, WidgetLoader } from "../loaders";
|
||||
import { AddLink } from "./action";
|
||||
import { ProjectLinkDetail } from "./link-detail";
|
||||
import { TLinkOperations } from "./use-links";
|
||||
import { EWidgetKeys, WidgetLoader } from "../loaders";
|
||||
|
||||
export type TLinkOperationsModal = Exclude<TLinkOperations, "create">;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { observer } from "mobx-react";
|
||||
import useSWR from "swr";
|
||||
import { THomeWidgetProps } from "@plane/types";
|
||||
import { useHome } from "@/hooks/store/use-home";
|
||||
import { LinkCreateUpdateModal } from "./create-update-link-modal";
|
||||
import { ProjectLinkList } from "./links";
|
||||
import { useLinks } from "./use-links";
|
||||
import { THomeWidgetProps } from "@plane/types";
|
||||
|
||||
export const DashboardQuickLinks = observer((props: THomeWidgetProps) => {
|
||||
const { workspaceSlug } = props;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// components
|
||||
import { RecentActivityWidgetLoader } from "./recent-activity";
|
||||
import { QuickLinksWidgetLoader } from "./quick-links";
|
||||
import { RecentActivityWidgetLoader } from "./recent-activity";
|
||||
|
||||
// types
|
||||
|
||||
|
|
|
|||
|
|
@ -14,38 +14,45 @@ import { attachInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree
|
|||
|
||||
import { observer } from "mobx-react";
|
||||
// plane helpers
|
||||
import { useParams } from "next/navigation";
|
||||
import { createRoot } from "react-dom/client";
|
||||
// ui
|
||||
import { InstructionType } from "@plane/types";
|
||||
import { InstructionType, TWidgetEntityData } from "@plane/types";
|
||||
// components
|
||||
import { DropIndicator, ToggleSwitch } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@plane/utils";
|
||||
import { useHome } from "@/hooks/store/use-home";
|
||||
import { WidgetItemDragHandle } from "./widget-item-drag-handle";
|
||||
import { getCanDrop, getInstructionFromPayload } from "./widget.helpers";
|
||||
|
||||
type Props = {
|
||||
widgetId: string;
|
||||
isLastChild: boolean;
|
||||
widget: any;
|
||||
handleDrop: (self: DropTargetRecord, source: ElementDragPayload, location: DragLocationHistory) => void;
|
||||
handleToggle: (workspaceSlug: string, widgetKey: string, is_enabled: boolean) => void;
|
||||
};
|
||||
|
||||
export const WidgetItem: FC<Props> = observer((props) => {
|
||||
// props
|
||||
const { isLastChild, widget, handleDrop } = props;
|
||||
const { widgetId, isLastChild, handleDrop, handleToggle } = props;
|
||||
const { workspaceSlug } = useParams();
|
||||
//state
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [instruction, setInstruction] = useState<InstructionType | undefined>(undefined);
|
||||
|
||||
//ref
|
||||
const elementRef = useRef<HTMLDivElement>(null);
|
||||
// hooks
|
||||
const { widgetsMap } = useHome();
|
||||
// derived values
|
||||
const widget = widgetsMap[widgetId] as TWidgetEntityData;
|
||||
|
||||
// drag and drop
|
||||
useEffect(() => {
|
||||
const element = elementRef.current;
|
||||
|
||||
if (!element) return;
|
||||
const initialData = { id: widget.id, isGroup: false };
|
||||
const initialData = { id: widget.key, isGroup: false };
|
||||
return combine(
|
||||
draggable({
|
||||
element,
|
||||
|
|
@ -62,7 +69,7 @@ export const WidgetItem: FC<Props> = observer((props) => {
|
|||
getOffset: pointerOutsideOfPreview({ x: "0px", y: "0px" }),
|
||||
render: ({ container }) => {
|
||||
const root = createRoot(container);
|
||||
root.render(<div className="rounded bg-custom-background-100 text-sm p-1 pr-2">{widget.title}</div>);
|
||||
root.render(<div className="rounded bg-custom-background-100 text-sm p-1 pr-2">{widget.key}</div>);
|
||||
return () => root.unmount();
|
||||
},
|
||||
nativeSetDragImage,
|
||||
|
|
@ -104,7 +111,7 @@ export const WidgetItem: FC<Props> = observer((props) => {
|
|||
})
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [elementRef?.current, isDragging, isLastChild, widget.id]);
|
||||
}, [elementRef?.current, isDragging, isLastChild, widget.key]);
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
|
|
@ -120,9 +127,12 @@ export const WidgetItem: FC<Props> = observer((props) => {
|
|||
>
|
||||
<div className="flex items-center">
|
||||
<WidgetItemDragHandle sort_order={widget.sort_order} isDragging={isDragging} />
|
||||
<div>{widget.title}</div>
|
||||
<div>{widget.key.replaceAll("_", " ")}</div>
|
||||
</div>
|
||||
{/* <ToggleSwitch /> */}
|
||||
<ToggleSwitch
|
||||
value={widget.is_enabled}
|
||||
onChange={() => handleToggle(workspaceSlug.toString(), widget.key, !widget.is_enabled)}
|
||||
/>
|
||||
</div>
|
||||
{isLastChild && <DropIndicator isVisible={instruction === "reorder-below"} />}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,17 +3,14 @@ import {
|
|||
DropTargetRecord,
|
||||
ElementDragPayload,
|
||||
} from "@atlaskit/pragmatic-drag-and-drop/dist/types/internal-types";
|
||||
import { observer } from "mobx-react";
|
||||
import { setToast, TOAST_TYPE } from "@plane/ui";
|
||||
import { useHome } from "@/hooks/store/use-home";
|
||||
import { WidgetItem } from "./widget-item";
|
||||
import { getInstructionFromPayload, TargetData } from "./widget.helpers";
|
||||
|
||||
const WIDGETS_LIST = [
|
||||
{ id: 1, title: "quick links" },
|
||||
{ id: 2, title: "recents" },
|
||||
{ id: 3, title: "stickies" },
|
||||
];
|
||||
export const WidgetList = ({ workspaceSlug }: { workspaceSlug: string }) => {
|
||||
const { reorderWidget } = useHome();
|
||||
export const WidgetList = observer(({ workspaceSlug }: { workspaceSlug: string }) => {
|
||||
const { orderedWidgets, reorderWidget, toggleWidget } = useHome();
|
||||
|
||||
const handleDrop = (self: DropTargetRecord, source: ElementDragPayload, location: DragLocationHistory) => {
|
||||
const dropTargets = location?.current?.dropTargets ?? [];
|
||||
|
|
@ -30,20 +27,34 @@ export const WidgetList = ({ workspaceSlug }: { workspaceSlug: string }) => {
|
|||
|
||||
if (!sourceData.id) return;
|
||||
if (droppedId) {
|
||||
reorderWidget(workspaceSlug, sourceData.id, droppedId, instruction); /** sequence */
|
||||
try {
|
||||
reorderWidget(workspaceSlug, sourceData.id, droppedId, instruction); /** sequence */
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
title: "Success!",
|
||||
message: "Widget reordered successfully.",
|
||||
});
|
||||
} catch {
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Error!",
|
||||
message: "Error occurred while reordering widget.",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="my-4">
|
||||
{WIDGETS_LIST.map((widget, index) => (
|
||||
{orderedWidgets.map((widget, index) => (
|
||||
<WidgetItem
|
||||
key={widget.id}
|
||||
widget={widget}
|
||||
isLastChild={index === WIDGETS_LIST.length - 1}
|
||||
key={widget}
|
||||
widgetId={widget}
|
||||
isLastChild={index === orderedWidgets.length - 1}
|
||||
handleDrop={handleDrop}
|
||||
handleToggle={toggleWidget}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
|
||||
import { IFavorite, InstructionType, IPragmaticPayloadLocation, TDropTarget } from "@plane/types";
|
||||
import { InstructionType, IPragmaticPayloadLocation, TDropTarget, TWidgetEntityData } from "@plane/types";
|
||||
|
||||
export type TargetData = {
|
||||
id: string;
|
||||
|
|
@ -11,7 +11,7 @@ export type TargetData = {
|
|||
/**
|
||||
* extracts the Payload and translates the instruction for the current dropTarget based on drag and drop payload
|
||||
* @param dropTarget dropTarget for which the instruction is required
|
||||
* @param source the dragging favorite data that is being dragged on the dropTarget
|
||||
* @param source the dragging widget data that is being dragged on the dropTarget
|
||||
* @param location location includes the data of all the dropTargets the source is being dragged on
|
||||
* @returns Instruction for dropTarget
|
||||
*/
|
||||
|
|
@ -37,7 +37,7 @@ export const getInstructionFromPayload = (
|
|||
instruction = dropTargetData.isChild ? "reorder-above" : "make-child";
|
||||
}
|
||||
|
||||
// if source that is being dragged is a group. A group cannon be a child of any other favorite,
|
||||
// if source that is being dragged is a group. A group cannon be a child of any other widget,
|
||||
// hence if current instruction is to be a child of dropTarget then reorder-above instead
|
||||
if (instruction === "make-child" && sourceData.isGroup) instruction = "reorder-above";
|
||||
|
||||
|
|
@ -45,18 +45,18 @@ export const getInstructionFromPayload = (
|
|||
};
|
||||
|
||||
/**
|
||||
* This provides a boolean to indicate if the favorite can be dropped onto the droptarget
|
||||
* This provides a boolean to indicate if the widget can be dropped onto the droptarget
|
||||
* @param source
|
||||
* @param favorite
|
||||
* @param widget
|
||||
* @returns
|
||||
*/
|
||||
export const getCanDrop = (source: TDropTarget, favorite: IFavorite | undefined) => {
|
||||
export const getCanDrop = (source: TDropTarget, widget: TWidgetEntityData | undefined) => {
|
||||
const sourceData = source?.data;
|
||||
|
||||
if (!sourceData) return false;
|
||||
|
||||
// a favorite cannot be dropped on to itself
|
||||
if (sourceData.id === favorite?.id) return false;
|
||||
// a widget cannot be dropped on to itself
|
||||
if (sourceData.id === widget?.key) return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import { TRecentActivityFilterKeys } from "@plane/types";
|
||||
import { CustomMenu } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
import { TRecentActivityFilterKeys } from "@plane/types";
|
||||
|
||||
export type TFiltersDropdown = {
|
||||
className?: string;
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@
|
|||
import { useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// types
|
||||
import useSWR from "swr";
|
||||
import { Briefcase, FileText } from "lucide-react";
|
||||
import { TActivityEntityData, THomeWidgetProps, TRecentActivityFilterKeys } from "@plane/types";
|
||||
// components
|
||||
import { LayersIcon } from "@plane/ui";
|
||||
import { WorkspaceService } from "@/plane-web/services";
|
||||
import { EmptyWorkspace } from "../empty-states";
|
||||
import { EWidgetKeys, WidgetLoader } from "../loaders";
|
||||
import { FiltersDropdown } from "./filters";
|
||||
import { RecentIssue } from "./issue";
|
||||
import { WorkspaceService } from "@/plane-web/services";
|
||||
import useSWR from "swr";
|
||||
import { RecentProject } from "./project";
|
||||
import { RecentPage } from "./page";
|
||||
import { EWidgetKeys, WidgetLoader } from "../loaders";
|
||||
import { Briefcase, FileText } from "lucide-react";
|
||||
import { LayersIcon } from "@plane/ui";
|
||||
import { EmptyWorkspace } from "../empty-states";
|
||||
import { RecentProject } from "./project";
|
||||
|
||||
const WIDGET_KEY = EWidgetKeys.RECENT_ACTIVITY;
|
||||
const workspaceService = new WorkspaceService();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { useRouter } from "next/navigation";
|
||||
import { FileText } from "lucide-react";
|
||||
import { TActivityEntityData, TPageEntityData } from "@plane/types";
|
||||
import { Avatar, Logo } from "@plane/ui";
|
||||
import { getFileURL } from "@plane/utils";
|
||||
import { ListItem } from "@/components/core/list";
|
||||
import { calculateTimeAgo } from "@/helpers/date-time.helper";
|
||||
import { FileText } from "lucide-react";
|
||||
import { getFileURL } from "@plane/utils";
|
||||
import { useMember } from "@/hooks/store";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
type BlockProps = {
|
||||
activity: TActivityEntityData;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useRouter } from "next/navigation";
|
||||
import { TActivityEntityData, TProjectEntityData } from "@plane/types";
|
||||
import { Logo } from "@plane/ui";
|
||||
import { ListItem } from "@/components/core/list";
|
||||
import { calculateTimeAgo } from "@/helpers/date-time.helper";
|
||||
import { MemberDropdown } from "@/components/dropdowns";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { calculateTimeAgo } from "@/helpers/date-time.helper";
|
||||
|
||||
type BlockProps = {
|
||||
activity: TActivityEntityData;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import orderBy from "lodash/orderBy";
|
||||
import set from "lodash/set";
|
||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||
import { TWidgetEntityData } from "@plane/types";
|
||||
import { action, computed, makeObservable, observable, runInAction } from "mobx";
|
||||
import { THomeWidgetKeys, TWidgetEntityData } from "@plane/types";
|
||||
import { WorkspaceService } from "@/plane-web/services";
|
||||
import { IWorkspaceLinkStore, WorkspaceLinkStore } from "./link.store";
|
||||
|
||||
|
|
@ -9,6 +9,9 @@ export interface IHomeStore {
|
|||
// observables
|
||||
showWidgetSettings: boolean;
|
||||
widgetsMap: Record<string, TWidgetEntityData>;
|
||||
widgets: THomeWidgetKeys[];
|
||||
// computed
|
||||
orderedWidgets: THomeWidgetKeys[];
|
||||
//stores
|
||||
quickLinks: IWorkspaceLinkStore;
|
||||
// actions
|
||||
|
|
@ -22,7 +25,7 @@ export class HomeStore implements IHomeStore {
|
|||
// observables
|
||||
showWidgetSettings = false;
|
||||
widgetsMap: Record<string, TWidgetEntityData> = {};
|
||||
widgets: string[] = [];
|
||||
widgets: THomeWidgetKeys[] = [];
|
||||
// stores
|
||||
quickLinks: IWorkspaceLinkStore;
|
||||
// services
|
||||
|
|
@ -34,6 +37,8 @@ export class HomeStore implements IHomeStore {
|
|||
showWidgetSettings: observable,
|
||||
widgetsMap: observable,
|
||||
widgets: observable,
|
||||
// computed
|
||||
orderedWidgets: computed,
|
||||
// actions
|
||||
toggleWidgetSettings: action,
|
||||
fetchWidgets: action,
|
||||
|
|
@ -47,6 +52,10 @@ export class HomeStore implements IHomeStore {
|
|||
this.quickLinks = new WorkspaceLinkStore();
|
||||
}
|
||||
|
||||
get orderedWidgets() {
|
||||
return orderBy(Object.values(this.widgetsMap), "sort_order", "desc").map((widget) => widget.key);
|
||||
}
|
||||
|
||||
toggleWidgetSettings = (value?: boolean) => {
|
||||
this.showWidgetSettings = value !== undefined ? value : !this.showWidgetSettings;
|
||||
};
|
||||
|
|
@ -55,7 +64,7 @@ export class HomeStore implements IHomeStore {
|
|||
try {
|
||||
const widgets = await this.workspaceService.fetchWorkspaceWidgets(workspaceSlug);
|
||||
runInAction(() => {
|
||||
this.widgets = widgets.map((widget) => widget.key);
|
||||
this.widgets = orderBy(Object.values(widgets), "sort_order", "desc").map((widget) => widget.key);
|
||||
widgets.forEach((widget) => {
|
||||
this.widgetsMap[widget.key] = widget;
|
||||
});
|
||||
|
|
|
|||
1
web/ee/components/home/header.tsx
Normal file
1
web/ee/components/home/header.tsx
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const HomePageHeader = () => <></>;
|
||||
Loading…
Add table
Add a link
Reference in a new issue