forked from github/plane
fix: command palette changes (#2465)
This commit is contained in:
parent
d689c63368
commit
90776237f3
@ -1,12 +1,7 @@
|
|||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
|
|
||||||
// cmdk
|
|
||||||
import { Command } from "cmdk";
|
import { Command } from "cmdk";
|
||||||
// headless ui
|
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// services
|
// services
|
||||||
import { WorkspaceService } from "services/workspace.service";
|
import { WorkspaceService } from "services/workspace.service";
|
||||||
@ -60,16 +55,20 @@ import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
|||||||
type Props = {
|
type Props = {
|
||||||
deleteIssue: () => void;
|
deleteIssue: () => void;
|
||||||
isPaletteOpen: boolean;
|
isPaletteOpen: boolean;
|
||||||
setIsPaletteOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
closePalette: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// services
|
// services
|
||||||
const workspaceService = new WorkspaceService();
|
const workspaceService = new WorkspaceService();
|
||||||
const issueService = new IssueService();
|
const issueService = new IssueService();
|
||||||
|
|
||||||
export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPaletteOpen }) => {
|
export const CommandModal: React.FC<Props> = (props) => {
|
||||||
|
const { deleteIssue, isPaletteOpen, closePalette } = props;
|
||||||
|
// router
|
||||||
|
const router = useRouter();
|
||||||
|
const { workspaceSlug, projectId, issueId } = router.query;
|
||||||
|
// 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);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isSearching, setIsSearching] = useState(false);
|
const [isSearching, setIsSearching] = useState(false);
|
||||||
@ -86,15 +85,12 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false);
|
const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false);
|
||||||
|
|
||||||
const [pages, setPages] = useState<string[]>([]);
|
const [pages, setPages] = useState<string[]>([]);
|
||||||
|
|
||||||
const page = pages[pages.length - 1];
|
const page = pages[pages.length - 1];
|
||||||
|
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, projectId, issueId } = router.query;
|
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
@ -141,7 +137,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
const handleIssueAssignees = (assignee: string) => {
|
const handleIssueAssignees = (assignee: string) => {
|
||||||
if (!issueDetails) return;
|
if (!issueDetails) return;
|
||||||
|
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
const updatedAssignees = issueDetails.assignees ?? [];
|
const updatedAssignees = issueDetails.assignees ?? [];
|
||||||
|
|
||||||
if (updatedAssignees.includes(assignee)) {
|
if (updatedAssignees.includes(assignee)) {
|
||||||
@ -153,12 +149,12 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
};
|
};
|
||||||
|
|
||||||
const redirect = (path: string) => {
|
const redirect = (path: string) => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
router.push(path);
|
router.push(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
const createNewWorkspace = () => {
|
const createNewWorkspace = () => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
router.push("/create-workspace");
|
router.push("/create-workspace");
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -236,7 +232,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
}}
|
}}
|
||||||
as={React.Fragment}
|
as={React.Fragment}
|
||||||
>
|
>
|
||||||
<Dialog as="div" className="relative z-30" onClose={() => setIsPaletteOpen(false)}>
|
<Dialog as="div" className="relative z-30" onClose={() => closePalette()}>
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={React.Fragment}
|
as={React.Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
@ -269,7 +265,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
// when search is empty and page is undefined
|
// when search is empty and page is undefined
|
||||||
// when user tries to close the modal with esc
|
// when user tries to close the modal with esc
|
||||||
if (e.key === "Escape" && !page && !searchTerm) {
|
if (e.key === "Escape" && !page && !searchTerm) {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
}
|
}
|
||||||
// Escape goes to previous page
|
// Escape goes to previous page
|
||||||
// Backspace goes to previous page when search is empty
|
// Backspace goes to previous page when search is empty
|
||||||
@ -365,7 +361,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Item
|
<Command.Item
|
||||||
key={item.id}
|
key={item.id}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
router.push(currentSection.path(item));
|
router.push(currentSection.path(item));
|
||||||
}}
|
}}
|
||||||
value={`${key}-${item?.name}`}
|
value={`${key}-${item?.name}`}
|
||||||
@ -388,7 +384,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Group heading="Issue actions">
|
<Command.Group heading="Issue actions">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
setPlaceholder("Change state...");
|
setPlaceholder("Change state...");
|
||||||
setSearchTerm("");
|
setSearchTerm("");
|
||||||
setPages([...pages, "change-issue-state"]);
|
setPages([...pages, "change-issue-state"]);
|
||||||
@ -455,7 +451,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
</Command.Item>
|
</Command.Item>
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
copyIssueUrlToClipboard();
|
copyIssueUrlToClipboard();
|
||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
@ -470,7 +466,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Group heading="Issue">
|
<Command.Group heading="Issue">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
const e = new KeyboardEvent("keydown", {
|
const e = new KeyboardEvent("keydown", {
|
||||||
key: "c",
|
key: "c",
|
||||||
});
|
});
|
||||||
@ -490,7 +486,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Group heading="Project">
|
<Command.Group heading="Project">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
const e = new KeyboardEvent("keydown", {
|
const e = new KeyboardEvent("keydown", {
|
||||||
key: "p",
|
key: "p",
|
||||||
});
|
});
|
||||||
@ -512,7 +508,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Group heading="Cycle">
|
<Command.Group heading="Cycle">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
const e = new KeyboardEvent("keydown", {
|
const e = new KeyboardEvent("keydown", {
|
||||||
key: "q",
|
key: "q",
|
||||||
});
|
});
|
||||||
@ -530,7 +526,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Group heading="Module">
|
<Command.Group heading="Module">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
const e = new KeyboardEvent("keydown", {
|
const e = new KeyboardEvent("keydown", {
|
||||||
key: "m",
|
key: "m",
|
||||||
});
|
});
|
||||||
@ -548,7 +544,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Group heading="View">
|
<Command.Group heading="View">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
const e = new KeyboardEvent("keydown", {
|
const e = new KeyboardEvent("keydown", {
|
||||||
key: "v",
|
key: "v",
|
||||||
});
|
});
|
||||||
@ -566,7 +562,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Group heading="Page">
|
<Command.Group heading="Page">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
const e = new KeyboardEvent("keydown", {
|
const e = new KeyboardEvent("keydown", {
|
||||||
key: "d",
|
key: "d",
|
||||||
});
|
});
|
||||||
@ -623,7 +619,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
<Command.Group heading="Help">
|
<Command.Group heading="Help">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
const e = new KeyboardEvent("keydown", {
|
const e = new KeyboardEvent("keydown", {
|
||||||
key: "h",
|
key: "h",
|
||||||
});
|
});
|
||||||
@ -638,7 +634,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
</Command.Item>
|
</Command.Item>
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
window.open("https://docs.plane.so/", "_blank");
|
window.open("https://docs.plane.so/", "_blank");
|
||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
@ -650,7 +646,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
</Command.Item>
|
</Command.Item>
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
window.open("https://discord.com/invite/A92xrEGCge", "_blank");
|
window.open("https://discord.com/invite/A92xrEGCge", "_blank");
|
||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
@ -662,7 +658,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
</Command.Item>
|
</Command.Item>
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
window.open("https://github.com/makeplane/plane/issues/new/choose", "_blank");
|
window.open("https://github.com/makeplane/plane/issues/new/choose", "_blank");
|
||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
@ -674,7 +670,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
</Command.Item>
|
</Command.Item>
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setIsPaletteOpen(false);
|
closePalette();
|
||||||
(window as any).$crisp.push(["do", "chat:open"]);
|
(window as any).$crisp.push(["do", "chat:open"]);
|
||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
@ -747,15 +743,15 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{page === "change-issue-state" && issueDetails && (
|
{page === "change-issue-state" && issueDetails && (
|
||||||
<ChangeIssueState issue={issueDetails} setIsPaletteOpen={setIsPaletteOpen} user={user} />
|
<ChangeIssueState issue={issueDetails} setIsPaletteOpen={closePalette} user={user} />
|
||||||
)}
|
)}
|
||||||
{page === "change-issue-priority" && issueDetails && (
|
{page === "change-issue-priority" && issueDetails && (
|
||||||
<ChangeIssuePriority issue={issueDetails} setIsPaletteOpen={setIsPaletteOpen} user={user} />
|
<ChangeIssuePriority issue={issueDetails} setIsPaletteOpen={closePalette} user={user} />
|
||||||
)}
|
)}
|
||||||
{page === "change-issue-assignee" && issueDetails && (
|
{page === "change-issue-assignee" && issueDetails && (
|
||||||
<ChangeIssueAssignee issue={issueDetails} setIsPaletteOpen={setIsPaletteOpen} user={user} />
|
<ChangeIssueAssignee issue={issueDetails} setIsPaletteOpen={closePalette} user={user} />
|
||||||
)}
|
)}
|
||||||
{page === "change-interface-theme" && <ChangeInterfaceTheme setIsPaletteOpen={setIsPaletteOpen} />}
|
{page === "change-interface-theme" && <ChangeInterfaceTheme setIsPaletteOpen={closePalette} />}
|
||||||
</Command.List>
|
</Command.List>
|
||||||
</Command>
|
</Command>
|
||||||
</Dialog.Panel>
|
</Dialog.Panel>
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, FC } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
@ -6,7 +6,7 @@ import { observer } from "mobx-react-lite";
|
|||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
import useUser from "hooks/use-user";
|
import useUser from "hooks/use-user";
|
||||||
// components
|
// components
|
||||||
import { CommandK, ShortcutsModal } from "components/command-palette";
|
import { CommandModal, ShortcutsModal } from "components/command-palette";
|
||||||
import { BulkDeleteIssuesModal } from "components/core";
|
import { BulkDeleteIssuesModal } from "components/core";
|
||||||
import { CreateUpdateCycleModal } from "components/cycles";
|
import { CreateUpdateCycleModal } from "components/cycles";
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
@ -26,22 +26,34 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||||||
// services
|
// services
|
||||||
const issueService = new IssueService();
|
const issueService = new IssueService();
|
||||||
|
|
||||||
export const CommandPalette: React.FC = observer(() => {
|
export const CommandPalette: FC = observer(() => {
|
||||||
const store: any = useMobxStore();
|
|
||||||
|
|
||||||
const [isPaletteOpen, setIsPaletteOpen] = useState(false);
|
|
||||||
const [isIssueModalOpen, setIsIssueModalOpen] = useState(false);
|
|
||||||
const [isProjectModalOpen, setIsProjectModalOpen] = useState(false);
|
|
||||||
const [isShortcutsModalOpen, setIsShortcutsModalOpen] = useState(false);
|
|
||||||
const [isCreateCycleModalOpen, setIsCreateCycleModalOpen] = useState(false);
|
|
||||||
const [isCreateViewModalOpen, setIsCreateViewModalOpen] = useState(false);
|
|
||||||
const [isCreateModuleModalOpen, setIsCreateModuleModalOpen] = useState(false);
|
|
||||||
const [isBulkDeleteIssuesModalOpen, setIsBulkDeleteIssuesModalOpen] = useState(false);
|
|
||||||
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
|
||||||
const [isCreateUpdatePageModalOpen, setIsCreateUpdatePageModalOpen] = useState(false);
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, issueId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, issueId, cycleId, moduleId } = router.query;
|
||||||
|
// store
|
||||||
|
const { commandPalette, theme: themeStore } = useMobxStore();
|
||||||
|
const {
|
||||||
|
isCommandPaletteOpen,
|
||||||
|
toggleCommandPaletteModal,
|
||||||
|
isCreateIssueModalOpen,
|
||||||
|
toggleCreateIssueModal,
|
||||||
|
isCreateCycleModalOpen,
|
||||||
|
toggleCreateCycleModal,
|
||||||
|
isCreatePageModalOpen,
|
||||||
|
toggleCreatePageModal,
|
||||||
|
isCreateProjectModalOpen,
|
||||||
|
toggleCreateProjectModal,
|
||||||
|
isCreateModuleModalOpen,
|
||||||
|
toggleCreateModuleModal,
|
||||||
|
isCreateViewModalOpen,
|
||||||
|
toggleCreateViewModal,
|
||||||
|
isShortcutModalOpen,
|
||||||
|
toggleShortcutModal,
|
||||||
|
isBulkDeleteIssueModalOpen,
|
||||||
|
toggleBulkDeleteIssueModal,
|
||||||
|
isDeleteIssueModalOpen,
|
||||||
|
toggleDeleteIssueModal,
|
||||||
|
} = commandPalette;
|
||||||
|
const { setSidebarCollapsed } = themeStore;
|
||||||
|
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
|
||||||
@ -55,7 +67,7 @@ export const CommandPalette: React.FC = observer(() => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const copyIssueUrlToClipboard = useCallback(() => {
|
const copyIssueUrlToClipboard = useCallback(() => {
|
||||||
if (!router.query.issueId) return;
|
if (!issueId) return;
|
||||||
|
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
copyTextToClipboard(url.href)
|
copyTextToClipboard(url.href)
|
||||||
@ -71,7 +83,7 @@ export const CommandPalette: React.FC = observer(() => {
|
|||||||
title: "Some error occurred",
|
title: "Some error occurred",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [router, setToastAlert]);
|
}, [setToastAlert, issueId]);
|
||||||
|
|
||||||
const handleKeyDown = useCallback(
|
const handleKeyDown = useCallback(
|
||||||
(e: KeyboardEvent) => {
|
(e: KeyboardEvent) => {
|
||||||
@ -91,101 +103,142 @@ export const CommandPalette: React.FC = observer(() => {
|
|||||||
if (cmdClicked) {
|
if (cmdClicked) {
|
||||||
if (keyPressed === "k") {
|
if (keyPressed === "k") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setIsPaletteOpen(true);
|
toggleCommandPaletteModal(true);
|
||||||
} else if (keyPressed === "c" && altKey) {
|
} else if (keyPressed === "c" && altKey) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
copyIssueUrlToClipboard();
|
copyIssueUrlToClipboard();
|
||||||
} else if (keyPressed === "b") {
|
} else if (keyPressed === "b") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
store.theme.setSidebarCollapsed(!store?.theme?.sidebarCollapsed);
|
setSidebarCollapsed();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (keyPressed === "c") {
|
if (keyPressed === "c") {
|
||||||
setIsIssueModalOpen(true);
|
toggleCreateIssueModal(true);
|
||||||
} else if (keyPressed === "p") {
|
} else if (keyPressed === "p") {
|
||||||
setIsProjectModalOpen(true);
|
toggleCreateProjectModal(true);
|
||||||
} else if (keyPressed === "v") {
|
} else if (keyPressed === "v") {
|
||||||
setIsCreateViewModalOpen(true);
|
toggleCreateViewModal(true);
|
||||||
} else if (keyPressed === "d") {
|
} else if (keyPressed === "d") {
|
||||||
setIsCreateUpdatePageModalOpen(true);
|
toggleCreatePageModal(true);
|
||||||
} else if (keyPressed === "h") {
|
} else if (keyPressed === "h") {
|
||||||
setIsShortcutsModalOpen(true);
|
toggleShortcutModal(true);
|
||||||
} else if (keyPressed === "q") {
|
} else if (keyPressed === "q") {
|
||||||
setIsCreateCycleModalOpen(true);
|
toggleCreateCycleModal(true);
|
||||||
} else if (keyPressed === "m") {
|
} else if (keyPressed === "m") {
|
||||||
setIsCreateModuleModalOpen(true);
|
toggleCreateModuleModal(true);
|
||||||
} else if (keyPressed === "backspace" || keyPressed === "delete") {
|
} else if (keyPressed === "backspace" || keyPressed === "delete") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setIsBulkDeleteIssuesModalOpen(true);
|
toggleBulkDeleteIssueModal(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[copyIssueUrlToClipboard, store.theme]
|
[
|
||||||
|
copyIssueUrlToClipboard,
|
||||||
|
toggleCreateProjectModal,
|
||||||
|
toggleCreateViewModal,
|
||||||
|
toggleCreatePageModal,
|
||||||
|
toggleShortcutModal,
|
||||||
|
toggleCreateCycleModal,
|
||||||
|
toggleCreateModuleModal,
|
||||||
|
toggleBulkDeleteIssueModal,
|
||||||
|
toggleCommandPaletteModal,
|
||||||
|
setSidebarCollapsed,
|
||||||
|
toggleCreateIssueModal,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.addEventListener("keydown", handleKeyDown);
|
document.addEventListener("keydown", handleKeyDown);
|
||||||
|
|
||||||
return () => document.removeEventListener("keydown", handleKeyDown);
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
||||||
}, [handleKeyDown]);
|
}, [handleKeyDown]);
|
||||||
|
|
||||||
if (!user) return null;
|
if (!user) return null;
|
||||||
|
|
||||||
const deleteIssue = () => {
|
const deleteIssue = () => {
|
||||||
setIsPaletteOpen(false);
|
toggleCommandPaletteModal(false);
|
||||||
setDeleteIssueModal(true);
|
toggleDeleteIssueModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ShortcutsModal isOpen={isShortcutsModalOpen} setIsOpen={setIsShortcutsModalOpen} />
|
<ShortcutsModal
|
||||||
|
isOpen={isShortcutModalOpen}
|
||||||
|
onClose={() => {
|
||||||
|
toggleShortcutModal(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{workspaceSlug && (
|
{workspaceSlug && (
|
||||||
<CreateProjectModal isOpen={isProjectModalOpen} setIsOpen={setIsProjectModalOpen} user={user} />
|
<CreateProjectModal
|
||||||
|
isOpen={isCreateProjectModalOpen}
|
||||||
|
onClose={() => {
|
||||||
|
toggleCreateProjectModal(false);
|
||||||
|
}}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{projectId && (
|
{workspaceSlug && projectId && (
|
||||||
<>
|
<>
|
||||||
<CreateUpdateCycleModal
|
<CreateUpdateCycleModal
|
||||||
isOpen={isCreateCycleModalOpen}
|
isOpen={isCreateCycleModalOpen}
|
||||||
handleClose={() => setIsCreateCycleModalOpen(false)}
|
handleClose={() => toggleCreateCycleModal(false)}
|
||||||
user={user}
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
/>
|
/>
|
||||||
<CreateUpdateModuleModal
|
<CreateUpdateModuleModal
|
||||||
isOpen={isCreateModuleModalOpen}
|
isOpen={isCreateModuleModalOpen}
|
||||||
setIsOpen={setIsCreateModuleModalOpen}
|
onClose={() => {
|
||||||
user={user}
|
toggleCreateModuleModal(false);
|
||||||
|
}}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
/>
|
/>
|
||||||
<CreateUpdateProjectViewModal
|
<CreateUpdateProjectViewModal
|
||||||
isOpen={isCreateViewModalOpen}
|
isOpen={isCreateViewModalOpen}
|
||||||
onClose={() => setIsCreateViewModalOpen(false)}
|
onClose={() => toggleCreateViewModal(false)}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
/>
|
/>
|
||||||
<CreateUpdatePageModal
|
<CreateUpdatePageModal
|
||||||
isOpen={isCreateUpdatePageModalOpen}
|
isOpen={isCreatePageModalOpen}
|
||||||
handleClose={() => setIsCreateUpdatePageModalOpen(false)}
|
handleClose={() => toggleCreatePageModal(false)}
|
||||||
user={user}
|
user={user}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{issueId && issueDetails && (
|
|
||||||
<DeleteIssueModal
|
|
||||||
handleClose={() => setDeleteIssueModal(false)}
|
|
||||||
isOpen={deleteIssueModal}
|
|
||||||
data={issueDetails}
|
|
||||||
user={user}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<CreateUpdateIssueModal
|
<CreateUpdateIssueModal
|
||||||
isOpen={isIssueModalOpen}
|
isOpen={isCreateIssueModalOpen}
|
||||||
handleClose={() => setIsIssueModalOpen(false)}
|
handleClose={() => toggleCreateIssueModal(false)}
|
||||||
prePopulateData={
|
prePopulateData={
|
||||||
cycleId ? { cycle: cycleId.toString() } : moduleId ? { module: moduleId.toString() } : undefined
|
cycleId ? { cycle: cycleId.toString() } : moduleId ? { module: moduleId.toString() } : undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{issueId && issueDetails && (
|
||||||
|
<DeleteIssueModal
|
||||||
|
handleClose={() => toggleDeleteIssueModal(false)}
|
||||||
|
isOpen={isDeleteIssueModalOpen}
|
||||||
|
data={issueDetails}
|
||||||
|
user={user}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<BulkDeleteIssuesModal
|
<BulkDeleteIssuesModal
|
||||||
isOpen={isBulkDeleteIssuesModalOpen}
|
isOpen={isBulkDeleteIssueModalOpen}
|
||||||
setIsOpen={setIsBulkDeleteIssuesModalOpen}
|
onClose={() => {
|
||||||
|
toggleBulkDeleteIssueModal(false);
|
||||||
|
}}
|
||||||
user={user}
|
user={user}
|
||||||
/>
|
/>
|
||||||
<CommandK deleteIssue={deleteIssue} isPaletteOpen={isPaletteOpen} setIsPaletteOpen={setIsPaletteOpen} />
|
<CommandModal
|
||||||
|
deleteIssue={deleteIssue}
|
||||||
|
isPaletteOpen={isCommandPaletteOpen}
|
||||||
|
closePalette={() => {
|
||||||
|
toggleCommandPaletteModal(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export * from "./issue";
|
export * from "./issue";
|
||||||
export * from "./change-interface-theme";
|
export * from "./change-interface-theme";
|
||||||
export * from "./command-k";
|
export * from "./command-modal";
|
||||||
export * from "./command-pallette";
|
export * from "./command-pallette";
|
||||||
export * from "./helpers";
|
export * from "./helpers";
|
||||||
export * from "./shortcuts-modal";
|
export * from "./shortcuts-modal";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import { FC, useEffect, useState, Dispatch, SetStateAction, Fragment } from "react";
|
||||||
// headless ui
|
// headless ui
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// icons
|
// icons
|
||||||
@ -8,7 +8,7 @@ import { Input } from "@plane/ui";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
onClose: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const shortcuts = [
|
const shortcuts = [
|
||||||
@ -43,8 +43,11 @@ const shortcuts = [
|
|||||||
|
|
||||||
const allShortcuts = shortcuts.map((i) => i.shortcuts).flat(1);
|
const allShortcuts = shortcuts.map((i) => i.shortcuts).flat(1);
|
||||||
|
|
||||||
export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
export const ShortcutsModal: FC<Props> = (props) => {
|
||||||
|
const { isOpen, onClose } = props;
|
||||||
|
// states
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
// computed
|
||||||
const filteredShortcuts = allShortcuts.filter((shortcut) =>
|
const filteredShortcuts = allShortcuts.filter((shortcut) =>
|
||||||
shortcut.description.toLowerCase().includes(query.trim().toLowerCase()) || query === "" ? true : false
|
shortcut.description.toLowerCase().includes(query.trim().toLowerCase()) || query === "" ? true : false
|
||||||
);
|
);
|
||||||
@ -54,10 +57,10 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
|||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={isOpen} as={React.Fragment}>
|
<Transition.Root show={isOpen} as={Fragment}>
|
||||||
<Dialog as="div" className="relative z-20" onClose={setIsOpen}>
|
<Dialog as="div" className="relative z-20" onClose={onClose}>
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={React.Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
@ -71,7 +74,7 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
|||||||
<div className="fixed inset-0 z-20 overflow-y-auto">
|
<div className="fixed inset-0 z-20 overflow-y-auto">
|
||||||
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={React.Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
||||||
@ -89,7 +92,7 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
|||||||
>
|
>
|
||||||
<span>Keyboard Shortcuts</span>
|
<span>Keyboard Shortcuts</span>
|
||||||
<span>
|
<span>
|
||||||
<button type="button" onClick={() => setIsOpen(false)}>
|
<button type="button" onClick={onClose}>
|
||||||
<X className="h-6 w-6 text-custom-text-200 hover:text-custom-text-100" aria-hidden="true" />
|
<X className="h-6 w-6 text-custom-text-200 hover:text-custom-text-100" aria-hidden="true" />
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
@ -33,18 +33,20 @@ type FormInput = {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
onClose: () => void;
|
||||||
user: IUser | undefined;
|
user: IUser | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const issueService = new IssueService();
|
const issueService = new IssueService();
|
||||||
|
|
||||||
export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user }) => {
|
export const BulkDeleteIssuesModal: React.FC<Props> = (props) => {
|
||||||
const [query, setQuery] = useState("");
|
const { isOpen, onClose, user } = props;
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||||
|
// states
|
||||||
|
const [query, setQuery] = useState("");
|
||||||
|
// fetching project issues.
|
||||||
const { data: issues } = useSWR(
|
const { data: issues } = useSWR(
|
||||||
workspaceSlug && projectId ? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string) : null,
|
workspaceSlug && projectId ? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string) : null,
|
||||||
workspaceSlug && projectId ? () => issueService.getIssues(workspaceSlug as string, projectId as string) : null
|
workspaceSlug && projectId ? () => issueService.getIssues(workspaceSlug as string, projectId as string) : null
|
||||||
@ -68,9 +70,9 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setIsOpen(false);
|
|
||||||
setQuery("");
|
setQuery("");
|
||||||
reset();
|
reset();
|
||||||
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete: SubmitHandler<FormInput> = async (data) => {
|
const handleDelete: SubmitHandler<FormInput> = async (data) => {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// services
|
// services
|
||||||
@ -11,7 +10,7 @@ import { CycleForm } from "components/cycles";
|
|||||||
// helper
|
// helper
|
||||||
import { getDateRangeStatus } from "helpers/date-time.helper";
|
import { getDateRangeStatus } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import type { CycleDateCheckData, IUser, ICycle, IProject } from "types";
|
import type { CycleDateCheckData, ICycle, IProject, IUser } from "types";
|
||||||
// fetch keys
|
// fetch keys
|
||||||
import {
|
import {
|
||||||
COMPLETED_CYCLES_LIST,
|
COMPLETED_CYCLES_LIST,
|
||||||
@ -27,23 +26,21 @@ type CycleModalProps = {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
data?: ICycle | null;
|
data?: ICycle | null;
|
||||||
user: IUser | undefined;
|
workspaceSlug: string;
|
||||||
|
projectId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// services
|
// services
|
||||||
const cycleService = new CycleService();
|
const cycleService = new CycleService();
|
||||||
|
|
||||||
export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({ isOpen, handleClose, data, user }) => {
|
export const CreateUpdateCycleModal: React.FC<CycleModalProps> = (props) => {
|
||||||
const router = useRouter();
|
const { isOpen, handleClose, data, workspaceSlug, projectId } = props;
|
||||||
const { workspaceSlug, projectId } = router.query;
|
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const createCycle = async (payload: Partial<ICycle>) => {
|
const createCycle = async (payload: Partial<ICycle>) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
await cycleService
|
await cycleService
|
||||||
.createCycle(workspaceSlug.toString(), projectId.toString(), payload, user)
|
.createCycle(workspaceSlug.toString(), projectId.toString(), payload, {} as IUser)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
switch (getDateRangeStatus(res.start_date, res.end_date)) {
|
switch (getDateRangeStatus(res.start_date, res.end_date)) {
|
||||||
case "completed":
|
case "completed":
|
||||||
@ -91,10 +88,8 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({ isOpen, hand
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateCycle = async (cycleId: string, payload: Partial<ICycle>) => {
|
const updateCycle = async (cycleId: string, payload: Partial<ICycle>) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
await cycleService
|
await cycleService
|
||||||
.updateCycle(workspaceSlug.toString(), projectId.toString(), cycleId, payload, user)
|
.updateCycle(workspaceSlug.toString(), projectId.toString(), cycleId, payload, {} as IUser)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
switch (getDateRangeStatus(data?.start_date, data?.end_date)) {
|
switch (getDateRangeStatus(data?.start_date, data?.end_date)) {
|
||||||
case "completed":
|
case "completed":
|
||||||
@ -177,7 +172,6 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({ isOpen, hand
|
|||||||
if (isDateValid) {
|
if (isDateValid) {
|
||||||
if (data) await updateCycle(data.id, payload);
|
if (data) await updateCycle(data.id, payload);
|
||||||
else await createCycle(payload);
|
else await createCycle(payload);
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
} else
|
} else
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
|
@ -50,7 +50,14 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({ projectId, value,
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreateUpdateCycleModal isOpen={isCycleModalActive} handleClose={closeCycleModal} user={user} />
|
{workspaceSlug && projectId && (
|
||||||
|
<CreateUpdateCycleModal
|
||||||
|
isOpen={isCycleModalActive}
|
||||||
|
handleClose={closeCycleModal}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Listbox as="div" className="relative" value={value} onChange={onChange} multiple={multiple}>
|
<Listbox as="div" className="relative" value={value} onChange={onChange} multiple={multiple}>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
|
@ -19,13 +19,20 @@ export const ProjectViewsHeader: FC<IProjectViewsHeader> = (props) => {
|
|||||||
const { title } = props;
|
const { title } = props;
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
// states
|
// states
|
||||||
const [createViewModal, setCreateViewModal] = useState(false);
|
const [createViewModal, setCreateViewModal] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreateUpdateProjectViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
|
{workspaceSlug && projectId && (
|
||||||
|
<CreateUpdateProjectViewModal
|
||||||
|
isOpen={createViewModal}
|
||||||
|
onClose={() => setCreateViewModal(false)}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
|
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
|
||||||
>
|
>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
@ -16,9 +15,10 @@ import { MODULE_LIST } from "constants/fetch-keys";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
onClose: () => void;
|
||||||
data?: IModule;
|
data?: IModule;
|
||||||
user: IUser | undefined;
|
workspaceSlug: string;
|
||||||
|
projectId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValues: Partial<IModule> = {
|
const defaultValues: Partial<IModule> = {
|
||||||
@ -31,15 +31,14 @@ const defaultValues: Partial<IModule> = {
|
|||||||
|
|
||||||
const moduleService = new ModuleService();
|
const moduleService = new ModuleService();
|
||||||
|
|
||||||
export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data, user }) => {
|
export const CreateUpdateModuleModal: React.FC<Props> = (props) => {
|
||||||
const router = useRouter();
|
const { isOpen, onClose, data, workspaceSlug, projectId } = props;
|
||||||
const { workspaceSlug, projectId } = router.query;
|
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setIsOpen(false);
|
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const { reset } = useForm<IModule>({
|
const { reset } = useForm<IModule>({
|
||||||
@ -48,7 +47,7 @@ export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, da
|
|||||||
|
|
||||||
const createModule = async (payload: Partial<IModule>) => {
|
const createModule = async (payload: Partial<IModule>) => {
|
||||||
await moduleService
|
await moduleService
|
||||||
.createModule(workspaceSlug as string, projectId as string, payload, user)
|
.createModule(workspaceSlug as string, projectId as string, payload, {} as IUser)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
mutate(MODULE_LIST(projectId as string));
|
mutate(MODULE_LIST(projectId as string));
|
||||||
handleClose();
|
handleClose();
|
||||||
@ -70,7 +69,7 @@ export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, da
|
|||||||
|
|
||||||
const updateModule = async (payload: Partial<IModule>) => {
|
const updateModule = async (payload: Partial<IModule>) => {
|
||||||
await moduleService
|
await moduleService
|
||||||
.updateModule(workspaceSlug as string, projectId as string, data?.id ?? "", payload, user)
|
.updateModule(workspaceSlug as string, projectId as string, data?.id ?? "", payload, {} as IUser)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate<IModule[]>(
|
mutate<IModule[]>(
|
||||||
MODULE_LIST(projectId as string),
|
MODULE_LIST(projectId as string),
|
||||||
|
@ -22,14 +22,17 @@ type Props = {
|
|||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
data?: IPage | null;
|
data?: IPage | null;
|
||||||
user: IUser | undefined;
|
user: IUser | undefined;
|
||||||
|
workspaceSlug: string;
|
||||||
|
projectId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// services
|
// services
|
||||||
const pageService = new PageService();
|
const pageService = new PageService();
|
||||||
|
|
||||||
export const CreateUpdatePageModal: React.FC<Props> = ({ isOpen, handleClose, data, user }) => {
|
export const CreateUpdatePageModal: React.FC<Props> = (props) => {
|
||||||
|
const { isOpen, handleClose, data, user, workspaceSlug, projectId } = props;
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
|
@ -38,14 +38,14 @@ 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> = ({ pages, viewType }) => {
|
||||||
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
|
// router
|
||||||
const [selectedPageToUpdate, setSelectedPageToUpdate] = useState<IPage | null>(null);
|
|
||||||
|
|
||||||
const [deletePageModal, setDeletePageModal] = useState(false);
|
|
||||||
const [selectedPageToDelete, setSelectedPageToDelete] = useState<IPage | null>(null);
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// states
|
||||||
|
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
|
||||||
|
const [selectedPageToUpdate, setSelectedPageToUpdate] = useState<IPage | null>(null);
|
||||||
|
const [deletePageModal, setDeletePageModal] = useState(false);
|
||||||
|
const [selectedPageToDelete, setSelectedPageToDelete] = useState<IPage | null>(null);
|
||||||
|
|
||||||
const { user } = useUserAuth();
|
const { user } = useUserAuth();
|
||||||
|
|
||||||
@ -188,18 +188,25 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreateUpdatePageModal
|
{workspaceSlug && projectId && (
|
||||||
isOpen={createUpdatePageModal}
|
<>
|
||||||
handleClose={() => setCreateUpdatePageModal(false)}
|
<CreateUpdatePageModal
|
||||||
data={selectedPageToUpdate}
|
isOpen={createUpdatePageModal}
|
||||||
user={user}
|
handleClose={() => setCreateUpdatePageModal(false)}
|
||||||
/>
|
data={selectedPageToUpdate}
|
||||||
<DeletePageModal
|
user={user}
|
||||||
isOpen={deletePageModal}
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
setIsOpen={setDeletePageModal}
|
projectId={projectId.toString()}
|
||||||
data={selectedPageToDelete}
|
/>
|
||||||
user={user}
|
<DeletePageModal
|
||||||
/>
|
isOpen={deletePageModal}
|
||||||
|
setIsOpen={setDeletePageModal}
|
||||||
|
data={selectedPageToDelete}
|
||||||
|
user={user}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{pages ? (
|
{pages ? (
|
||||||
<div className="space-y-4 h-full overflow-y-auto">
|
<div className="space-y-4 h-full overflow-y-auto">
|
||||||
{pages.length > 0 ? (
|
{pages.length > 0 ? (
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { useState, useEffect, Fragment } from "react";
|
import { useState, useEffect, Fragment, FC } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// icons
|
// icons
|
||||||
import { Users2, X } from "lucide-react";
|
import { Users2, X } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
import { useWorkspaceMyMembership } from "contexts/workspace-member.context";
|
import { useWorkspaceMyMembership } from "contexts/workspace-member.context";
|
||||||
import useWorkspaceMembers from "hooks/use-workspace-members";
|
import useWorkspaceMembers from "hooks/use-workspace-members";
|
||||||
@ -17,16 +18,15 @@ import EmojiIconPicker from "components/emoji-icon-picker";
|
|||||||
// helpers
|
// helpers
|
||||||
import { getRandomEmoji, renderEmoji } from "helpers/emoji.helper";
|
import { getRandomEmoji, renderEmoji } from "helpers/emoji.helper";
|
||||||
// types
|
// types
|
||||||
import { IUser, IProject } from "types";
|
import { IProject } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { NETWORK_CHOICES } from "constants/project";
|
import { NETWORK_CHOICES } from "constants/project";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
onClose: () => void;
|
||||||
setToFavorite?: boolean;
|
setToFavorite?: boolean;
|
||||||
user: IUser | undefined;
|
workspaceSlug: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValues: Partial<IProject> = {
|
const defaultValues: Partial<IProject> = {
|
||||||
@ -40,26 +40,27 @@ const defaultValues: Partial<IProject> = {
|
|||||||
project_lead: null,
|
project_lead: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const IsGuestCondition: React.FC<{
|
interface IIsGuestCondition {
|
||||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
onClose: () => void;
|
||||||
}> = ({ setIsOpen }) => {
|
}
|
||||||
|
|
||||||
|
const IsGuestCondition: FC<IIsGuestCondition> = ({ onClose }) => {
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsOpen(false);
|
onClose();
|
||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
type: "error",
|
type: "error",
|
||||||
message: "You don't have permission to create project.",
|
message: "You don't have permission to create project.",
|
||||||
});
|
});
|
||||||
}, [setIsOpen, setToastAlert]);
|
}, [onClose, setToastAlert]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateProjectModal: React.FC<Props> = (props) => {
|
export const CreateProjectModal: React.FC<Props> = (props) => {
|
||||||
const { isOpen, setIsOpen, setToFavorite = false } = props;
|
const { isOpen, onClose, setToFavorite = false, workspaceSlug } = props;
|
||||||
// store
|
// store
|
||||||
const { project: projectStore } = useMobxStore();
|
const { project: projectStore } = useMobxStore();
|
||||||
// states
|
// states
|
||||||
@ -67,9 +68,6 @@ export const CreateProjectModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug } = router.query;
|
|
||||||
|
|
||||||
const { memberDetails } = useWorkspaceMyMembership();
|
const { memberDetails } = useWorkspaceMyMembership();
|
||||||
const { workspaceMembers } = useWorkspaceMembers(workspaceSlug?.toString() ?? "");
|
const { workspaceMembers } = useWorkspaceMembers(workspaceSlug?.toString() ?? "");
|
||||||
|
|
||||||
@ -86,7 +84,7 @@ export const CreateProjectModal: React.FC<Props> = (props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setIsOpen(false);
|
onClose();
|
||||||
setIsChangeInIdentifierRequired(true);
|
setIsChangeInIdentifierRequired(true);
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
};
|
};
|
||||||
@ -172,7 +170,7 @@ export const CreateProjectModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const currentNetwork = NETWORK_CHOICES.find((n) => n.key === watch("network"));
|
const currentNetwork = NETWORK_CHOICES.find((n) => n.key === watch("network"));
|
||||||
|
|
||||||
if (memberDetails && isOpen) if (memberDetails.role <= 10) return <IsGuestCondition setIsOpen={setIsOpen} />;
|
if (memberDetails && isOpen) if (memberDetails.role <= 10) return <IsGuestCondition onClose={onClose} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={isOpen} as={Fragment}>
|
<Transition.Root show={isOpen} as={Fragment}>
|
||||||
|
@ -108,12 +108,16 @@ export const ProjectSidebarList: FC = observer(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreateProjectModal
|
{workspaceSlug && (
|
||||||
isOpen={isProjectModalOpen}
|
<CreateProjectModal
|
||||||
setIsOpen={setIsProjectModalOpen}
|
isOpen={isProjectModalOpen}
|
||||||
setToFavorite={isFavoriteProjectCreate}
|
onClose={() => {
|
||||||
user={user}
|
setIsProjectModalOpen(false);
|
||||||
/>
|
}}
|
||||||
|
setToFavorite={isFavoriteProjectCreate}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
className={`h-full overflow-y-auto px-4 space-y-2 ${
|
className={`h-full overflow-y-auto px-4 space-y-2 ${
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
import React from "react";
|
import { FC, Fragment } from "react";
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
|
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { ProjectViewForm } from "components/views";
|
import { ProjectViewForm } from "components/views";
|
||||||
@ -17,31 +14,24 @@ type Props = {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
preLoadedData?: Partial<IProjectView> | null;
|
preLoadedData?: Partial<IProjectView> | null;
|
||||||
|
workspaceSlug: string;
|
||||||
|
projectId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateUpdateProjectViewModal: React.FC<Props> = observer((props) => {
|
export const CreateUpdateProjectViewModal: FC<Props> = observer((props) => {
|
||||||
const { data, isOpen, onClose, preLoadedData } = props;
|
const { data, isOpen, onClose, preLoadedData, workspaceSlug, projectId } = props;
|
||||||
|
// store
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, projectId } = router.query;
|
|
||||||
|
|
||||||
const { projectViews: projectViewsStore } = useMobxStore();
|
const { projectViews: projectViewsStore } = useMobxStore();
|
||||||
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const createView = async (formData: IProjectView) => {
|
const createView = async (payload: IProjectView) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
...formData,
|
|
||||||
};
|
|
||||||
|
|
||||||
await projectViewsStore
|
await projectViewsStore
|
||||||
.createView(workspaceSlug.toString(), projectId.toString(), payload)
|
.createView(workspaceSlug, projectId, payload)
|
||||||
.then(() => handleClose())
|
.then(() => handleClose())
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -52,15 +42,9 @@ export const CreateUpdateProjectViewModal: React.FC<Props> = observer((props) =>
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateView = async (formData: IProjectView) => {
|
const updateView = async (payload: IProjectView) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
...formData,
|
|
||||||
};
|
|
||||||
|
|
||||||
await projectViewsStore
|
await projectViewsStore
|
||||||
.updateView(workspaceSlug.toString(), projectId.toString(), data?.id as string, payload)
|
.updateView(workspaceSlug, projectId, data?.id as string, payload)
|
||||||
.then(() => handleClose())
|
.then(() => handleClose())
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -77,10 +61,10 @@ export const CreateUpdateProjectViewModal: React.FC<Props> = observer((props) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={isOpen} as={React.Fragment}>
|
<Transition.Root show={isOpen} as={Fragment}>
|
||||||
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={React.Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
@ -94,7 +78,7 @@ export const CreateUpdateProjectViewModal: React.FC<Props> = observer((props) =>
|
|||||||
<div className="fixed inset-0 z-20 overflow-y-auto">
|
<div className="fixed inset-0 z-20 overflow-y-auto">
|
||||||
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
|
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={React.Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
||||||
|
@ -16,7 +16,7 @@ export const AppLayout: FC<IAppLayout> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* <CommandPalette /> */}
|
<CommandPalette />
|
||||||
<UserAuthWrapper>
|
<UserAuthWrapper>
|
||||||
<WorkspaceAuthWrapper>
|
<WorkspaceAuthWrapper>
|
||||||
<div className="relative flex h-screen w-full overflow-hidden">
|
<div className="relative flex h-screen w-full overflow-hidden">
|
||||||
|
@ -66,12 +66,18 @@ const ProjectModules: NextPage = () => {
|
|||||||
<AppLayout
|
<AppLayout
|
||||||
header={<ModulesHeader name={activeProject?.name} modulesView={modulesView} setModulesView={setModulesView} />}
|
header={<ModulesHeader name={activeProject?.name} modulesView={modulesView} setModulesView={setModulesView} />}
|
||||||
>
|
>
|
||||||
<CreateUpdateModuleModal
|
{workspaceSlug && projectId && (
|
||||||
isOpen={createUpdateModule}
|
<CreateUpdateModuleModal
|
||||||
setIsOpen={setCreateUpdateModule}
|
isOpen={createUpdateModule}
|
||||||
data={selectedModule}
|
onClose={() => {
|
||||||
user={user}
|
setCreateUpdateModule(false);
|
||||||
/>
|
}}
|
||||||
|
data={selectedModule}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{modules ? (
|
{modules ? (
|
||||||
modules.length > 0 ? (
|
modules.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
|
@ -51,12 +51,11 @@ const tabsList = ["Recent", "All", "Favorites", "Created by me", "Created by oth
|
|||||||
const projectService = new ProjectService();
|
const projectService = new ProjectService();
|
||||||
|
|
||||||
const ProjectPages: NextPage = () => {
|
const ProjectPages: NextPage = () => {
|
||||||
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
|
|
||||||
|
|
||||||
const [viewType, setViewType] = useState<TPageViewProps>("list");
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// states
|
||||||
|
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
|
||||||
|
const [viewType, setViewType] = useState<TPageViewProps>("list");
|
||||||
|
|
||||||
const { user } = useUserAuth();
|
const { user } = useUserAuth();
|
||||||
|
|
||||||
@ -87,11 +86,16 @@ const ProjectPages: NextPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreateUpdatePageModal
|
{workspaceSlug && projectId && (
|
||||||
isOpen={createUpdatePageModal}
|
<CreateUpdatePageModal
|
||||||
handleClose={() => setCreateUpdatePageModal(false)}
|
isOpen={createUpdatePageModal}
|
||||||
user={user}
|
handleClose={() => setCreateUpdatePageModal(false)}
|
||||||
/>
|
user={user}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<ProjectAuthorizationWrapper
|
<ProjectAuthorizationWrapper
|
||||||
breadcrumbs={
|
breadcrumbs={
|
||||||
<Breadcrumbs onBack={() => router.back()}>
|
<Breadcrumbs onBack={() => router.back()}>
|
||||||
|
161
web/store/command-palette.store.ts
Normal file
161
web/store/command-palette.store.ts
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import { observable, action, makeObservable } from "mobx";
|
||||||
|
// types
|
||||||
|
import { RootStore } from "./root";
|
||||||
|
// services
|
||||||
|
import { ProjectService } from "services/project";
|
||||||
|
import { PageService } from "services/page.service";
|
||||||
|
|
||||||
|
export interface ICommandPaletteStore {
|
||||||
|
isCommandPaletteOpen: boolean;
|
||||||
|
isShortcutModalOpen: boolean;
|
||||||
|
isCreateProjectModalOpen: boolean;
|
||||||
|
isCreateCycleModalOpen: boolean;
|
||||||
|
isCreateModuleModalOpen: boolean;
|
||||||
|
isCreateViewModalOpen: boolean;
|
||||||
|
isCreatePageModalOpen: boolean;
|
||||||
|
isCreateIssueModalOpen: boolean;
|
||||||
|
isDeleteIssueModalOpen: boolean;
|
||||||
|
isBulkDeleteIssueModalOpen: boolean;
|
||||||
|
|
||||||
|
toggleCommandPaletteModal: (value?: boolean) => void;
|
||||||
|
toggleShortcutModal: (value?: boolean) => void;
|
||||||
|
toggleCreateProjectModal: (value?: boolean) => void;
|
||||||
|
toggleCreateCycleModal: (value?: boolean) => void;
|
||||||
|
toggleCreateViewModal: (value?: boolean) => void;
|
||||||
|
toggleCreatePageModal: (value?: boolean) => void;
|
||||||
|
toggleCreateIssueModal: (value?: boolean) => void;
|
||||||
|
toggleCreateModuleModal: (value?: boolean) => void;
|
||||||
|
toggleDeleteIssueModal: (value?: boolean) => void;
|
||||||
|
toggleBulkDeleteIssueModal: (value?: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommandPaletteStore implements ICommandPaletteStore {
|
||||||
|
isCommandPaletteOpen: boolean = false;
|
||||||
|
isShortcutModalOpen: boolean = false;
|
||||||
|
isCreateProjectModalOpen: boolean = false;
|
||||||
|
isCreateCycleModalOpen: boolean = false;
|
||||||
|
isCreateModuleModalOpen: boolean = false;
|
||||||
|
isCreateViewModalOpen: boolean = false;
|
||||||
|
isCreatePageModalOpen: boolean = false;
|
||||||
|
isCreateIssueModalOpen: boolean = false;
|
||||||
|
isDeleteIssueModalOpen: boolean = false;
|
||||||
|
isBulkDeleteIssueModalOpen: boolean = false;
|
||||||
|
// root store
|
||||||
|
rootStore;
|
||||||
|
// service
|
||||||
|
projectService;
|
||||||
|
pageService;
|
||||||
|
|
||||||
|
constructor(_rootStore: RootStore) {
|
||||||
|
makeObservable(this, {
|
||||||
|
// observable
|
||||||
|
isCommandPaletteOpen: observable.ref,
|
||||||
|
isShortcutModalOpen: observable.ref,
|
||||||
|
isCreateProjectModalOpen: observable.ref,
|
||||||
|
isCreateCycleModalOpen: observable.ref,
|
||||||
|
isCreateModuleModalOpen: observable.ref,
|
||||||
|
isCreateViewModalOpen: observable.ref,
|
||||||
|
isCreatePageModalOpen: observable.ref,
|
||||||
|
isDeleteIssueModalOpen: observable.ref,
|
||||||
|
isCreateIssueModalOpen: observable.ref,
|
||||||
|
// computed
|
||||||
|
// projectPages: computed,
|
||||||
|
// action
|
||||||
|
toggleCommandPaletteModal: action,
|
||||||
|
toggleShortcutModal: action,
|
||||||
|
toggleCreateProjectModal: action,
|
||||||
|
toggleCreateCycleModal: action,
|
||||||
|
toggleCreateViewModal: action,
|
||||||
|
toggleCreatePageModal: action,
|
||||||
|
toggleCreateIssueModal: action,
|
||||||
|
toggleCreateModuleModal: action,
|
||||||
|
toggleBulkDeleteIssueModal: action,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.rootStore = _rootStore;
|
||||||
|
this.projectService = new ProjectService();
|
||||||
|
this.pageService = new PageService();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleCommandPaletteModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isCommandPaletteOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isCommandPaletteOpen = !this.isCommandPaletteOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleShortcutModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isShortcutModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isShortcutModalOpen = !this.isShortcutModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleCreateProjectModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isCreateProjectModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isCreateProjectModalOpen = !this.isCreateProjectModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleCreateCycleModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isCreateCycleModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isCreateCycleModalOpen = !this.isCreateCycleModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleCreateViewModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isCreateViewModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isCreateViewModalOpen = !this.isCreateViewModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleCreatePageModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isCreatePageModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isCreatePageModalOpen = !this.isCreatePageModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleCreateIssueModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isCreateIssueModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isCreateIssueModalOpen = !this.isCreateIssueModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleDeleteIssueModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isDeleteIssueModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isDeleteIssueModalOpen = !this.isDeleteIssueModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleCreateModuleModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isCreateModuleModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isCreateModuleModalOpen = !this.isCreateModuleModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleBulkDeleteIssueModal = (value?: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
this.isBulkDeleteIssueModalOpen = value;
|
||||||
|
} else {
|
||||||
|
this.isBulkDeleteIssueModalOpen = !this.isBulkDeleteIssueModalOpen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CommandPaletteStore;
|
@ -1,7 +1,8 @@
|
|||||||
import { enableStaticRendering } from "mobx-react-lite";
|
import { enableStaticRendering } from "mobx-react-lite";
|
||||||
// store imports
|
// store imports
|
||||||
import UserStore from "store/user.store";
|
import CommandPaletteStore, { ICommandPaletteStore } from "./command-palette.store";
|
||||||
import ThemeStore from "store/theme.store";
|
import UserStore, { IUserStore } from "store/user.store";
|
||||||
|
import ThemeStore, { IThemeStore } from "store/theme.store";
|
||||||
import {
|
import {
|
||||||
DraftIssuesStore,
|
DraftIssuesStore,
|
||||||
IIssueDetailStore,
|
IIssueDetailStore,
|
||||||
@ -79,9 +80,10 @@ import {
|
|||||||
enableStaticRendering(typeof window === "undefined");
|
enableStaticRendering(typeof window === "undefined");
|
||||||
|
|
||||||
export class RootStore {
|
export class RootStore {
|
||||||
user;
|
user: IUserStore;
|
||||||
theme;
|
theme: IThemeStore;
|
||||||
|
|
||||||
|
commandPalette: ICommandPaletteStore;
|
||||||
workspace: IWorkspaceStore;
|
workspace: IWorkspaceStore;
|
||||||
workspaceFilter: IWorkspaceFilterStore;
|
workspaceFilter: IWorkspaceFilterStore;
|
||||||
|
|
||||||
@ -129,6 +131,7 @@ export class RootStore {
|
|||||||
inboxFilters: IInboxFiltersStore;
|
inboxFilters: IInboxFiltersStore;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.commandPalette = new CommandPaletteStore(this);
|
||||||
this.user = new UserStore(this);
|
this.user = new UserStore(this);
|
||||||
this.theme = new ThemeStore(this);
|
this.theme = new ThemeStore(this);
|
||||||
|
|
||||||
|
@ -3,7 +3,15 @@ import { action, observable, makeObservable } from "mobx";
|
|||||||
// helper
|
// helper
|
||||||
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
|
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
|
||||||
|
|
||||||
class ThemeStore {
|
export interface IThemeStore {
|
||||||
|
theme: string | null;
|
||||||
|
sidebarCollapsed: boolean | null;
|
||||||
|
|
||||||
|
setSidebarCollapsed: (collapsed?: boolean) => void;
|
||||||
|
setTheme: (theme: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThemeStore implements IThemeStore {
|
||||||
sidebarCollapsed: boolean | null = null;
|
sidebarCollapsed: boolean | null = null;
|
||||||
theme: string | null = null;
|
theme: string | null = null;
|
||||||
// root store
|
// root store
|
||||||
@ -24,8 +32,8 @@ class ThemeStore {
|
|||||||
this.initialLoad();
|
this.initialLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
setSidebarCollapsed(collapsed: boolean | null = null) {
|
setSidebarCollapsed(collapsed?: boolean) {
|
||||||
if (collapsed === null) {
|
if (!collapsed) {
|
||||||
let _sidebarCollapsed: string | boolean | null = localStorage.getItem("app_sidebar_collapsed");
|
let _sidebarCollapsed: string | boolean | null = localStorage.getItem("app_sidebar_collapsed");
|
||||||
_sidebarCollapsed = _sidebarCollapsed ? (_sidebarCollapsed === "true" ? true : false) : false;
|
_sidebarCollapsed = _sidebarCollapsed ? (_sidebarCollapsed === "true" ? true : false) : false;
|
||||||
this.sidebarCollapsed = _sidebarCollapsed;
|
this.sidebarCollapsed = _sidebarCollapsed;
|
||||||
|
@ -8,7 +8,7 @@ import { WorkspaceService } from "services/workspace.service";
|
|||||||
import { IUser, IUserSettings } from "types/users";
|
import { IUser, IUserSettings } from "types/users";
|
||||||
import { IWorkspaceMember, IProjectMember } from "types";
|
import { IWorkspaceMember, IProjectMember } from "types";
|
||||||
|
|
||||||
interface IUserStore {
|
export interface IUserStore {
|
||||||
loader: boolean;
|
loader: boolean;
|
||||||
|
|
||||||
currentUser: IUser | null;
|
currentUser: IUser | null;
|
||||||
@ -28,9 +28,11 @@ interface IUserStore {
|
|||||||
|
|
||||||
fetchUserWorkspaceInfo: (workspaceSlug: string) => Promise<IWorkspaceMember>;
|
fetchUserWorkspaceInfo: (workspaceSlug: string) => Promise<IWorkspaceMember>;
|
||||||
fetchUserProjectInfo: (workspaceSlug: string, projectId: string) => Promise<IProjectMember>;
|
fetchUserProjectInfo: (workspaceSlug: string, projectId: string) => Promise<IProjectMember>;
|
||||||
|
fetchUserDashboardInfo: (workspaceSlug: string, month: number) => Promise<any>;
|
||||||
|
|
||||||
updateTourCompleted: () => Promise<void>;
|
updateTourCompleted: () => Promise<void>;
|
||||||
updateCurrentUser: (data: Partial<IUser>) => Promise<IUser>;
|
updateCurrentUser: (data: Partial<IUser>) => Promise<IUser>;
|
||||||
|
updateCurrentUserTheme: (theme: string) => Promise<IUser>;
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserStore implements IUserStore {
|
class UserStore implements IUserStore {
|
||||||
|
Loading…
Reference in New Issue
Block a user