Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/types/src/command-palette.d.ts
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions packages/types/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 3 additions & 0 deletions web/ce/components/command-palette/modals/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./workspace-level";
export * from "./project-level";
export * from "./issue-level";
73 changes: 73 additions & 0 deletions web/ce/components/command-palette/modals/issue-level.tsx
Original file line number Diff line number Diff line change
@@ -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 changes: 59 additions & 0 deletions web/ce/components/command-palette/modals/project-level.tsx
Original file line number Diff line number Diff line change
@@ -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 changes: 25 additions & 0 deletions web/ce/components/command-palette/modals/workspace-level.tsx
Original file line number Diff line number Diff line change
@@ -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 changes: 95 additions & 0 deletions web/ce/helpers/command-palette.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions web/ce/store/command-palette.store.ts
Original file line number Diff line number Diff line change
@@ -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, {});
}
}
Loading