refactor: replace keyboard events with command palette store (#2688)

This commit is contained in:
Aaryan Khandelwal 2023-11-08 13:51:55 +05:30 committed by GitHub
parent 53e7da08e4
commit 5a84ed279d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 219 additions and 344 deletions

View File

@ -3,6 +3,7 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
import { Command } from "cmdk"; import { Command } from "cmdk";
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
import { observer } from "mobx-react-lite";
import { import {
FileText, FileText,
FolderPlus, FolderPlus,
@ -16,12 +17,13 @@ import {
UserMinus2, UserMinus2,
UserPlus2, UserPlus2,
} from "lucide-react"; } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// services // services
import { WorkspaceService } from "services/workspace.service"; import { WorkspaceService } from "services/workspace.service";
import { IssueService } from "services/issue"; import { IssueService } from "services/issue";
// hooks // hooks
import useDebounce from "hooks/use-debounce"; import useDebounce from "hooks/use-debounce";
import useUser from "hooks/use-user";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// components // components
import { import {
@ -61,11 +63,8 @@ type Props = {
const workspaceService = new WorkspaceService(); const workspaceService = new WorkspaceService();
const issueService = new IssueService(); const issueService = new IssueService();
export const CommandModal: React.FC<Props> = (props) => { export const CommandModal: React.FC<Props> = observer((props) => {
const { deleteIssue, isPaletteOpen, closePalette } = props; const { deleteIssue, isPaletteOpen, closePalette } = props;
// router
const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query;
// states // states
const [placeholder, setPlaceholder] = useState("Type a command or search..."); const [placeholder, setPlaceholder] = useState("Type a command or search...");
const [resultsCount, setResultsCount] = useState(0); const [resultsCount, setResultsCount] = useState(0);
@ -86,14 +85,19 @@ export const CommandModal: React.FC<Props> = (props) => {
const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false); const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false);
const [pages, setPages] = useState<string[]>([]); const [pages, setPages] = useState<string[]>([]);
const { user: userStore, commandPalette: commandPaletteStore } = useMobxStore();
const user = userStore.currentUser ?? undefined;
// router
const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query;
const page = pages[pages.length - 1]; const page = pages[pages.length - 1];
const debouncedSearchTerm = useDebounce(searchTerm, 500); const debouncedSearchTerm = useDebounce(searchTerm, 500);
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { user } = useUser();
const { data: issueDetails } = useSWR( const { data: issueDetails } = useSWR(
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null, workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
workspaceSlug && projectId && issueId workspaceSlug && projectId && issueId
@ -468,10 +472,7 @@ export const CommandModal: React.FC<Props> = (props) => {
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
const e = new KeyboardEvent("keydown", { commandPaletteStore.toggleCreateIssueModal(true);
key: "c",
});
document.dispatchEvent(e);
}} }}
className="focus:bg-custom-background-80" className="focus:bg-custom-background-80"
> >
@ -488,10 +489,7 @@ export const CommandModal: React.FC<Props> = (props) => {
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
const e = new KeyboardEvent("keydown", { commandPaletteStore.toggleCreateProjectModal(true);
key: "p",
});
document.dispatchEvent(e);
}} }}
className="focus:outline-none" className="focus:outline-none"
> >
@ -510,10 +508,7 @@ export const CommandModal: React.FC<Props> = (props) => {
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
const e = new KeyboardEvent("keydown", { commandPaletteStore.toggleCreateCycleModal(true);
key: "q",
});
document.dispatchEvent(e);
}} }}
className="focus:outline-none" className="focus:outline-none"
> >
@ -528,10 +523,7 @@ export const CommandModal: React.FC<Props> = (props) => {
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
const e = new KeyboardEvent("keydown", { commandPaletteStore.toggleCreateModuleModal(true);
key: "m",
});
document.dispatchEvent(e);
}} }}
className="focus:outline-none" className="focus:outline-none"
> >
@ -546,10 +538,7 @@ export const CommandModal: React.FC<Props> = (props) => {
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
const e = new KeyboardEvent("keydown", { commandPaletteStore.toggleCreateViewModal(true);
key: "v",
});
document.dispatchEvent(e);
}} }}
className="focus:outline-none" className="focus:outline-none"
> >
@ -564,10 +553,7 @@ export const CommandModal: React.FC<Props> = (props) => {
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
const e = new KeyboardEvent("keydown", { commandPaletteStore.toggleCreatePageModal(true);
key: "d",
});
document.dispatchEvent(e);
}} }}
className="focus:outline-none" className="focus:outline-none"
> >
@ -621,10 +607,7 @@ export const CommandModal: React.FC<Props> = (props) => {
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
const e = new KeyboardEvent("keydown", { commandPaletteStore.toggleShortcutModal(true);
key: "h",
});
document.dispatchEvent(e);
}} }}
className="focus:outline-none" className="focus:outline-none"
> >
@ -762,4 +745,4 @@ export const CommandModal: React.FC<Props> = (props) => {
</Dialog> </Dialog>
</Transition.Root> </Transition.Root>
); );
}; });

View File

@ -1,10 +1,12 @@
import { MouseEvent } from "react"; import { MouseEvent } from "react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import useSWR from "swr"; import useSWR from "swr";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import { useMobxStore } from "lib/mobx/store-provider";
// ui // ui
import { SingleProgressStats } from "components/core"; import { SingleProgressStats } from "components/core";
import { import {
@ -25,7 +27,6 @@ import { ActiveCycleProgressStats } from "components/cycles";
import { ViewIssueLabel } from "components/issues"; import { ViewIssueLabel } from "components/issues";
// icons // icons
import { AlarmClock, AlertTriangle, ArrowRight, CalendarDays, Star, Target } from "lucide-react"; import { AlarmClock, AlertTriangle, ArrowRight, CalendarDays, Star, Target } from "lucide-react";
// helpers // helpers
import { getDateRangeStatus, renderShortDateWithYearFormat, findHowManyDaysLeft } from "helpers/date-time.helper"; import { getDateRangeStatus, renderShortDateWithYearFormat, findHowManyDaysLeft } from "helpers/date-time.helper";
import { truncateText } from "helpers/string.helper"; import { truncateText } from "helpers/string.helper";
@ -65,12 +66,12 @@ interface IActiveCycleDetails {
projectId: string; projectId: string;
} }
export const ActiveCycleDetails: React.FC<IActiveCycleDetails> = (props) => { export const ActiveCycleDetails: React.FC<IActiveCycleDetails> = observer((props) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = props; const { workspaceSlug, projectId } = props;
const { cycle: cycleStore } = useMobxStore(); const { cycle: cycleStore, commandPalette: commandPaletteStore } = useMobxStore();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -117,12 +118,7 @@ export const ActiveCycleDetails: React.FC<IActiveCycleDetails> = (props) => {
<button <button
type="button" type="button"
className="text-custom-primary-100 text-sm outline-none" className="text-custom-primary-100 text-sm outline-none"
onClick={() => { onClick={() => commandPaletteStore.toggleCreateCycleModal(true)}
const e = new KeyboardEvent("keydown", {
key: "q",
});
document.dispatchEvent(e);
}}
> >
Create a new cycle Create a new cycle
</button> </button>
@ -485,4 +481,4 @@ export const ActiveCycleDetails: React.FC<IActiveCycleDetails> = (props) => {
</div> </div>
</div> </div>
); );
}; });

View File

@ -1,8 +1,11 @@
import { FC } from "react"; import { FC } from "react";
// types import { observer } from "mobx-react-lite";
import { ICycle } from "types"; // mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components // components
import { CyclePeekOverview, CyclesBoardCard } from "components/cycles"; import { CyclePeekOverview, CyclesBoardCard } from "components/cycles";
// types
import { ICycle } from "types";
export interface ICyclesBoard { export interface ICyclesBoard {
cycles: ICycle[]; cycles: ICycle[];
@ -12,9 +15,11 @@ export interface ICyclesBoard {
peekCycle: string; peekCycle: string;
} }
export const CyclesBoard: FC<ICyclesBoard> = (props) => { export const CyclesBoard: FC<ICyclesBoard> = observer((props) => {
const { cycles, filter, workspaceSlug, projectId, peekCycle } = props; const { cycles, filter, workspaceSlug, projectId, peekCycle } = props;
const { commandPalette: commandPaletteStore } = useMobxStore();
return ( return (
<> <>
{cycles.length > 0 ? ( {cycles.length > 0 ? (
@ -53,12 +58,7 @@ export const CyclesBoard: FC<ICyclesBoard> = (props) => {
<button <button
type="button" type="button"
className="text-custom-primary-100 text-sm outline-none" className="text-custom-primary-100 text-sm outline-none"
onClick={() => { onClick={() => commandPaletteStore.toggleCreateCycleModal(true)}
const e = new KeyboardEvent("keydown", {
key: "q",
});
document.dispatchEvent(e);
}}
> >
Create a new cycle Create a new cycle
</button> </button>
@ -67,4 +67,4 @@ export const CyclesBoard: FC<ICyclesBoard> = (props) => {
)} )}
</> </>
); );
}; });

View File

@ -1,7 +1,9 @@
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components // components
import { CyclePeekOverview, CyclesListItem } from "components/cycles"; import { CyclePeekOverview, CyclesListItem } from "components/cycles";
// ui // ui
import { Loader } from "@plane/ui"; import { Loader } from "@plane/ui";
// types // types
@ -14,9 +16,11 @@ export interface ICyclesList {
projectId: string; projectId: string;
} }
export const CyclesList: FC<ICyclesList> = (props) => { export const CyclesList: FC<ICyclesList> = observer((props) => {
const { cycles, filter, workspaceSlug, projectId } = props; const { cycles, filter, workspaceSlug, projectId } = props;
const { commandPalette: commandPaletteStore } = useMobxStore();
return ( return (
<> <>
{cycles ? ( {cycles ? (
@ -53,12 +57,7 @@ export const CyclesList: FC<ICyclesList> = (props) => {
<button <button
type="button" type="button"
className="text-custom-primary-100 text-sm outline-none" className="text-custom-primary-100 text-sm outline-none"
onClick={() => { onClick={() => commandPaletteStore.toggleCreateCycleModal(true)}
const e = new KeyboardEvent("keydown", {
key: "q",
});
document.dispatchEvent(e);
}}
> >
Create a new cycle Create a new cycle
</button> </button>
@ -75,4 +74,4 @@ export const CyclesList: FC<ICyclesList> = (props) => {
)} )}
</> </>
); );
}; });

View File

@ -317,11 +317,11 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
<LinkIcon className="h-3 w-3 text-custom-text-300" /> <LinkIcon className="h-3 w-3 text-custom-text-300" />
</button> </button>
{!isCompleted && ( {!isCompleted && (
<CustomMenu width="lg" ellipsis> <CustomMenu width="lg" placement="bottom-end" ellipsis>
<CustomMenu.MenuItem onClick={() => setCycleDeleteModal(true)}> <CustomMenu.MenuItem onClick={() => setCycleDeleteModal(true)}>
<span className="flex items-center justify-start gap-2"> <span className="flex items-center justify-start gap-2">
<Trash2 className="h-4 w-4" /> <Trash2 className="h-3 w-3" />
<span>Delete</span> <span>Delete cycle</span>
</span> </span>
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
</CustomMenu> </CustomMenu>

View File

@ -31,6 +31,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
cycle: cycleStore, cycle: cycleStore,
cycleIssueFilter: cycleIssueFilterStore, cycleIssueFilter: cycleIssueFilterStore,
project: projectStore, project: projectStore,
commandPalette: commandPaletteStore,
} = useMobxStore(); } = useMobxStore();
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
@ -139,7 +140,6 @@ export const CycleIssuesHeader: React.FC = observer(() => {
type="component" type="component"
component={ component={
<CustomMenu <CustomMenu
placement="bottom-start"
label={ label={
<> <>
<ContrastIcon className="h-3 w-3" /> <ContrastIcon className="h-3 w-3" />
@ -148,6 +148,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
} }
className="ml-1.5 flex-shrink-0" className="ml-1.5 flex-shrink-0"
width="auto" width="auto"
placement="bottom-start"
> >
{cyclesList?.map((cycle) => ( {cyclesList?.map((cycle) => (
<CustomMenu.MenuItem <CustomMenu.MenuItem
@ -194,16 +195,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm"> <Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
Analytics Analytics
</Button> </Button>
<Button <Button onClick={() => commandPaletteStore.toggleCreateIssueModal(true)} size="sm" prependIcon={<Plus />}>
onClick={() => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
}}
size="sm"
prependIcon={<Plus />}
>
Add Issue Add Issue
</Button> </Button>
<button <button

View File

@ -1,22 +1,20 @@
import { FC } from "react"; import { FC } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { Plus } from "lucide-react"; import { Plus } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// ui // ui
import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui"; import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui";
// helpers // helpers
import { renderEmoji } from "helpers/emoji.helper"; import { renderEmoji } from "helpers/emoji.helper";
// hooks
import { useMobxStore } from "lib/mobx/store-provider";
export interface ICyclesHeader {} export const CyclesHeader: FC = observer(() => {
export const CyclesHeader: FC<ICyclesHeader> = (props) => {
const {} = props;
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
// store // store
const { project: projectStore } = useMobxStore(); const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
return ( return (
@ -54,14 +52,11 @@ export const CyclesHeader: FC<ICyclesHeader> = (props) => {
<Button <Button
variant="primary" variant="primary"
prependIcon={<Plus />} prependIcon={<Plus />}
onClick={() => { onClick={() => commandPaletteStore.toggleCreateCycleModal(true)}
const e = new KeyboardEvent("keydown", { key: "q" });
document.dispatchEvent(e);
}}
> >
Add Cycle Add Cycle
</Button> </Button>
</div> </div>
</div> </div>
); );
}; });

View File

@ -31,6 +31,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
module: moduleStore, module: moduleStore,
moduleFilter: moduleFilterStore, moduleFilter: moduleFilterStore,
project: projectStore, project: projectStore,
commandPalette: commandPaletteStore,
} = useMobxStore(); } = useMobxStore();
const activeLayout = issueFilterStore.userDisplayFilters.layout; const activeLayout = issueFilterStore.userDisplayFilters.layout;
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
@ -146,6 +147,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
} }
className="ml-1.5 flex-shrink-0" className="ml-1.5 flex-shrink-0"
width="auto" width="auto"
placement="bottom-start"
> >
{modulesList?.map((module) => ( {modulesList?.map((module) => (
<CustomMenu.MenuItem <CustomMenu.MenuItem
@ -192,16 +194,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm"> <Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
Analytics Analytics
</Button> </Button>
<Button <Button onClick={() => commandPaletteStore.toggleCreateIssueModal(true)} size="sm" prependIcon={<Plus />}>
onClick={() => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
}}
size="sm"
prependIcon={<Plus />}
>
Add Issue Add Issue
</Button> </Button>
<button <button

View File

@ -17,7 +17,7 @@ export const ModulesListHeader: React.FC = observer(() => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
// store // store
const { project: projectStore } = useMobxStore(); const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
const { storedValue: modulesView, setValue: setModulesView } = useLocalStorage("modules_view", "grid"); const { storedValue: modulesView, setValue: setModulesView } = useLocalStorage("modules_view", "grid");
@ -77,10 +77,7 @@ export const ModulesListHeader: React.FC = observer(() => {
<Button <Button
variant="primary" variant="primary"
prependIcon={<Plus />} prependIcon={<Plus />}
onClick={() => { onClick={() => commandPaletteStore.toggleCreateModuleModal(true)}
const e = new KeyboardEvent("keydown", { key: "m" });
document.dispatchEvent(e);
}}
> >
Add Module Add Module
</Button> </Button>

View File

@ -24,10 +24,11 @@ const pageService = new PageService();
export const PageDetailsHeader: FC<IPagesHeaderProps> = observer((props) => { export const PageDetailsHeader: FC<IPagesHeaderProps> = observer((props) => {
const { showButton = false } = props; const { showButton = false } = props;
const router = useRouter(); const router = useRouter();
const { workspaceSlug, pageId } = router.query; const { workspaceSlug, pageId } = router.query;
const { project: projectStore } = useMobxStore(); const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
const { data: pageDetails } = useSWR( const { data: pageDetails } = useSWR(
@ -78,10 +79,7 @@ export const PageDetailsHeader: FC<IPagesHeaderProps> = observer((props) => {
variant="primary" variant="primary"
prependIcon={<Plus />} prependIcon={<Plus />}
size="sm" size="sm"
onClick={() => { onClick={() => commandPaletteStore.toggleCreatePageModal(true)}
const e = new KeyboardEvent("keydown", { key: "d" });
document.dispatchEvent(e);
}}
> >
Create Page Create Page
</Button> </Button>

View File

@ -18,7 +18,7 @@ export const PagesHeader: FC<IPagesHeaderProps> = observer((props) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { project: projectStore } = useMobxStore(); const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
return ( return (
@ -56,10 +56,7 @@ export const PagesHeader: FC<IPagesHeaderProps> = observer((props) => {
variant="primary" variant="primary"
prependIcon={<Plus />} prependIcon={<Plus />}
size="sm" size="sm"
onClick={() => { onClick={() => commandPaletteStore.toggleCreatePageModal(true)}
const e = new KeyboardEvent("keydown", { key: "d" });
document.dispatchEvent(e);
}}
> >
Create Page Create Page
</Button> </Button>

View File

@ -23,7 +23,12 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { issueFilter: issueFilterStore, project: projectStore, inbox: inboxStore } = useMobxStore(); const {
issueFilter: issueFilterStore,
project: projectStore,
inbox: inboxStore,
commandPalette: commandPaletteStore,
} = useMobxStore();
const activeLayout = issueFilterStore.userDisplayFilters.layout; const activeLayout = issueFilterStore.userDisplayFilters.layout;
@ -198,16 +203,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm"> <Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
Analytics Analytics
</Button> </Button>
<Button <Button onClick={() => commandPaletteStore.toggleCreateIssueModal(true)} size="sm" prependIcon={<Plus />}>
onClick={() => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
}}
size="sm"
prependIcon={<Plus />}
>
Add Issue Add Issue
</Button> </Button>
</div> </div>

View File

@ -11,7 +11,7 @@ export const ProjectsHeader = observer(() => {
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
// store // store
const { project: projectStore } = useMobxStore(); const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const projectsList = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : []; const projectsList = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : [];
@ -43,14 +43,7 @@ export const ProjectsHeader = observer(() => {
</div> </div>
)} )}
<Button <Button prependIcon={<Plus />} size="md" onClick={() => commandPaletteStore.toggleCreateProjectModal(true)}>
prependIcon={<Plus />}
size="md"
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "p" });
document.dispatchEvent(e);
}}
>
Add Project Add Project
</Button> </Button>
</div> </div>

View File

@ -16,15 +16,14 @@ export const JiraGetImportDetail: React.FC = observer(() => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined;
const { const {
control, control,
formState: { errors }, formState: { errors },
} = useFormContext<IJiraImporterForm>(); } = useFormContext<IJiraImporterForm>();
const { project: projectStore } = useMobxStore();
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined;
return ( return (
<div className="h-full w-full space-y-8 overflow-y-auto"> <div className="h-full w-full space-y-8 overflow-y-auto">
<div className="grid grid-cols-1 gap-10 md:grid-cols-2"> <div className="grid grid-cols-1 gap-10 md:grid-cols-2">
@ -190,10 +189,7 @@ export const JiraGetImportDetail: React.FC = observer(() => {
<div> <div>
<button <button
type="button" type="button"
onClick={() => { onClick={() => commandPaletteStore.toggleCreateProjectModal(true)}
const event = new KeyboardEvent("keydown", { key: "p" });
document.dispatchEvent(event);
}}
className="flex cursor-pointer select-none items-center space-x-2 truncate rounded px-1 py-1.5 text-custom-text-200" className="flex cursor-pointer select-none items-center space-x-2 truncate rounded px-1 py-1.5 text-custom-text-200"
> >
<Plus className="h-4 w-4 text-custom-text-200" /> <Plus className="h-4 w-4 text-custom-text-200" />

View File

@ -26,7 +26,7 @@ export const CycleEmptyState: React.FC<Props> = observer((props) => {
// states // states
const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false); const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false);
const { cycleIssue: cycleIssueStore } = useMobxStore(); const { cycleIssue: cycleIssueStore, commandPalette: commandPaletteStore } = useMobxStore();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -62,12 +62,7 @@ export const CycleEmptyState: React.FC<Props> = observer((props) => {
primaryButton={{ primaryButton={{
text: "New issue", text: "New issue",
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />, icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
onClick: () => { onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
},
}} }}
secondaryButton={ secondaryButton={
<Button <Button

View File

@ -1,25 +1,27 @@
import { observer } from "mobx-react-lite";
import { PlusIcon } from "lucide-react"; import { PlusIcon } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components // components
import { EmptyState } from "components/common"; import { EmptyState } from "components/common";
// assets // assets
import emptyIssue from "public/empty-state/issue.svg"; import emptyIssue from "public/empty-state/issue.svg";
export const GlobalViewEmptyState: React.FC = () => ( export const GlobalViewEmptyState: React.FC = observer(() => {
<div className="h-full w-full grid place-items-center"> const { commandPalette: commandPaletteStore } = useMobxStore();
<EmptyState
title="View issues will appear here" return (
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done." <div className="h-full w-full grid place-items-center">
image={emptyIssue} <EmptyState
primaryButton={{ title="View issues will appear here"
text: "New issue", description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />, image={emptyIssue}
onClick: () => { primaryButton={{
const e = new KeyboardEvent("keydown", { text: "New issue",
key: "c", icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
}); onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
document.dispatchEvent(e); }}
}, />
}} </div>
/> );
</div> });
);

View File

@ -22,7 +22,7 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
// states // states
const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false); const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false);
const { moduleIssue: moduleIssueStore } = useMobxStore(); const { moduleIssue: moduleIssueStore, commandPalette: commandPaletteStore } = useMobxStore();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -58,12 +58,7 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
primaryButton={{ primaryButton={{
text: "New issue", text: "New issue",
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />, icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
onClick: () => { onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
},
}} }}
secondaryButton={ secondaryButton={
<Button <Button

View File

@ -1,25 +1,27 @@
import { observer } from "mobx-react-lite";
import { PlusIcon } from "lucide-react"; import { PlusIcon } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components // components
import { EmptyState } from "components/common"; import { EmptyState } from "components/common";
// assets // assets
import emptyIssue from "public/empty-state/issue.svg"; import emptyIssue from "public/empty-state/issue.svg";
export const ProjectViewEmptyState: React.FC = () => ( export const ProjectViewEmptyState: React.FC = observer(() => {
<div className="h-full w-full grid place-items-center"> const { commandPalette: commandPaletteStore } = useMobxStore();
<EmptyState
title="View issues will appear here" return (
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done." <div className="h-full w-full grid place-items-center">
image={emptyIssue} <EmptyState
primaryButton={{ title="View issues will appear here"
text: "New issue", description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />, image={emptyIssue}
onClick: () => { primaryButton={{
const e = new KeyboardEvent("keydown", { text: "New issue",
key: "c", icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
}); onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
document.dispatchEvent(e); }}
}, />
}} </div>
/> );
</div> });
);

View File

@ -1,25 +1,27 @@
import { observer } from "mobx-react-lite";
import { PlusIcon } from "lucide-react"; import { PlusIcon } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components // components
import { EmptyState } from "components/common"; import { EmptyState } from "components/common";
// assets // assets
import emptyIssue from "public/empty-state/issue.svg"; import emptyIssue from "public/empty-state/issue.svg";
export const ProjectEmptyState: React.FC = () => ( export const ProjectEmptyState: React.FC = observer(() => {
<div className="h-full w-full grid place-items-center"> const { commandPalette: commandPaletteStore } = useMobxStore();
<EmptyState
title="Project issues will appear here" return (
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done." <div className="h-full w-full grid place-items-center">
image={emptyIssue} <EmptyState
primaryButton={{ title="Project issues will appear here"
text: "New issue", description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />, image={emptyIssue}
onClick: () => { primaryButton={{
const e = new KeyboardEvent("keydown", { text: "New issue",
key: "c", icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
}); onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
document.dispatchEvent(e); }}
}, />
}} </div>
/> );
</div> });
);

View File

@ -17,7 +17,7 @@ export const ModulesListView: React.FC = observer(() => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, peekModule } = router.query; const { workspaceSlug, projectId, peekModule } = router.query;
const { module: moduleStore } = useMobxStore(); const { module: moduleStore, commandPalette: commandPaletteStore } = useMobxStore();
const { storedValue: modulesView } = useLocalStorage("modules_view", "grid"); const { storedValue: modulesView } = useLocalStorage("modules_view", "grid");
@ -85,12 +85,7 @@ export const ModulesListView: React.FC = observer(() => {
primaryButton={{ primaryButton={{
icon: <Plus className="h-4 w-4" />, icon: <Plus className="h-4 w-4" />,
text: "New Module", text: "New Module",
onClick: () => { onClick: () => commandPaletteStore.toggleCreateModuleModal(true),
const e = new KeyboardEvent("keydown", {
key: "m",
});
document.dispatchEvent(e);
},
}} }}
/> />
)} )}

View File

@ -246,11 +246,11 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
<button onClick={handleCopyText}> <button onClick={handleCopyText}>
<LinkIcon className="h-3 w-3 text-custom-text-300" /> <LinkIcon className="h-3 w-3 text-custom-text-300" />
</button> </button>
<CustomMenu width="lg" ellipsis> <CustomMenu width="lg" placement="bottom-end" ellipsis>
<CustomMenu.MenuItem onClick={() => setModuleDeleteModal(true)}> <CustomMenu.MenuItem onClick={() => setModuleDeleteModal(true)}>
<span className="flex items-center justify-start gap-2"> <span className="flex items-center justify-start gap-2">
<Trash2 className="h-4 w-4" /> <Trash2 className="h-3 w-3" />
<span>Delete</span> <span>Delete module</span>
</span> </span>
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
</CustomMenu> </CustomMenu>

View File

@ -18,7 +18,8 @@ export const WorkspaceDashboardView = observer(() => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
// store // store
const { user: userStore, project: projectStore } = useMobxStore(); const { user: userStore, project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const user = userStore.currentUser; const user = userStore.currentUser;
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null; const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
const workspaceDashboardInfo = userStore.dashboardInfo; const workspaceDashboardInfo = userStore.dashboardInfo;
@ -67,16 +68,7 @@ export const WorkspaceDashboardView = observer(() => {
<div className="p-5 md:p-8 pr-0"> <div className="p-5 md:p-8 pr-0">
<h5 className="text-xl font-semibold">Create a project</h5> <h5 className="text-xl font-semibold">Create a project</h5>
<p className="mt-2 mb-5">Manage your projects by creating issues, cycles, modules, views and pages.</p> <p className="mt-2 mb-5">Manage your projects by creating issues, cycles, modules, views and pages.</p>
<Button <Button variant="primary" size="sm" onClick={() => commandPaletteStore.toggleCreateProjectModal(true)}>
variant="primary"
size="sm"
onClick={() => {
const e = new KeyboardEvent("keydown", {
key: "p",
});
document.dispatchEvent(e);
}}
>
Create Project Create Project
</Button> </Button>
</div> </div>

View File

@ -1,19 +1,18 @@
import React from "react"; import React from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import useSWR from "swr"; import useSWR from "swr";
import { Plus } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// services // services
import { PageService } from "services/page.service"; import { PageService } from "services/page.service";
// components // components
import { PagesView } from "components/pages"; import { PagesView } from "components/pages";
// ui
import { EmptyState } from "components/common"; import { EmptyState } from "components/common";
// ui
import { Loader } from "@plane/ui"; import { Loader } from "@plane/ui";
// icons // assets
import { Plus } from "lucide-react";
// images
import emptyPage from "public/empty-state/page.svg"; import emptyPage from "public/empty-state/page.svg";
// helpers // helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper"; import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
@ -26,7 +25,11 @@ import { RECENT_PAGES_LIST } from "constants/fetch-keys";
// services // services
const pageService = new PageService(); const pageService = new PageService();
export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => { export const RecentPagesList: React.FC<TPagesListProps> = observer((props) => {
const { viewType } = props;
const { commandPalette: commandPaletteStore } = useMobxStore();
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -46,9 +49,7 @@ export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
return ( return (
<div key={key} className="h-full overflow-hidden pb-9"> <div key={key} className="h-full overflow-hidden pb-9">
<h2 className="text-xl font-semibold capitalize mb-2"> <h2 className="text-xl font-semibold capitalize mb-2">{replaceUnderscoreIfSnakeCase(key)}</h2>
{replaceUnderscoreIfSnakeCase(key)}
</h2>
<PagesView pages={pages[key as keyof RecentPagesResponse]} viewType={viewType} /> <PagesView pages={pages[key as keyof RecentPagesResponse]} viewType={viewType} />
</div> </div>
); );
@ -61,12 +62,7 @@ export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
primaryButton={{ primaryButton={{
icon: <Plus className="h-4 w-4" />, icon: <Plus className="h-4 w-4" />,
text: "New Page", text: "New Page",
onClick: () => { onClick: () => commandPaletteStore.toggleCreatePageModal(true),
const e = new KeyboardEvent("keydown", {
key: "d",
});
document.dispatchEvent(e);
},
}} }}
/> />
) )
@ -79,4 +75,4 @@ export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
)} )}
</> </>
); );
}; });

View File

@ -1,21 +1,20 @@
import { useState } from "react"; import { useState } from "react";
import useSWR, { mutate } from "swr";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import useSWR, { mutate } from "swr";
import { Plus } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// services // services
import { PageService } from "services/page.service"; import { PageService } from "services/page.service";
import { ProjectService } from "services/project"; import { ProjectService } from "services/project";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// components // components
import { CreateUpdatePageModal, DeletePageModal, SinglePageDetailedItem, SinglePageListItem } from "components/pages"; import { CreateUpdatePageModal, DeletePageModal, SinglePageDetailedItem, SinglePageListItem } from "components/pages";
// ui
import { EmptyState } from "components/common"; import { EmptyState } from "components/common";
// ui
import { Loader } from "@plane/ui"; import { Loader } from "@plane/ui";
// icons
import { Plus } from "lucide-react";
// images // images
import emptyPage from "public/empty-state/page.svg"; import emptyPage from "public/empty-state/page.svg";
// types // types
@ -37,17 +36,19 @@ type Props = {
const pageService = new PageService(); const pageService = new PageService();
const projectService = new ProjectService(); const projectService = new ProjectService();
export const PagesView: React.FC<Props> = ({ pages, viewType }) => { export const PagesView: React.FC<Props> = observer(({ pages, viewType }) => {
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
// states // states
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false); const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
const [selectedPageToUpdate, setSelectedPageToUpdate] = useState<IPage | null>(null); const [selectedPageToUpdate, setSelectedPageToUpdate] = useState<IPage | null>(null);
const [deletePageModal, setDeletePageModal] = useState(false); const [deletePageModal, setDeletePageModal] = useState(false);
const [selectedPageToDelete, setSelectedPageToDelete] = useState<IPage | null>(null); const [selectedPageToDelete, setSelectedPageToDelete] = useState<IPage | null>(null);
const { user } = useUserAuth(); const { user: userStore, commandPalette: commandPaletteStore } = useMobxStore();
const user = userStore.currentUser ?? undefined;
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -163,7 +164,7 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
}; };
const partialUpdatePage = (page: IPage, formData: Partial<IPage>) => { const partialUpdatePage = (page: IPage, formData: Partial<IPage>) => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId || !user) return;
mutate<IPage[]>( mutate<IPage[]>(
ALL_PAGES_LIST(projectId.toString()), ALL_PAGES_LIST(projectId.toString()),
@ -264,12 +265,7 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
primaryButton={{ primaryButton={{
icon: <Plus className="h-4 w-4" />, icon: <Plus className="h-4 w-4" />,
text: "New Page", text: "New Page",
onClick: () => { onClick: () => commandPaletteStore.toggleCreatePageModal(true),
const e = new KeyboardEvent("keydown", {
key: "d",
});
document.dispatchEvent(e);
},
}} }}
/> />
)} )}
@ -294,4 +290,4 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
)} )}
</> </>
); );
}; });

View File

@ -18,7 +18,7 @@ export interface IProjectCardList {
export const ProjectCardList: FC<IProjectCardList> = observer((props) => { export const ProjectCardList: FC<IProjectCardList> = observer((props) => {
const { workspaceSlug } = props; const { workspaceSlug } = props;
// store // store
const { project: projectStore } = useMobxStore(); const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null; const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
@ -53,12 +53,7 @@ export const ProjectCardList: FC<IProjectCardList> = observer((props) => {
primaryButton={{ primaryButton={{
icon: <Plus className="h-4 w-4" />, icon: <Plus className="h-4 w-4" />,
text: "New Project", text: "New Project",
onClick: () => { onClick: () => commandPaletteStore.toggleCreateProjectModal(true),
const e = new KeyboardEvent("keydown", {
key: "p",
});
document.dispatchEvent(e);
},
}} }}
/> />
)} )}

View File

@ -19,11 +19,6 @@ import { IProject } from "types";
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
export const ProjectSidebarList: FC = observer(() => { export const ProjectSidebarList: FC = observer(() => {
const { theme: themeStore, project: projectStore } = useMobxStore();
// router
const router = useRouter();
const { workspaceSlug } = router.query;
// states // states
const [isFavoriteProjectCreate, setIsFavoriteProjectCreate] = useState(false); const [isFavoriteProjectCreate, setIsFavoriteProjectCreate] = useState(false);
const [isProjectModalOpen, setIsProjectModalOpen] = useState(false); const [isProjectModalOpen, setIsProjectModalOpen] = useState(false);
@ -31,6 +26,11 @@ export const ProjectSidebarList: FC = observer(() => {
// refs // refs
const containerRef = useRef<HTMLDivElement | null>(null); const containerRef = useRef<HTMLDivElement | null>(null);
const { theme: themeStore, project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
// router
const router = useRouter();
const { workspaceSlug } = router.query;
// toast // toast
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -254,12 +254,7 @@ export const ProjectSidebarList: FC = observer(() => {
<button <button
type="button" type="button"
className="flex w-full items-center gap-2 px-3 text-sm text-custom-sidebar-text-200" className="flex w-full items-center gap-2 px-3 text-sm text-custom-sidebar-text-200"
onClick={() => { onClick={() => commandPaletteStore.toggleCreateProjectModal(true)}
const e = new KeyboardEvent("keydown", {
key: "p",
});
document.dispatchEvent(e);
}}
> >
<Plus className="h-5 w-5" /> <Plus className="h-5 w-5" />
{!isCollapsed && "Add Project"} {!isCollapsed && "Add Project"}

View File

@ -20,7 +20,7 @@ export const ProjectViewsList = observer(() => {
const router = useRouter(); const router = useRouter();
const { projectId } = router.query; const { projectId } = router.query;
const { projectViews: projectViewsStore } = useMobxStore(); const { projectViews: projectViewsStore, commandPalette: commandPaletteStore } = useMobxStore();
const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined; const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined;
@ -66,12 +66,7 @@ export const ProjectViewsList = observer(() => {
primaryButton={{ primaryButton={{
icon: <Plus size={14} strokeWidth={2} />, icon: <Plus size={14} strokeWidth={2} />,
text: "New View", text: "New View",
onClick: () => { onClick: () => commandPaletteStore.toggleCreateViewModal(true),
const e = new KeyboardEvent("keydown", {
key: "v",
});
document.dispatchEvent(e);
},
}} }}
/> />
)} )}

View File

@ -43,7 +43,7 @@ export interface WorkspaceHelpSectionProps {
export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = observer(() => { export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = observer(() => {
// store // store
const { theme: themeStore } = useMobxStore(); const { theme: themeStore, commandPalette: commandPaletteStore } = useMobxStore();
// states // states
const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false); const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false);
// refs // refs
@ -71,12 +71,7 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = observe
className={`grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none ${ className={`grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none ${
isCollapsed ? "w-full" : "" isCollapsed ? "w-full" : ""
}`} }`}
onClick={() => { onClick={() => commandPaletteStore.toggleShortcutModal(true)}
const e = new KeyboardEvent("keydown", {
key: "h",
});
document.dispatchEvent(e);
}}
> >
<Zap className="h-3.5 w-3.5" /> <Zap className="h-3.5 w-3.5" />
</button> </button>

View File

@ -8,14 +8,18 @@ import useLocalStorage from "hooks/use-local-storage";
import { CreateUpdateDraftIssueModal } from "components/issues"; import { CreateUpdateDraftIssueModal } from "components/issues";
// mobx store // mobx store
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
import { observer } from "mobx-react-lite";
export const WorkspaceSidebarQuickAction = () => { export const WorkspaceSidebarQuickAction = observer(() => {
const store: any = useMobxStore(); // states
const [isDraftIssueModalOpen, setIsDraftIssueModalOpen] = useState(false); const [isDraftIssueModalOpen, setIsDraftIssueModalOpen] = useState(false);
const { theme: themeStore, commandPalette: commandPaletteStore } = useMobxStore();
const { storedValue, clearValue } = useLocalStorage<any>("draftedIssue", JSON.stringify({})); const { storedValue, clearValue } = useLocalStorage<any>("draftedIssue", JSON.stringify({}));
const isSidebarCollapsed = themeStore.sidebarCollapsed;
return ( return (
<> <>
<CreateUpdateDraftIssueModal <CreateUpdateDraftIssueModal
@ -31,12 +35,12 @@ export const WorkspaceSidebarQuickAction = () => {
<div <div
className={`flex items-center justify-between w-full cursor-pointer px-4 mt-4 ${ className={`flex items-center justify-between w-full cursor-pointer px-4 mt-4 ${
store?.theme?.sidebarCollapsed ? "flex-col gap-1" : "gap-2" isSidebarCollapsed ? "flex-col gap-1" : "gap-2"
}`} }`}
> >
<div <div
className={`relative flex items-center justify-between w-full rounded cursor-pointer px-2 gap-1 group ${ className={`relative flex items-center justify-between w-full rounded cursor-pointer px-2 gap-1 group ${
store?.theme?.sidebarCollapsed isSidebarCollapsed
? "px-2 hover:bg-custom-sidebar-background-80" ? "px-2 hover:bg-custom-sidebar-background-80"
: "px-3 shadow border-[0.5px] border-custom-border-300" : "px-3 shadow border-[0.5px] border-custom-border-300"
}`} }`}
@ -44,29 +48,22 @@ export const WorkspaceSidebarQuickAction = () => {
<button <button
type="button" type="button"
className={`relative flex items-center gap-2 flex-grow rounded flex-shrink-0 py-1.5 ${ className={`relative flex items-center gap-2 flex-grow rounded flex-shrink-0 py-1.5 ${
store?.theme?.sidebarCollapsed ? "justify-center" : "" isSidebarCollapsed ? "justify-center" : ""
}`} }`}
onClick={() => { onClick={() => commandPaletteStore.toggleCreateIssueModal(true)}
const e = new KeyboardEvent("keydown", { key: "c" });
document.dispatchEvent(e);
}}
> >
<PenSquare className="h-4 w-4 text-custom-sidebar-text-300" /> <PenSquare className="h-4 w-4 text-custom-sidebar-text-300" />
{!store?.theme?.sidebarCollapsed && <span className="text-sm font-medium">New Issue</span>} {!isSidebarCollapsed && <span className="text-sm font-medium">New Issue</span>}
</button> </button>
{storedValue && Object.keys(JSON.parse(storedValue)).length > 0 && ( {storedValue && Object.keys(JSON.parse(storedValue)).length > 0 && (
<> <>
<div <div className={`h-8 w-0.5 bg-custom-sidebar-background-80 ${isSidebarCollapsed ? "hidden" : "block"}`} />
className={`h-8 w-0.5 bg-custom-sidebar-background-80 ${
store?.theme?.sidebarCollapsed ? "hidden" : "block"
}`}
/>
<button <button
type="button" type="button"
className={`flex items-center justify-center rounded flex-shrink-0 py-1.5 ml-1.5 ${ className={`flex items-center justify-center rounded flex-shrink-0 py-1.5 ml-1.5 ${
store?.theme?.sidebarCollapsed ? "hidden" : "block" isSidebarCollapsed ? "hidden" : "block"
}`} }`}
> >
<ChevronDown <ChevronDown
@ -77,7 +74,7 @@ export const WorkspaceSidebarQuickAction = () => {
<div <div
className={`fixed h-10 pt-2 w-[203px] left-4 opacity-0 group-hover:opacity-100 mt-0 pointer-events-none group-hover:pointer-events-auto ${ className={`fixed h-10 pt-2 w-[203px] left-4 opacity-0 group-hover:opacity-100 mt-0 pointer-events-none group-hover:pointer-events-auto ${
store?.theme?.sidebarCollapsed ? "top-[5.5rem]" : "top-24" isSidebarCollapsed ? "top-[5.5rem]" : "top-24"
}`} }`}
> >
<div className="w-full h-full"> <div className="w-full h-full">
@ -96,18 +93,15 @@ export const WorkspaceSidebarQuickAction = () => {
<button <button
className={`flex items-center justify-center rounded flex-shrink-0 p-2 ${ className={`flex items-center justify-center rounded flex-shrink-0 p-2 ${
store?.theme?.sidebarCollapsed isSidebarCollapsed
? "hover:bg-custom-sidebar-background-80" ? "hover:bg-custom-sidebar-background-80"
: "shadow border-[0.5px] border-custom-border-300" : "shadow border-[0.5px] border-custom-border-300"
}`} }`}
onClick={() => { onClick={() => commandPaletteStore.toggleCommandPaletteModal(true)}
const e = new KeyboardEvent("keydown", { key: "k", ctrlKey: true, metaKey: true });
document.dispatchEvent(e);
}}
> >
<Search className="h-4 w-4 text-custom-sidebar-text-300" /> <Search className="h-4 w-4 text-custom-sidebar-text-300" />
</button> </button>
</div> </div>
</> </>
); );
}; });

View File

@ -25,6 +25,7 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
module: moduleStore, module: moduleStore,
projectViews: projectViewsStore, projectViews: projectViewsStore,
inbox: inboxStore, inbox: inboxStore,
commandPalette: commandPaletteStore,
} = useMobxStore(); } = useMobxStore();
// router // router
const router = useRouter(); const router = useRouter();
@ -131,12 +132,7 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
image={emptyProject} image={emptyProject}
primaryButton={{ primaryButton={{
text: "Create Project", text: "Create Project",
onClick: () => { onClick: () => commandPaletteStore.toggleCreateProjectModal(true),
const e = new KeyboardEvent("keydown", {
key: "p",
});
document.dispatchEvent(e);
},
}} }}
/> />
</div> </div>

View File

@ -28,7 +28,7 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
// store // store
const { project: projectStore, user: userStore } = useMobxStore(); const { project: projectStore, user: userStore, commandPalette: commandPaletteStore } = useMobxStore();
const user = userStore.currentUser; const user = userStore.currentUser;
const projects = workspaceSlug ? projectStore.projects[workspaceSlug?.toString()] : null; const projects = workspaceSlug ? projectStore.projects[workspaceSlug?.toString()] : null;
@ -96,12 +96,7 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
primaryButton={{ primaryButton={{
icon: <Plus className="h-4 w-4" />, icon: <Plus className="h-4 w-4" />,
text: "New Project", text: "New Project",
onClick: () => { onClick: () => commandPaletteStore.toggleCreateProjectModal(true),
const e = new KeyboardEvent("keydown", {
key: "p",
});
document.dispatchEvent(e);
},
}} }}
/> />
</> </>