mirror of
https://github.com/makeplane/plane.git
synced 2026-02-17 12:21:00 -06:00
refactor: enhance command palette modularity (#6139)
* refactor: enhance command palette modularity * chore: minor updates to command palette store
This commit is contained in:
15
packages/types/src/command-palette.d.ts
vendored
Normal file
15
packages/types/src/command-palette.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export type TCommandPaletteActionList = Record<
|
||||
string,
|
||||
{ title: string; description: string; action: () => void }
|
||||
>;
|
||||
|
||||
export type TCommandPaletteShortcutList = {
|
||||
key: string;
|
||||
title: string;
|
||||
shortcuts: TCommandPaletteShortcut[];
|
||||
};
|
||||
|
||||
export type TCommandPaletteShortcut = {
|
||||
keys: string; // comma separated keys
|
||||
description: string;
|
||||
};
|
||||
1
packages/types/src/index.d.ts
vendored
1
packages/types/src/index.d.ts
vendored
@@ -32,3 +32,4 @@ export * from "./workspace-notifications";
|
||||
export * from "./favorite";
|
||||
export * from "./file";
|
||||
export * from "./workspace-draft-issues/base";
|
||||
export * from "./command-palette";
|
||||
|
||||
3
web/ce/components/command-palette/modals/index.ts
Normal file
3
web/ce/components/command-palette/modals/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./workspace-level";
|
||||
export * from "./project-level";
|
||||
export * from "./issue-level";
|
||||
73
web/ce/components/command-palette/modals/issue-level.tsx
Normal file
73
web/ce/components/command-palette/modals/issue-level.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
import useSWR from "swr";
|
||||
// components
|
||||
import { BulkDeleteIssuesModal } from "@/components/core";
|
||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "@/components/issues";
|
||||
// constants
|
||||
import { ISSUE_DETAILS } from "@/constants/fetch-keys";
|
||||
// hooks
|
||||
import { useCommandPalette, useUser } from "@/hooks/store";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useIssuesStore } from "@/hooks/use-issue-layout-store";
|
||||
// services
|
||||
import { IssueService } from "@/services/issue";
|
||||
|
||||
// services
|
||||
const issueService = new IssueService();
|
||||
|
||||
export const IssueLevelModals = observer(() => {
|
||||
// router
|
||||
const pathname = usePathname();
|
||||
const { workspaceSlug, projectId, issueId, cycleId, moduleId } = useParams();
|
||||
const router = useAppRouter();
|
||||
// store hooks
|
||||
const { data: currentUser } = useUser();
|
||||
const {
|
||||
issues: { removeIssue },
|
||||
} = useIssuesStore();
|
||||
const {
|
||||
isCreateIssueModalOpen,
|
||||
toggleCreateIssueModal,
|
||||
isDeleteIssueModalOpen,
|
||||
toggleDeleteIssueModal,
|
||||
isBulkDeleteIssueModalOpen,
|
||||
toggleBulkDeleteIssueModal,
|
||||
} = useCommandPalette();
|
||||
// derived values
|
||||
const isDraftIssue = pathname?.includes("draft-issues") || false;
|
||||
|
||||
const { data: issueDetails } = useSWR(
|
||||
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
|
||||
workspaceSlug && projectId && issueId
|
||||
? () => issueService.retrieve(workspaceSlug as string, projectId as string, issueId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<CreateUpdateIssueModal
|
||||
isOpen={isCreateIssueModalOpen}
|
||||
onClose={() => toggleCreateIssueModal(false)}
|
||||
data={cycleId ? { cycle_id: cycleId.toString() } : moduleId ? { module_ids: [moduleId.toString()] } : undefined}
|
||||
isDraft={isDraftIssue}
|
||||
/>
|
||||
{workspaceSlug && projectId && issueId && issueDetails && (
|
||||
<DeleteIssueModal
|
||||
handleClose={() => toggleDeleteIssueModal(false)}
|
||||
isOpen={isDeleteIssueModalOpen}
|
||||
data={issueDetails}
|
||||
onSubmit={async () => {
|
||||
await removeIssue(workspaceSlug.toString(), projectId.toString(), issueId.toString());
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<BulkDeleteIssuesModal
|
||||
isOpen={isBulkDeleteIssueModalOpen}
|
||||
onClose={() => toggleBulkDeleteIssueModal(false)}
|
||||
user={currentUser}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
59
web/ce/components/command-palette/modals/project-level.tsx
Normal file
59
web/ce/components/command-palette/modals/project-level.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { observer } from "mobx-react";
|
||||
// components
|
||||
import { CycleCreateUpdateModal } from "@/components/cycles";
|
||||
import { CreateUpdateModuleModal } from "@/components/modules";
|
||||
import { CreatePageModal } from "@/components/pages";
|
||||
import { CreateUpdateProjectViewModal } from "@/components/views";
|
||||
// hooks
|
||||
import { useCommandPalette } from "@/hooks/store";
|
||||
|
||||
export type TProjectLevelModalsProps = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export const ProjectLevelModals = observer((props: TProjectLevelModalsProps) => {
|
||||
const { workspaceSlug, projectId } = props;
|
||||
// store hooks
|
||||
const {
|
||||
isCreateCycleModalOpen,
|
||||
toggleCreateCycleModal,
|
||||
isCreateModuleModalOpen,
|
||||
toggleCreateModuleModal,
|
||||
isCreateViewModalOpen,
|
||||
toggleCreateViewModal,
|
||||
createPageModal,
|
||||
toggleCreatePageModal,
|
||||
} = useCommandPalette();
|
||||
|
||||
return (
|
||||
<>
|
||||
<CycleCreateUpdateModal
|
||||
isOpen={isCreateCycleModalOpen}
|
||||
handleClose={() => toggleCreateCycleModal(false)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
/>
|
||||
<CreateUpdateModuleModal
|
||||
isOpen={isCreateModuleModalOpen}
|
||||
onClose={() => toggleCreateModuleModal(false)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
/>
|
||||
<CreateUpdateProjectViewModal
|
||||
isOpen={isCreateViewModalOpen}
|
||||
onClose={() => toggleCreateViewModal(false)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
/>
|
||||
<CreatePageModal
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
isModalOpen={createPageModal.isOpen}
|
||||
pageAccess={createPageModal.pageAccess}
|
||||
handleModalClose={() => toggleCreatePageModal({ isOpen: false })}
|
||||
redirectionEnabled
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
25
web/ce/components/command-palette/modals/workspace-level.tsx
Normal file
25
web/ce/components/command-palette/modals/workspace-level.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { observer } from "mobx-react";
|
||||
// components
|
||||
import { CreateProjectModal } from "@/components/project";
|
||||
// hooks
|
||||
import { useCommandPalette } from "@/hooks/store";
|
||||
|
||||
export type TWorkspaceLevelModalsProps = {
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const WorkspaceLevelModals = observer((props: TWorkspaceLevelModalsProps) => {
|
||||
const { workspaceSlug } = props;
|
||||
// store hooks
|
||||
const { isCreateProjectModalOpen, toggleCreateProjectModal } = useCommandPalette();
|
||||
|
||||
return (
|
||||
<>
|
||||
<CreateProjectModal
|
||||
isOpen={isCreateProjectModalOpen}
|
||||
onClose={() => toggleCreateProjectModal(false)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
95
web/ce/helpers/command-palette.ts
Normal file
95
web/ce/helpers/command-palette.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
// types
|
||||
import { TCommandPaletteActionList, TCommandPaletteShortcut, TCommandPaletteShortcutList } from "@plane/types";
|
||||
// store
|
||||
import { store } from "@/lib/store-context";
|
||||
|
||||
export const getGlobalShortcutsList: () => TCommandPaletteActionList = () => {
|
||||
const { toggleCreateIssueModal } = store.commandPalette;
|
||||
|
||||
return {
|
||||
c: {
|
||||
title: "Create a new issue",
|
||||
description: "Create a new issue in the current project",
|
||||
action: () => toggleCreateIssueModal(true),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const getWorkspaceShortcutsList: () => TCommandPaletteActionList = () => {
|
||||
const { toggleCreateProjectModal } = store.commandPalette;
|
||||
|
||||
return {
|
||||
p: {
|
||||
title: "Create a new project",
|
||||
description: "Create a new project in the current workspace",
|
||||
action: () => toggleCreateProjectModal(true),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const getProjectShortcutsList: () => TCommandPaletteActionList = () => {
|
||||
const {
|
||||
toggleCreatePageModal,
|
||||
toggleCreateModuleModal,
|
||||
toggleCreateCycleModal,
|
||||
toggleCreateViewModal,
|
||||
toggleBulkDeleteIssueModal,
|
||||
} = store.commandPalette;
|
||||
|
||||
return {
|
||||
d: {
|
||||
title: "Create a new page",
|
||||
description: "Create a new page in the current project",
|
||||
action: () => toggleCreatePageModal({ isOpen: true }),
|
||||
},
|
||||
m: {
|
||||
title: "Create a new module",
|
||||
description: "Create a new module in the current project",
|
||||
action: () => toggleCreateModuleModal(true),
|
||||
},
|
||||
q: {
|
||||
title: "Create a new cycle",
|
||||
description: "Create a new cycle in the current project",
|
||||
action: () => toggleCreateCycleModal(true),
|
||||
},
|
||||
v: {
|
||||
title: "Create a new view",
|
||||
description: "Create a new view in the current project",
|
||||
action: () => toggleCreateViewModal(true),
|
||||
},
|
||||
backspace: {
|
||||
title: "Bulk delete issues",
|
||||
description: "Bulk delete issues in the current project",
|
||||
action: () => toggleBulkDeleteIssueModal(true),
|
||||
},
|
||||
delete: {
|
||||
title: "Bulk delete issues",
|
||||
description: "Bulk delete issues in the current project",
|
||||
action: () => toggleBulkDeleteIssueModal(true),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const handleAdditionalKeyDownEvents = (e: KeyboardEvent) => null;
|
||||
|
||||
export const getNavigationShortcutsList = (): TCommandPaletteShortcut[] => [
|
||||
{ keys: "Ctrl,K", description: "Open command menu" },
|
||||
];
|
||||
|
||||
export const getCommonShortcutsList = (platform: string): TCommandPaletteShortcut[] => [
|
||||
{ keys: "P", description: "Create project" },
|
||||
{ keys: "C", description: "Create issue" },
|
||||
{ keys: "Q", description: "Create cycle" },
|
||||
{ keys: "M", description: "Create module" },
|
||||
{ keys: "V", description: "Create view" },
|
||||
{ keys: "D", description: "Create page" },
|
||||
{ keys: "Delete", description: "Bulk delete issues" },
|
||||
{ keys: "Shift,/", description: "Open shortcuts guide" },
|
||||
{
|
||||
keys: platform === "MacOS" ? "Ctrl,control,C" : "Ctrl,Alt,C",
|
||||
description: "Copy issue URL from the issue details page",
|
||||
},
|
||||
];
|
||||
|
||||
export const getAdditionalShortcutsList = (): TCommandPaletteShortcutList[] => [];
|
||||
12
web/ce/store/command-palette.store.ts
Normal file
12
web/ce/store/command-palette.store.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { makeObservable } from "mobx";
|
||||
// types / constants
|
||||
import { BaseCommandPaletteStore, IBaseCommandPaletteStore } from "@/store/base-command-palette.store";
|
||||
|
||||
export type ICommandPaletteStore = IBaseCommandPaletteStore;
|
||||
|
||||
export class CommandPaletteStore extends BaseCommandPaletteStore implements ICommandPaletteStore {
|
||||
constructor() {
|
||||
super();
|
||||
makeObservable(this, {});
|
||||
}
|
||||
}
|
||||
@@ -2,87 +2,43 @@
|
||||
|
||||
import React, { useCallback, useEffect, FC, useMemo } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
import useSWR from "swr";
|
||||
import { useParams } from "next/navigation";
|
||||
// ui
|
||||
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||
// components
|
||||
import { CommandModal, ShortcutsModal } from "@/components/command-palette";
|
||||
import { BulkDeleteIssuesModal } from "@/components/core";
|
||||
import { CycleCreateUpdateModal } from "@/components/cycles";
|
||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "@/components/issues";
|
||||
import { CreateUpdateModuleModal } from "@/components/modules";
|
||||
import { CreatePageModal } from "@/components/pages";
|
||||
import { CreateProjectModal } from "@/components/project";
|
||||
import { CreateUpdateProjectViewModal } from "@/components/views";
|
||||
// constants
|
||||
import { ISSUE_DETAILS } from "@/constants/fetch-keys";
|
||||
// helpers
|
||||
import { copyTextToClipboard } from "@/helpers/string.helper";
|
||||
// hooks
|
||||
import { useEventTracker, useUser, useAppTheme, useCommandPalette, useUserPermissions } from "@/hooks/store";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useIssuesStore } from "@/hooks/use-issue-layout-store";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
// plane web components
|
||||
import {
|
||||
IssueLevelModals,
|
||||
ProjectLevelModals,
|
||||
WorkspaceLevelModals,
|
||||
} from "@/plane-web/components/command-palette/modals";
|
||||
// plane web constants
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||
// services
|
||||
import { IssueService } from "@/services/issue";
|
||||
|
||||
// services
|
||||
const issueService = new IssueService();
|
||||
// plane web helpers
|
||||
import {
|
||||
getGlobalShortcutsList,
|
||||
getProjectShortcutsList,
|
||||
getWorkspaceShortcutsList,
|
||||
handleAdditionalKeyDownEvents,
|
||||
} from "@/plane-web/helpers/command-palette";
|
||||
|
||||
export const CommandPalette: FC = observer(() => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
// router params
|
||||
const { workspaceSlug, projectId, issueId, cycleId, moduleId } = useParams();
|
||||
// pathname
|
||||
const pathname = usePathname();
|
||||
const { workspaceSlug, projectId, issueId } = useParams();
|
||||
// store hooks
|
||||
const { toggleSidebar } = useAppTheme();
|
||||
const { setTrackElement } = useEventTracker();
|
||||
const { platform } = usePlatformOS();
|
||||
const {
|
||||
data: currentUser,
|
||||
// canPerformProjectMemberActions,
|
||||
// canPerformWorkspaceMemberActions,
|
||||
canPerformAnyCreateAction,
|
||||
// canPerformProjectAdminActions,
|
||||
} = useUser();
|
||||
const {
|
||||
issues: { removeIssue },
|
||||
} = useIssuesStore();
|
||||
const {
|
||||
toggleCommandPaletteModal,
|
||||
isCreateIssueModalOpen,
|
||||
toggleCreateIssueModal,
|
||||
isCreateCycleModalOpen,
|
||||
toggleCreateCycleModal,
|
||||
createPageModal,
|
||||
toggleCreatePageModal,
|
||||
isCreateProjectModalOpen,
|
||||
toggleCreateProjectModal,
|
||||
isCreateModuleModalOpen,
|
||||
toggleCreateModuleModal,
|
||||
isCreateViewModalOpen,
|
||||
toggleCreateViewModal,
|
||||
isShortcutModalOpen,
|
||||
toggleShortcutModal,
|
||||
isBulkDeleteIssueModalOpen,
|
||||
toggleBulkDeleteIssueModal,
|
||||
isDeleteIssueModalOpen,
|
||||
toggleDeleteIssueModal,
|
||||
isAnyModalOpen,
|
||||
} = useCommandPalette();
|
||||
const { data: currentUser, canPerformAnyCreateAction } = useUser();
|
||||
const { toggleCommandPaletteModal, isShortcutModalOpen, toggleShortcutModal, isAnyModalOpen } = useCommandPalette();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
const { data: issueDetails } = useSWR(
|
||||
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
|
||||
workspaceSlug && projectId && issueId
|
||||
? () => issueService.retrieve(workspaceSlug as string, projectId as string, issueId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
// derived values
|
||||
const canPerformWorkspaceMemberActions = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
@@ -170,62 +126,11 @@ export const CommandPalette: FC = observer(() => {
|
||||
project: Record<string, { title: string; description: string; action: () => void }>;
|
||||
} = useMemo(
|
||||
() => ({
|
||||
global: {
|
||||
c: {
|
||||
title: "Create a new issue",
|
||||
description: "Create a new issue in the current project",
|
||||
action: () => toggleCreateIssueModal(true),
|
||||
},
|
||||
},
|
||||
workspace: {
|
||||
p: {
|
||||
title: "Create a new project",
|
||||
description: "Create a new project in the current workspace",
|
||||
action: () => toggleCreateProjectModal(true),
|
||||
},
|
||||
},
|
||||
project: {
|
||||
d: {
|
||||
title: "Create a new page",
|
||||
description: "Create a new page in the current project",
|
||||
action: () => toggleCreatePageModal({ isOpen: true }),
|
||||
},
|
||||
m: {
|
||||
title: "Create a new module",
|
||||
description: "Create a new module in the current project",
|
||||
action: () => toggleCreateModuleModal(true),
|
||||
},
|
||||
q: {
|
||||
title: "Create a new cycle",
|
||||
description: "Create a new cycle in the current project",
|
||||
action: () => toggleCreateCycleModal(true),
|
||||
},
|
||||
v: {
|
||||
title: "Create a new view",
|
||||
description: "Create a new view in the current project",
|
||||
action: () => toggleCreateViewModal(true),
|
||||
},
|
||||
backspace: {
|
||||
title: "Bulk delete issues",
|
||||
description: "Bulk delete issues in the current project",
|
||||
action: () => toggleBulkDeleteIssueModal(true),
|
||||
},
|
||||
delete: {
|
||||
title: "Bulk delete issues",
|
||||
description: "Bulk delete issues in the current project",
|
||||
action: () => toggleBulkDeleteIssueModal(true),
|
||||
},
|
||||
},
|
||||
global: getGlobalShortcutsList(),
|
||||
workspace: getWorkspaceShortcutsList(),
|
||||
project: getProjectShortcutsList(),
|
||||
}),
|
||||
[
|
||||
toggleBulkDeleteIssueModal,
|
||||
toggleCreateCycleModal,
|
||||
toggleCreateIssueModal,
|
||||
toggleCreateModuleModal,
|
||||
toggleCreatePageModal,
|
||||
toggleCreateProjectModal,
|
||||
toggleCreateViewModal,
|
||||
]
|
||||
[]
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
@@ -296,6 +201,8 @@ export const CommandPalette: FC = observer(() => {
|
||||
shortcutsList.project[keyPressed].action();
|
||||
}
|
||||
}
|
||||
// Additional keydown events
|
||||
handleAdditionalKeyDownEvents(e);
|
||||
},
|
||||
[
|
||||
copyIssueUrlToClipboard,
|
||||
@@ -320,75 +227,16 @@ export const CommandPalette: FC = observer(() => {
|
||||
return () => document.removeEventListener("keydown", handleKeyDown);
|
||||
}, [handleKeyDown]);
|
||||
|
||||
const isDraftIssue = pathname?.includes("draft-issues") || false;
|
||||
|
||||
if (!currentUser) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<ShortcutsModal isOpen={isShortcutModalOpen} onClose={() => toggleShortcutModal(false)} />
|
||||
{workspaceSlug && (
|
||||
<CreateProjectModal
|
||||
isOpen={isCreateProjectModalOpen}
|
||||
onClose={() => toggleCreateProjectModal(false)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
)}
|
||||
{workspaceSlug && <WorkspaceLevelModals workspaceSlug={workspaceSlug.toString()} />}
|
||||
{workspaceSlug && projectId && (
|
||||
<>
|
||||
<CycleCreateUpdateModal
|
||||
isOpen={isCreateCycleModalOpen}
|
||||
handleClose={() => toggleCreateCycleModal(false)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
/>
|
||||
<CreateUpdateModuleModal
|
||||
isOpen={isCreateModuleModalOpen}
|
||||
onClose={() => toggleCreateModuleModal(false)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
/>
|
||||
<CreateUpdateProjectViewModal
|
||||
isOpen={isCreateViewModalOpen}
|
||||
onClose={() => toggleCreateViewModal(false)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
/>
|
||||
<CreatePageModal
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
isModalOpen={createPageModal.isOpen}
|
||||
pageAccess={createPageModal.pageAccess}
|
||||
handleModalClose={() => toggleCreatePageModal({ isOpen: false })}
|
||||
redirectionEnabled
|
||||
/>
|
||||
</>
|
||||
<ProjectLevelModals workspaceSlug={workspaceSlug.toString()} projectId={projectId.toString()} />
|
||||
)}
|
||||
|
||||
<CreateUpdateIssueModal
|
||||
isOpen={isCreateIssueModalOpen}
|
||||
onClose={() => toggleCreateIssueModal(false)}
|
||||
data={cycleId ? { cycle_id: cycleId.toString() } : moduleId ? { module_ids: [moduleId.toString()] } : undefined}
|
||||
isDraft={isDraftIssue}
|
||||
/>
|
||||
|
||||
{workspaceSlug && projectId && issueId && issueDetails && (
|
||||
<DeleteIssueModal
|
||||
handleClose={() => toggleDeleteIssueModal(false)}
|
||||
isOpen={isDeleteIssueModalOpen}
|
||||
data={issueDetails}
|
||||
onSubmit={async () => {
|
||||
await removeIssue(workspaceSlug.toString(), projectId.toString(), issueId.toString());
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<BulkDeleteIssuesModal
|
||||
isOpen={isBulkDeleteIssueModalOpen}
|
||||
onClose={() => toggleBulkDeleteIssueModal(false)}
|
||||
user={currentUser}
|
||||
/>
|
||||
<IssueLevelModals />
|
||||
<CommandModal />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,12 @@ import { Command } from "lucide-react";
|
||||
import { substringMatch } from "@/helpers/string.helper";
|
||||
// hooks
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
// plane web helpers
|
||||
import {
|
||||
getAdditionalShortcutsList,
|
||||
getCommonShortcutsList,
|
||||
getNavigationShortcutsList,
|
||||
} from "@/plane-web/helpers/command-palette";
|
||||
|
||||
type Props = {
|
||||
searchQuery: string;
|
||||
@@ -16,26 +22,14 @@ export const ShortcutCommandsList: React.FC<Props> = (props) => {
|
||||
{
|
||||
key: "navigation",
|
||||
title: "Navigation",
|
||||
shortcuts: [{ keys: "Ctrl,K", description: "Open command menu" }],
|
||||
shortcuts: getNavigationShortcutsList(),
|
||||
},
|
||||
{
|
||||
key: "common",
|
||||
title: "Common",
|
||||
shortcuts: [
|
||||
{ keys: "P", description: "Create project" },
|
||||
{ keys: "C", description: "Create issue" },
|
||||
{ keys: "Q", description: "Create cycle" },
|
||||
{ keys: "M", description: "Create module" },
|
||||
{ keys: "V", description: "Create view" },
|
||||
{ keys: "D", description: "Create page" },
|
||||
{ keys: "Delete", description: "Bulk delete issues" },
|
||||
{ keys: "Shift,/", description: "Open shortcuts guide" },
|
||||
{
|
||||
keys: platform === "MacOS" ? "Ctrl,control,C" : "Ctrl,Alt,C",
|
||||
description: "Copy issue URL from the issue details page",
|
||||
},
|
||||
],
|
||||
shortcuts: getCommonShortcutsList(platform),
|
||||
},
|
||||
...getAdditionalShortcutsList(),
|
||||
];
|
||||
|
||||
const filteredShortcuts = KEYBOARD_SHORTCUTS.map((category) => {
|
||||
@@ -69,7 +63,11 @@ export const ShortcutCommandsList: React.FC<Props> = (props) => {
|
||||
<div key={key} className="flex items-center gap-1">
|
||||
{key === "Ctrl" ? (
|
||||
<div className="grid h-6 min-w-[1.5rem] place-items-center rounded-sm border-[0.5px] border-custom-border-200 bg-custom-background-90 px-1.5 text-[10px] text-custom-text-200">
|
||||
{ platform === "MacOS" ? <Command className="h-2.5 w-2.5 text-custom-text-200" /> : 'Ctrl'}
|
||||
{platform === "MacOS" ? (
|
||||
<Command className="h-2.5 w-2.5 text-custom-text-200" />
|
||||
) : (
|
||||
"Ctrl"
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<kbd className="grid h-6 min-w-[1.5rem] place-items-center rounded-sm border-[0.5px] border-custom-border-200 bg-custom-background-90 px-1.5 text-[10px] text-custom-text-200">
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useContext } from "react";
|
||||
// mobx store
|
||||
import { StoreContext } from "@/lib/store-context";
|
||||
// types
|
||||
import { ICommandPaletteStore } from "@/store/command-palette.store";
|
||||
import { ICommandPaletteStore } from "@/plane-web/store/command-palette.store";
|
||||
|
||||
export const useCommandPalette = (): ICommandPaletteStore => {
|
||||
const context = useContext(StoreContext);
|
||||
|
||||
@@ -9,9 +9,8 @@ export interface ModalData {
|
||||
viewId: string;
|
||||
}
|
||||
|
||||
export interface ICommandPaletteStore {
|
||||
export interface IBaseCommandPaletteStore {
|
||||
// observables
|
||||
|
||||
isCommandPaletteOpen: boolean;
|
||||
isShortcutModalOpen: boolean;
|
||||
isCreateProjectModalOpen: boolean;
|
||||
@@ -22,6 +21,7 @@ export interface ICommandPaletteStore {
|
||||
isCreateIssueModalOpen: boolean;
|
||||
isDeleteIssueModalOpen: boolean;
|
||||
isBulkDeleteIssueModalOpen: boolean;
|
||||
createIssueStoreType: TCreateModalStoreTypes;
|
||||
// computed
|
||||
isAnyModalOpen: boolean;
|
||||
// toggle actions
|
||||
@@ -35,11 +35,9 @@ export interface ICommandPaletteStore {
|
||||
toggleCreateModuleModal: (value?: boolean) => void;
|
||||
toggleDeleteIssueModal: (value?: boolean) => void;
|
||||
toggleBulkDeleteIssueModal: (value?: boolean) => void;
|
||||
|
||||
createIssueStoreType: TCreateModalStoreTypes;
|
||||
}
|
||||
|
||||
export class CommandPaletteStore implements ICommandPaletteStore {
|
||||
export abstract class BaseCommandPaletteStore implements IBaseCommandPaletteStore {
|
||||
// observables
|
||||
isCommandPaletteOpen: boolean = false;
|
||||
isShortcutModalOpen: boolean = false;
|
||||
@@ -51,7 +49,6 @@ export class CommandPaletteStore implements ICommandPaletteStore {
|
||||
isDeleteIssueModalOpen: boolean = false;
|
||||
isBulkDeleteIssueModalOpen: boolean = false;
|
||||
createPageModal: TCreatePageModal = DEFAULT_CREATE_PAGE_MODAL_DATA;
|
||||
|
||||
createIssueStoreType: TCreateModalStoreTypes = EIssuesStoreType.PROJECT;
|
||||
|
||||
constructor() {
|
||||
@@ -67,6 +64,7 @@ export class CommandPaletteStore implements ICommandPaletteStore {
|
||||
isDeleteIssueModalOpen: observable.ref,
|
||||
isBulkDeleteIssueModalOpen: observable.ref,
|
||||
createPageModal: observable,
|
||||
createIssueStoreType: observable,
|
||||
// computed
|
||||
isAnyModalOpen: computed,
|
||||
// projectPages: computed,
|
||||
@@ -85,20 +83,20 @@ export class CommandPaletteStore implements ICommandPaletteStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether any modal is open or not.
|
||||
* Checks whether any modal is open or not in the base command palette.
|
||||
* @returns boolean
|
||||
*/
|
||||
get isAnyModalOpen() {
|
||||
return Boolean(
|
||||
this.isCreateIssueModalOpen ||
|
||||
this.isCreateCycleModalOpen ||
|
||||
this.isCreateProjectModalOpen ||
|
||||
this.isCreateModuleModalOpen ||
|
||||
this.isCreateViewModalOpen ||
|
||||
this.isShortcutModalOpen ||
|
||||
this.isBulkDeleteIssueModalOpen ||
|
||||
this.isDeleteIssueModalOpen ||
|
||||
this.createPageModal.isOpen
|
||||
this.isCreateCycleModalOpen ||
|
||||
this.isCreateProjectModalOpen ||
|
||||
this.isCreateModuleModalOpen ||
|
||||
this.isCreateViewModalOpen ||
|
||||
this.isShortcutModalOpen ||
|
||||
this.isBulkDeleteIssueModalOpen ||
|
||||
this.isDeleteIssueModalOpen ||
|
||||
this.createPageModal.isOpen
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { enableStaticRendering } from "mobx-react";
|
||||
// plane web store
|
||||
import { CommandPaletteStore, ICommandPaletteStore } from "@/plane-web/store/command-palette.store";
|
||||
import { RootStore } from "@/plane-web/store/root.store";
|
||||
import { IStateStore, StateStore } from "@/plane-web/store/state.store";
|
||||
// stores
|
||||
import { CommandPaletteStore, ICommandPaletteStore } from "./command-palette.store";
|
||||
import { CycleStore, ICycleStore } from "./cycle.store";
|
||||
import { CycleFilterStore, ICycleFilterStore } from "./cycle_filter.store";
|
||||
import { DashboardStore, IDashboardStore } from "./dashboard.store";
|
||||
|
||||
1
web/ee/components/command-palette/modals/index.ts
Normal file
1
web/ee/components/command-palette/modals/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "ce/components/command-palette/modals";
|
||||
1
web/ee/store/command-palette.store.ts
Normal file
1
web/ee/store/command-palette.store.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "ce/store/command-palette.store";
|
||||
1
web/helpers/command-palette.ts
Normal file
1
web/helpers/command-palette.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "ce/helpers/command-palette";
|
||||
Reference in New Issue
Block a user