+
{store.issue.getFilteredIssuesByState(_state.id) &&
store.issue.getFilteredIssuesByState(_state.id).length > 0 ? (
-
+
{store.issue.getFilteredIssuesByState(_state.id).map((_issue: IIssue) => (
-
+
))}
) : (
-
- No Issues are available.
+
+
+ No issues in this state
)}
diff --git a/space/components/issues/board-views/list/block.tsx b/space/components/issues/board-views/list/block.tsx
new file mode 100644
index 000000000..bdf39b84f
--- /dev/null
+++ b/space/components/issues/board-views/list/block.tsx
@@ -0,0 +1,84 @@
+import { FC } from "react";
+import { useRouter } from "next/router";
+import { observer } from "mobx-react-lite";
+// components
+import { IssueBlockPriority } from "components/issues/board-views/block-priority";
+import { IssueBlockState } from "components/issues/board-views/block-state";
+import { IssueBlockLabels } from "components/issues/board-views/block-labels";
+import { IssueBlockDueDate } from "components/issues/board-views/block-due-date";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+// interfaces
+import { IIssue } from "types/issue";
+// store
+import { RootStore } from "store/root";
+
+export const IssueListBlock: FC<{ issue: IIssue }> = observer((props) => {
+ const { issue } = props;
+ // store
+ const { project: projectStore, issueDetails: issueDetailStore }: RootStore = useMobxStore();
+ // router
+ const router = useRouter();
+ const { workspace_slug, project_slug, board } = router.query;
+
+ const handleBlockClick = () => {
+ issueDetailStore.setPeekId(issue.id);
+ router.push(
+ {
+ pathname: `/${workspace_slug?.toString()}/${project_slug}`,
+ query: {
+ board: board?.toString(),
+ peekId: issue.id,
+ },
+ },
+ undefined,
+ { shallow: true }
+ );
+ // router.push(`/${workspace_slug?.toString()}/${project_slug}?board=${board?.toString()}&peekId=${issue.id}`);
+ };
+
+ return (
+
+
+ {/* id */}
+
+ {projectStore?.project?.identifier}-{issue?.sequence_id}
+
+ {/* name */}
+
+ {issue.name}
+
+
+
+
+ {/* priority */}
+ {issue?.priority && (
+
+
+
+ )}
+
+ {/* state */}
+ {issue?.state_detail && (
+
+
+
+ )}
+
+ {/* labels */}
+ {issue?.label_details && issue?.label_details.length > 0 && (
+
+
+
+ )}
+
+ {/* due date */}
+ {issue?.target_date && (
+
+
+
+ )}
+
+
+ );
+});
diff --git a/apps/space/components/issues/board-views/list/header.tsx b/space/components/issues/board-views/list/header.tsx
similarity index 50%
rename from apps/space/components/issues/board-views/list/header.tsx
rename to space/components/issues/board-views/list/header.tsx
index e87cac6f7..83312e7b9 100644
--- a/apps/space/components/issues/board-views/list/header.tsx
+++ b/space/components/issues/board-views/list/header.tsx
@@ -1,9 +1,9 @@
-"use client";
-
// mobx react lite
import { observer } from "mobx-react-lite";
// interfaces
-import { IIssueState } from "store/types/issue";
+import { IIssueState } from "types/issue";
+// icons
+import { StateGroupIcon } from "components/icons";
// constants
import { issueGroupFilter } from "constants/data";
// mobx hook
@@ -18,14 +18,12 @@ export const IssueListHeader = observer(({ state }: { state: IIssueState }) => {
if (stateGroup === null) return <>>;
return (
-
-
-
-
-
{state?.name}
-
- {store.issue.getCountOfIssuesByState(state.id)}
+
+
+
+
{state?.name}
+
{store.issue.getCountOfIssuesByState(state.id)}
);
});
diff --git a/space/components/issues/board-views/list/index.tsx b/space/components/issues/board-views/list/index.tsx
new file mode 100644
index 000000000..1c6900dd9
--- /dev/null
+++ b/space/components/issues/board-views/list/index.tsx
@@ -0,0 +1,38 @@
+import { observer } from "mobx-react-lite";
+// components
+import { IssueListHeader } from "components/issues/board-views/list/header";
+import { IssueListBlock } from "components/issues/board-views/list/block";
+// interfaces
+import { IIssueState, IIssue } from "types/issue";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+// store
+import { RootStore } from "store/root";
+
+export const IssueListView = observer(() => {
+ const { issue: issueStore }: RootStore = useMobxStore();
+
+ return (
+ <>
+ {issueStore?.states &&
+ issueStore?.states.length > 0 &&
+ issueStore?.states.map((_state: IIssueState) => (
+
+
+ {issueStore.getFilteredIssuesByState(_state.id) &&
+ issueStore.getFilteredIssuesByState(_state.id).length > 0 ? (
+
+ {issueStore.getFilteredIssuesByState(_state.id).map((_issue: IIssue) => (
+
+ ))}
+
+ ) : (
+
+ No Issues are available.
+
+ )}
+
+ ))}
+ >
+ );
+});
diff --git a/apps/space/components/issues/board-views/spreadsheet/index.tsx b/space/components/issues/board-views/spreadsheet/index.tsx
similarity index 100%
rename from apps/space/components/issues/board-views/spreadsheet/index.tsx
rename to space/components/issues/board-views/spreadsheet/index.tsx
diff --git a/space/components/issues/filters-render/index.tsx b/space/components/issues/filters-render/index.tsx
new file mode 100644
index 000000000..d797d1506
--- /dev/null
+++ b/space/components/issues/filters-render/index.tsx
@@ -0,0 +1,53 @@
+import { useRouter } from "next/router";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// components
+import IssueStateFilter from "./state";
+import IssueLabelFilter from "./label";
+import IssuePriorityFilter from "./priority";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+
+const IssueFilter = observer(() => {
+ const store: RootStore = useMobxStore();
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const clearAllFilters = () => {
+ // router.replace(
+ // store.issue.getURLDefinition(workspace_slug, project_slug, {
+ // key: "all",
+ // removeAll: true,
+ // })
+ // );
+ };
+
+ // if (store.issue.getIfFiltersIsEmpty()) return null;
+
+ return (
+
+
+ {/* state */}
+ {/* {store.issue.checkIfFilterExistsForKey("state") &&
} */}
+ {/* labels */}
+ {/* {store.issue.checkIfFilterExistsForKey("label") &&
} */}
+ {/* priority */}
+ {/* {store.issue.checkIfFilterExistsForKey("priority") &&
} */}
+ {/* clear all filters */}
+
+
Clear all filters
+
+ close
+
+
+
+
+ );
+});
+
+export default IssueFilter;
diff --git a/space/components/issues/filters-render/label/filter-label-block.tsx b/space/components/issues/filters-render/label/filter-label-block.tsx
new file mode 100644
index 000000000..a54fb65e4
--- /dev/null
+++ b/space/components/issues/filters-render/label/filter-label-block.tsx
@@ -0,0 +1,43 @@
+import { useRouter } from "next/router";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+// interfaces
+import { IIssueLabel } from "types/issue";
+
+export const RenderIssueLabel = observer(({ label }: { label: IIssueLabel }) => {
+ const store = useMobxStore();
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const removeLabelFromFilter = () => {
+ // router.replace(
+ // store.issue.getURLDefinition(workspace_slug, project_slug, {
+ // key: "label",
+ // value: label?.id,
+ // })
+ // );
+ };
+
+ return (
+
+
+
+
{label?.name}
+
+ close
+
+
+ );
+});
diff --git a/space/components/issues/filters-render/label/index.tsx b/space/components/issues/filters-render/label/index.tsx
new file mode 100644
index 000000000..1d9a4f990
--- /dev/null
+++ b/space/components/issues/filters-render/label/index.tsx
@@ -0,0 +1,51 @@
+import { useRouter } from "next/router";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// components
+import { RenderIssueLabel } from "./filter-label-block";
+// interfaces
+import { IIssueLabel } from "types/issue";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+
+const IssueLabelFilter = observer(() => {
+ const store: RootStore = useMobxStore();
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const clearLabelFilters = () => {
+ // router.replace(
+ // store.issue.getURLDefinition(workspace_slug, project_slug, {
+ // key: "label",
+ // removeAll: true,
+ // })
+ // );
+ };
+
+ return (
+ <>
+
+
Labels
+
+ {/* {store?.issue?.labels &&
+ store?.issue?.labels.map(
+ (_label: IIssueLabel, _index: number) =>
+ store.issue.getUserSelectedFilter("label", _label.id) && (
+
+ )
+ )} */}
+
+
+ close
+
+
+ >
+ );
+});
+
+export default IssueLabelFilter;
diff --git a/space/components/issues/filters-render/priority/filter-priority-block.tsx b/space/components/issues/filters-render/priority/filter-priority-block.tsx
new file mode 100644
index 000000000..5fd1ef1a7
--- /dev/null
+++ b/space/components/issues/filters-render/priority/filter-priority-block.tsx
@@ -0,0 +1,42 @@
+import { useRouter } from "next/router";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+// interfaces
+import { IIssuePriorityFilters } from "types/issue";
+
+export const RenderIssuePriority = observer(({ priority }: { priority: IIssuePriorityFilters }) => {
+ const store = useMobxStore();
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const removePriorityFromFilter = () => {
+ // router.replace(
+ // store.issue.getURLDefinition(workspace_slug, project_slug, {
+ // key: "priority",
+ // value: priority?.key,
+ // })
+ // );
+ };
+
+ return (
+
+
+ {priority?.icon}
+
+
{priority?.title}
+
+ close
+
+
+ );
+});
diff --git a/space/components/issues/filters-render/priority/index.tsx b/space/components/issues/filters-render/priority/index.tsx
new file mode 100644
index 000000000..100ba1761
--- /dev/null
+++ b/space/components/issues/filters-render/priority/index.tsx
@@ -0,0 +1,53 @@
+import { useRouter } from "next/router";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+// components
+import { RenderIssuePriority } from "./filter-priority-block";
+// interfaces
+import { IIssuePriorityFilters } from "types/issue";
+// constants
+import { issuePriorityFilters } from "constants/data";
+
+const IssuePriorityFilter = observer(() => {
+ const store = useMobxStore();
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const clearPriorityFilters = () => {
+ // router.replace(
+ // store.issue.getURLDefinition(workspace_slug, project_slug, {
+ // key: "priority",
+ // removeAll: true,
+ // })
+ // );
+ };
+
+ return (
+ <>
+
+
Priority
+
+ {/* {issuePriorityFilters.map(
+ (_priority: IIssuePriorityFilters, _index: number) =>
+ store.issue.getUserSelectedFilter("priority", _priority.key) && (
+
+ )
+ )} */}
+
+
{
+ clearPriorityFilters();
+ }}
+ >
+ close
+
+
+ >
+ );
+});
+
+export default IssuePriorityFilter;
diff --git a/space/components/issues/filters-render/state/filter-state-block.tsx b/space/components/issues/filters-render/state/filter-state-block.tsx
new file mode 100644
index 000000000..8445386a4
--- /dev/null
+++ b/space/components/issues/filters-render/state/filter-state-block.tsx
@@ -0,0 +1,43 @@
+import { useRouter } from "next/router";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+// interfaces
+import { IIssueState } from "types/issue";
+// constants
+import { issueGroupFilter } from "constants/data";
+
+export const RenderIssueState = observer(({ state }: { state: IIssueState }) => {
+ const store = useMobxStore();
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const stateGroup = issueGroupFilter(state.group);
+
+ const removeStateFromFilter = () => {
+ // router.replace(
+ // store.issue.getURLDefinition(workspace_slug, project_slug, {
+ // key: "state",
+ // value: state?.id,
+ // })
+ // );
+ };
+
+ if (stateGroup === null) return <>>;
+ return (
+
+
+
+
+
{state?.name}
+
+ close
+
+
+ );
+});
diff --git a/space/components/issues/filters-render/state/index.tsx b/space/components/issues/filters-render/state/index.tsx
new file mode 100644
index 000000000..0198c5215
--- /dev/null
+++ b/space/components/issues/filters-render/state/index.tsx
@@ -0,0 +1,51 @@
+import { useRouter } from "next/router";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// components
+import { RenderIssueState } from "./filter-state-block";
+// interfaces
+import { IIssueState } from "types/issue";
+// mobx hook
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+
+const IssueStateFilter = observer(() => {
+ const store: RootStore = useMobxStore();
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const clearStateFilters = () => {
+ // router.replace(
+ // store.issue.getURLDefinition(workspace_slug, project_slug, {
+ // key: "state",
+ // removeAll: true,
+ // })
+ // );
+ };
+
+ return (
+ <>
+
+
State
+
+ {/* {store?.issue?.states &&
+ store?.issue?.states.map(
+ (_state: IIssueState, _index: number) =>
+ store.issue.getUserSelectedFilter("state", _state.id) && (
+
+ )
+ )} */}
+
+
+ close
+
+
+ >
+ );
+});
+
+export default IssueStateFilter;
diff --git a/space/components/issues/navbar/index.tsx b/space/components/issues/navbar/index.tsx
new file mode 100644
index 000000000..509d676b7
--- /dev/null
+++ b/space/components/issues/navbar/index.tsx
@@ -0,0 +1,121 @@
+import { useEffect } from "react";
+
+import Link from "next/link";
+import Image from "next/image";
+import { useRouter } from "next/router";
+
+// mobx
+import { observer } from "mobx-react-lite";
+// components
+import { NavbarSearch } from "./search";
+import { NavbarIssueBoardView } from "./issue-board-view";
+import { NavbarTheme } from "./theme";
+// ui
+import { PrimaryButton } from "components/ui";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+// store
+import { RootStore } from "store/root";
+
+const renderEmoji = (emoji: string | { name: string; color: string }) => {
+ if (!emoji) return;
+
+ if (typeof emoji === "object")
+ return (
+
+ {emoji.name}
+
+ );
+ else return isNaN(parseInt(emoji)) ? emoji : String.fromCodePoint(parseInt(emoji));
+};
+
+const IssueNavbar = observer(() => {
+ const { project: projectStore, user: userStore }: RootStore = useMobxStore();
+ // router
+ const router = useRouter();
+ const { workspace_slug, project_slug, board } = router.query;
+
+ const user = userStore?.currentUser;
+
+ useEffect(() => {
+ if (workspace_slug && project_slug) {
+ projectStore.fetchProjectSettings(workspace_slug.toString(), project_slug.toString());
+ }
+ }, [projectStore, workspace_slug, project_slug]);
+
+ useEffect(() => {
+ if (workspace_slug && project_slug) {
+ if (!board) {
+ router.push({
+ pathname: `/${workspace_slug}/${project_slug}`,
+ query: {
+ board: "list",
+ },
+ });
+ return projectStore.setActiveBoard("list");
+ }
+ projectStore.setActiveBoard(board.toString());
+ }
+ }, [board, workspace_slug, project_slug]);
+
+ return (
+
+ {/* project detail */}
+
+
+ {projectStore?.project && projectStore?.project?.emoji ? (
+ renderEmoji(projectStore?.project?.emoji)
+ ) : (
+
+ )}
+
+
+ {projectStore?.project?.name || `...`}
+
+
+
+ {/* issue search bar */}
+
+
+
+
+ {/* issue views */}
+
+
+
+
+ {/* theming */}
+
+
+
+
+ {user ? (
+
+ {user.avatar && user.avatar !== "" ? (
+
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+
+
+ ) : (
+
+ {(user.display_name ?? "A")[0]}
+
+ )}
+
{user.display_name}
+
+ ) : (
+
+ )}
+
+ );
+});
+
+export default IssueNavbar;
diff --git a/space/components/issues/navbar/issue-board-view.tsx b/space/components/issues/navbar/issue-board-view.tsx
new file mode 100644
index 000000000..0ae71e8ee
--- /dev/null
+++ b/space/components/issues/navbar/issue-board-view.tsx
@@ -0,0 +1,49 @@
+import { useRouter } from "next/router";
+import { observer } from "mobx-react-lite";
+// constants
+import { issueViews } from "constants/data";
+// mobx
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+
+export const NavbarIssueBoardView = observer(() => {
+ const { project: projectStore, issue: issueStore }: RootStore = useMobxStore();
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const handleCurrentBoardView = (boardView: string) => {
+ projectStore.setActiveBoard(boardView);
+ router.push(`/${workspace_slug}/${project_slug}?board=${boardView}`);
+ };
+
+ return (
+ <>
+ {projectStore?.viewOptions &&
+ Object.keys(projectStore?.viewOptions).map((viewKey: string) => {
+ if (projectStore?.viewOptions[viewKey]) {
+ return (
+
handleCurrentBoardView(viewKey)}
+ title={viewKey}
+ >
+
+ {issueViews[viewKey]?.icon}
+
+
+ );
+ }
+ })}
+ >
+ );
+});
diff --git a/space/components/issues/navbar/issue-filter.tsx b/space/components/issues/navbar/issue-filter.tsx
new file mode 100644
index 000000000..852121a5e
--- /dev/null
+++ b/space/components/issues/navbar/issue-filter.tsx
@@ -0,0 +1,111 @@
+import { useRouter } from "next/router";
+import { observer } from "mobx-react-lite";
+// icons
+import { ChevronDownIcon } from "@heroicons/react/20/solid";
+// mobx
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+// components
+import { Dropdown } from "components/ui/dropdown";
+// constants
+import { issueGroupFilter } from "constants/data";
+
+const PRIORITIES = ["urgent", "high", "medium", "low"];
+
+export const NavbarIssueFilter = observer(() => {
+ const store: RootStore = useMobxStore();
+
+ const router = useRouter();
+ const pathName = router.asPath;
+
+ const handleOnSelect = (key: "states" | "labels" | "priorities", value: string) => {
+ // if (key === "states") {
+ // store.issue.userSelectedStates = store.issue.userSelectedStates.includes(value)
+ // ? store.issue.userSelectedStates.filter((s) => s !== value)
+ // : [...store.issue.userSelectedStates, value];
+ // } else if (key === "labels") {
+ // store.issue.userSelectedLabels = store.issue.userSelectedLabels.includes(value)
+ // ? store.issue.userSelectedLabels.filter((l) => l !== value)
+ // : [...store.issue.userSelectedLabels, value];
+ // } else if (key === "priorities") {
+ // store.issue.userSelectedPriorities = store.issue.userSelectedPriorities.includes(value)
+ // ? store.issue.userSelectedPriorities.filter((p) => p !== value)
+ // : [...store.issue.userSelectedPriorities, value];
+ // }
+ // const paramsCommaSeparated = `${`board=${store.issue.currentIssueBoardView || "list"}`}${
+ // store.issue.userSelectedPriorities.length > 0 ? `&priorities=${store.issue.userSelectedPriorities.join(",")}` : ""
+ // }${store.issue.userSelectedStates.length > 0 ? `&states=${store.issue.userSelectedStates.join(",")}` : ""}${
+ // store.issue.userSelectedLabels.length > 0 ? `&labels=${store.issue.userSelectedLabels.join(",")}` : ""
+ // }`;
+ // router.replace(`${pathName}?${paramsCommaSeparated}`);
+ };
+
+ return (
+
+ Filters
+
+ >
+ }
+ items={[
+ {
+ display: "Priority",
+ children: PRIORITIES.map((priority) => ({
+ display: (
+
+
+ {priority === "urgent"
+ ? "error"
+ : priority === "high"
+ ? "signal_cellular_alt"
+ : priority === "medium"
+ ? "signal_cellular_alt_2_bar"
+ : "signal_cellular_alt_1_bar"}
+
+ {priority}
+
+ ),
+ onClick: () => handleOnSelect("priorities", priority),
+ isSelected: store.issue.filteredPriorities.includes(priority),
+ })),
+ },
+ {
+ display: "State",
+ children: (store.issue.states || []).map((state) => {
+ const stateGroup = issueGroupFilter(state.group);
+
+ return {
+ display: (
+
+ {stateGroup && }
+ {state.name}
+
+ ),
+ onClick: () => handleOnSelect("states", state.id),
+ isSelected: store.issue.filteredStates.includes(state.id),
+ };
+ }),
+ },
+ {
+ display: "Labels",
+ children: [...(store.issue.labels || [])].map((label) => ({
+ display: (
+
+
+ {label.name}
+
+ ),
+ onClick: () => handleOnSelect("labels", label.id),
+ isSelected: store.issue.filteredLabels.includes(label.id),
+ })),
+ },
+ ]}
+ />
+ );
+});
diff --git a/apps/space/components/issues/navbar/issue-view.tsx b/space/components/issues/navbar/issue-view.tsx
similarity index 100%
rename from apps/space/components/issues/navbar/issue-view.tsx
rename to space/components/issues/navbar/issue-view.tsx
diff --git a/apps/space/components/issues/navbar/search.tsx b/space/components/issues/navbar/search.tsx
similarity index 100%
rename from apps/space/components/issues/navbar/search.tsx
rename to space/components/issues/navbar/search.tsx
diff --git a/space/components/issues/navbar/theme.tsx b/space/components/issues/navbar/theme.tsx
new file mode 100644
index 000000000..7efb561a4
--- /dev/null
+++ b/space/components/issues/navbar/theme.tsx
@@ -0,0 +1,32 @@
+// next theme
+import { useTheme } from "next-themes";
+
+// mobx react lite
+import { observer } from "mobx-react-lite";
+import { useEffect, useState } from "react";
+
+export const NavbarTheme = observer(() => {
+ const [appTheme, setAppTheme] = useState("light");
+
+ const { setTheme, theme } = useTheme();
+
+ const handleTheme = () => {
+ setTheme(theme === "light" ? "dark" : "light");
+ };
+
+ useEffect(() => {
+ if (!theme) return;
+
+ setAppTheme(theme);
+ }, [theme]);
+
+ return (
+
+ {appTheme === "light" ? "dark_mode" : "light_mode"}
+
+ );
+});
diff --git a/space/components/issues/peek-overview/add-comment.tsx b/space/components/issues/peek-overview/add-comment.tsx
new file mode 100644
index 000000000..3ea4308d7
--- /dev/null
+++ b/space/components/issues/peek-overview/add-comment.tsx
@@ -0,0 +1,104 @@
+import React, { useRef } from "react";
+import { useRouter } from "next/router";
+import { observer } from "mobx-react-lite";
+import { useForm, Controller } from "react-hook-form";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+// hooks
+import useToast from "hooks/use-toast";
+// ui
+import { SecondaryButton } from "components/ui";
+// types
+import { Comment } from "types/issue";
+// components
+import { TipTapEditor } from "components/tiptap";
+
+const defaultValues: Partial = {
+ comment_html: "",
+};
+
+type Props = {
+ disabled?: boolean;
+};
+
+export const AddComment: React.FC = observer((props) => {
+ const { disabled = false } = props;
+
+ const {
+ handleSubmit,
+ control,
+ setValue,
+ watch,
+ formState: { isSubmitting },
+ reset,
+ } = useForm({ defaultValues });
+
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
+
+ const { user: userStore, issueDetails: issueDetailStore } = useMobxStore();
+
+ const issueId = issueDetailStore.peekId;
+
+ const editorRef = useRef(null);
+
+ const { setToastAlert } = useToast();
+
+ const onSubmit = async (formData: Comment) => {
+ if (!workspace_slug || !project_slug || !issueId || isSubmitting || !formData.comment_html) return;
+
+ await issueDetailStore
+ .addIssueComment(workspace_slug, project_slug, issueId, formData)
+ .then(() => {
+ reset(defaultValues);
+ editorRef.current?.clearEditor();
+ })
+ .catch(() => {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Comment could not be posted. Please try again.",
+ });
+ });
+ };
+
+ return (
+
+
+ (
+ {
+ onChange(comment_html);
+ }}
+ />
+ )}
+ />
+
+ {
+ userStore.requiredLogin(() => {
+ handleSubmit(onSubmit)(e);
+ });
+ }}
+ type="submit"
+ disabled={isSubmitting || disabled}
+ className="mt-2"
+ >
+ {isSubmitting ? "Adding..." : "Comment"}
+
+
+
+ );
+});
diff --git a/space/components/issues/peek-overview/comment-detail-card.tsx b/space/components/issues/peek-overview/comment-detail-card.tsx
new file mode 100644
index 000000000..a43942f4c
--- /dev/null
+++ b/space/components/issues/peek-overview/comment-detail-card.tsx
@@ -0,0 +1,190 @@
+import React, { useEffect, useState, useRef } from "react";
+import { useForm, Controller } from "react-hook-form";
+import { observer } from "mobx-react-lite";
+import { Menu, Transition } from "@headlessui/react";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+// icons
+import { ChatBubbleLeftEllipsisIcon, CheckIcon, XMarkIcon, EllipsisVerticalIcon } from "@heroicons/react/24/outline";
+// helpers
+import { timeAgo } from "helpers/date-time.helper";
+// types
+import { Comment } from "types/issue";
+// components
+import { TipTapEditor } from "components/tiptap";
+
+type Props = {
+ workspaceSlug: string;
+ comment: Comment;
+};
+
+export const CommentCard: React.FC = observer((props) => {
+ const { comment, workspaceSlug } = props;
+ // store
+ const { user: userStore, issueDetails: issueDetailStore } = useMobxStore();
+ // states
+ const [isEditing, setIsEditing] = useState(false);
+
+ const {
+ formState: { isSubmitting },
+ handleSubmit,
+ control,
+ } = useForm({
+ defaultValues: { comment_html: comment.comment_html },
+ });
+
+ const handleDelete = () => {
+ if (!workspaceSlug || !issueDetailStore.peekId) return;
+ issueDetailStore.deleteIssueComment(workspaceSlug, comment.project, issueDetailStore.peekId, comment.id);
+ };
+
+ const handleCommentUpdate = async (formData: Comment) => {
+ if (!workspaceSlug || !issueDetailStore.peekId) return;
+ issueDetailStore.updateIssueComment(workspaceSlug, comment.project, issueDetailStore.peekId, comment.id, formData);
+ setIsEditing(false);
+ };
+
+ return (
+
+
+ {comment.actor_detail.avatar && comment.actor_detail.avatar !== "" ? (
+ // eslint-disable-next-line @next/next/no-img-element
+
+ ) : (
+
+ {comment.actor_detail.is_bot
+ ? comment?.actor_detail?.first_name?.charAt(0)
+ : comment?.actor_detail?.display_name?.charAt(0)}
+
+ )}
+
+
+
+
+
+
+
+
+ {comment.actor_detail.is_bot ? comment.actor_detail.first_name + " Bot" : comment.actor_detail.display_name}
+
+
+ <>Commented {timeAgo(comment.created_at)}>
+
+
+
+
+
+ {userStore?.currentUser?.id === comment?.actor_detail?.id && (
+
+ {}}
+ className="relative grid place-items-center rounded p-1 text-custom-text-200 hover:text-custom-text-100 outline-none cursor-pointer hover:bg-custom-background-80"
+ >
+
+
+
+
+
+
+ {({ active }) => (
+
+ {
+ setIsEditing(true);
+ }}
+ className={`w-full select-none truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80 ${
+ active ? "bg-custom-background-80" : ""
+ }`}
+ >
+ Edit
+
+
+ )}
+
+
+ {({ active }) => (
+
+
+ Delete
+
+
+ )}
+
+
+
+
+ )}
+
+ );
+});
diff --git a/space/components/issues/peek-overview/full-screen-peek-view.tsx b/space/components/issues/peek-overview/full-screen-peek-view.tsx
new file mode 100644
index 000000000..a40e6b16a
--- /dev/null
+++ b/space/components/issues/peek-overview/full-screen-peek-view.tsx
@@ -0,0 +1,71 @@
+import { useEffect } from "react";
+import { observer } from "mobx-react-lite";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+// components
+import {
+ PeekOverviewHeader,
+ PeekOverviewIssueActivity,
+ PeekOverviewIssueDetails,
+ PeekOverviewIssueProperties,
+} from "components/issues/peek-overview";
+// types
+import { Loader } from "components/ui/loader";
+import { IIssue } from "types/issue";
+
+type Props = {
+ handleClose: () => void;
+ issueDetails: IIssue | undefined;
+};
+
+export const FullScreenPeekView: React.FC = observer((props) => {
+ const { handleClose, issueDetails } = props;
+
+ return (
+
+
+
+ {issueDetails ? (
+
+ {/* issue title and description */}
+
+ {/* divider */}
+
+ {/* issue activity/comments */}
+
+
+ ) : (
+
+
+
+
+
+
+
+
+ )}
+
+
+ {/* issue properties */}
+
+ {issueDetails ? (
+
+ ) : (
+
+
+
+
+
+
+ )}
+
+
+
+ );
+});
diff --git a/space/components/issues/peek-overview/header.tsx b/space/components/issues/peek-overview/header.tsx
new file mode 100644
index 000000000..2aa43ff47
--- /dev/null
+++ b/space/components/issues/peek-overview/header.tsx
@@ -0,0 +1,140 @@
+import React from "react";
+
+// headless ui
+import { Listbox, Transition } from "@headlessui/react";
+// hooks
+import useToast from "hooks/use-toast";
+// ui
+import { Icon } from "components/ui";
+// icons
+import { East } from "@mui/icons-material";
+// helpers
+import { copyTextToClipboard } from "helpers/string.helper";
+// store
+import { IPeekMode } from "store/issue_details";
+import { RootStore } from "store/root";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+// types
+import { IIssue } from "types/issue";
+
+type Props = {
+ handleClose: () => void;
+ issueDetails: IIssue | undefined;
+};
+
+const peekModes: {
+ key: IPeekMode;
+ icon: string;
+ label: string;
+}[] = [
+ { key: "side", icon: "side_navigation", label: "Side Peek" },
+ {
+ key: "modal",
+ icon: "dialogs",
+ label: "Modal Peek",
+ },
+ {
+ key: "full",
+ icon: "nearby",
+ label: "Full Screen Peek",
+ },
+];
+
+export const PeekOverviewHeader: React.FC = (props) => {
+ const { handleClose, issueDetails } = props;
+
+ const { issueDetails: issueDetailStore }: RootStore = useMobxStore();
+
+ const { setToastAlert } = useToast();
+
+ const handleCopyLink = () => {
+ const urlToCopy = window.location.href;
+
+ copyTextToClipboard(urlToCopy).then(() => {
+ setToastAlert({
+ type: "success",
+ title: "Link copied!",
+ message: "Issue link copied to clipboard",
+ });
+ });
+ };
+
+ return (
+ <>
+
+
+ {issueDetailStore.peekMode === "side" && (
+
+
+
+ )}
+
issueDetailStore.setPeekMode(val)}
+ className="relative flex-shrink-0 text-left"
+ >
+
+ m.key === issueDetailStore.peekMode)?.icon ?? ""} />
+
+
+
+
+
+ {peekModes.map((mode) => (
+
+ `cursor-pointer select-none truncate rounded px-1 py-1.5 ${
+ active || selected ? "bg-custom-background-80" : ""
+ } ${selected ? "text-custom-text-100" : "text-custom-text-200"}`
+ }
+ >
+ {({ selected }) => (
+
+ )}
+
+ ))}
+
+
+
+
+
+ {(issueDetailStore.peekMode === "side" || issueDetailStore.peekMode === "modal") && (
+
+
+
+
+
+ )}
+
+ >
+ );
+};
diff --git a/space/components/issues/peek-overview/index.ts b/space/components/issues/peek-overview/index.ts
new file mode 100644
index 000000000..44ab04b88
--- /dev/null
+++ b/space/components/issues/peek-overview/index.ts
@@ -0,0 +1,12 @@
+export * from "./full-screen-peek-view";
+export * from "./header";
+export * from "./issue-activity";
+export * from "./issue-details";
+export * from "./issue-properties";
+export * from "./layout";
+export * from "./side-peek-view";
+export * from "./issue-reaction";
+export * from "./issue-vote-reactions";
+export * from "./issue-emoji-reactions";
+export * from "./comment-detail-card";
+export * from "./add-comment";
diff --git a/space/components/issues/peek-overview/issue-activity.tsx b/space/components/issues/peek-overview/issue-activity.tsx
new file mode 100644
index 000000000..fde2fd878
--- /dev/null
+++ b/space/components/issues/peek-overview/issue-activity.tsx
@@ -0,0 +1,66 @@
+import React from "react";
+
+import Link from "next/link";
+import { useRouter } from "next/router";
+
+// mobx
+import { observer } from "mobx-react-lite";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+// components
+import { CommentCard, AddComment } from "components/issues/peek-overview";
+// ui
+import { Icon, PrimaryButton } from "components/ui";
+// types
+import { IIssue } from "types/issue";
+
+type Props = {
+ issueDetails: IIssue;
+};
+
+export const PeekOverviewIssueActivity: React.FC = observer((props) => {
+ const router = useRouter();
+ const { workspace_slug } = router.query;
+
+ const { issueDetails: issueDetailStore, project: projectStore, user: userStore } = useMobxStore();
+
+ const comments = issueDetailStore.details[issueDetailStore.peekId || ""]?.comments || [];
+
+ const user = userStore?.currentUser;
+
+ return (
+
+
Activity
+ {workspace_slug && (
+
+
+ {comments.map((comment: any) => (
+
+ ))}
+
+ {user ? (
+ <>
+ {projectStore.deploySettings?.comments && (
+
+ )}
+ >
+ ) : (
+
+
+
+ Sign in to add your comment
+
+
+
+ Sign in
+
+
+
+ )}
+
+ )}
+
+ );
+});
diff --git a/space/components/issues/peek-overview/issue-details.tsx b/space/components/issues/peek-overview/issue-details.tsx
new file mode 100644
index 000000000..0b329568c
--- /dev/null
+++ b/space/components/issues/peek-overview/issue-details.tsx
@@ -0,0 +1,40 @@
+import { IssueReactions } from "components/issues/peek-overview";
+import { TipTapEditor } from "components/tiptap";
+import { useRouter } from "next/router";
+// types
+import { IIssue } from "types/issue";
+
+type Props = {
+ issueDetails: IIssue;
+};
+
+export const PeekOverviewIssueDetails: React.FC = ({ issueDetails }) => {
+ const router = useRouter();
+ const { workspace_slug } = router.query;
+
+ return (
+
+
+ {issueDetails.project_detail.identifier}-{issueDetails.sequence_id}
+
+
{issueDetails.name}
+ {issueDetails.description_html !== "" && issueDetails.description_html !== "
" && (
+
"
+ : issueDetails.description_html
+ }
+ customClassName="p-3 min-h-[50px] shadow-sm"
+ debouncedUpdatesEnabled={false}
+ editable={false}
+ />
+ )}
+
+
+ );
+};
diff --git a/space/components/issues/peek-overview/issue-emoji-reactions.tsx b/space/components/issues/peek-overview/issue-emoji-reactions.tsx
new file mode 100644
index 000000000..3d2bfadac
--- /dev/null
+++ b/space/components/issues/peek-overview/issue-emoji-reactions.tsx
@@ -0,0 +1,99 @@
+import { useEffect } from "react";
+import { useRouter } from "next/router";
+import { observer } from "mobx-react-lite";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+// helpers
+import { groupReactions, renderEmoji } from "helpers/emoji.helper";
+// components
+import { ReactionSelector, Tooltip } from "components/ui";
+
+export const IssueEmojiReactions: React.FC = observer(() => {
+ // router
+ const router = useRouter();
+ const { workspace_slug, project_slug } = router.query;
+ // store
+ const { user: userStore, issueDetails: issueDetailsStore } = useMobxStore();
+
+ const user = userStore?.currentUser;
+ const issueId = issueDetailsStore.peekId;
+ const reactions = issueId ? issueDetailsStore.details[issueId]?.reactions || [] : [];
+ const groupedReactions = groupReactions(reactions, "reaction");
+
+ const handleReactionSelectClick = (reactionHex: string) => {
+ if (!workspace_slug || !project_slug || !issueId) return;
+ const userReaction = reactions?.find((r) => r.actor_detail.id === user?.id && r.reaction === reactionHex);
+ if (userReaction) return;
+ issueDetailsStore.addIssueReaction(workspace_slug.toString(), project_slug.toString(), issueId, reactionHex);
+ };
+
+ const handleReactionClick = (reactionHex: string) => {
+ if (!workspace_slug || !project_slug || !issueId) return;
+ issueDetailsStore.removeIssueReaction(workspace_slug.toString(), project_slug.toString(), issueId, reactionHex);
+ };
+
+ useEffect(() => {
+ if (user) return;
+ userStore.fetchCurrentUser();
+ }, [user, userStore]);
+
+ return (
+ <>
+ {
+ userStore.requiredLogin(() => {
+ handleReactionSelectClick(value);
+ });
+ }}
+ size="md"
+ />
+
+ {Object.keys(groupedReactions || {}).map((reaction) => {
+ const reactions = groupedReactions?.[reaction] ?? [];
+ const REACTIONS_LIMIT = 1000;
+
+ if (reactions.length > 0)
+ return (
+
+ {reactions
+ .map((r) => r.actor_detail.display_name)
+ .splice(0, REACTIONS_LIMIT)
+ .join(", ")}
+ {reactions.length > REACTIONS_LIMIT && " and " + (reactions.length - REACTIONS_LIMIT) + " more"}
+
+ }
+ >
+ {
+ userStore.requiredLogin(() => {
+ handleReactionClick(reaction);
+ });
+ }}
+ className={`flex items-center gap-1 text-custom-text-100 text-sm h-full px-2 py-1 rounded-md ${
+ reactions?.some((r) => r.actor_detail.id === user?.id && r.reaction === reaction)
+ ? "bg-custom-primary-100/10"
+ : "bg-custom-background-80"
+ }`}
+ >
+ {renderEmoji(reaction)}
+ r.actor_detail.id === user?.id && r.reaction === reaction)
+ ? "text-custom-primary-100"
+ : ""
+ }
+ >
+ {groupedReactions?.[reaction].length}{" "}
+
+
+
+ );
+ })}
+
+ >
+ );
+});
diff --git a/space/components/issues/peek-overview/issue-properties.tsx b/space/components/issues/peek-overview/issue-properties.tsx
new file mode 100644
index 000000000..6b3394b56
--- /dev/null
+++ b/space/components/issues/peek-overview/issue-properties.tsx
@@ -0,0 +1,142 @@
+// hooks
+import useToast from "hooks/use-toast";
+// icons
+import { Icon } from "components/ui";
+import { copyTextToClipboard, addSpaceIfCamelCase } from "helpers/string.helper";
+// helpers
+import { renderDateFormat } from "constants/helpers";
+// types
+import { IIssue } from "types/issue";
+import { IPeekMode } from "store/issue_details";
+// constants
+import { issueGroupFilter, issuePriorityFilter } from "constants/data";
+
+type Props = {
+ issueDetails: IIssue;
+ mode?: IPeekMode;
+};
+
+const validDate = (date: any, state: string): string => {
+ if (date === null || ["backlog", "unstarted", "cancelled"].includes(state))
+ return `bg-gray-500/10 text-gray-500 border-gray-500/50`;
+ else {
+ const today = new Date();
+ const dueDate = new Date(date);
+
+ if (dueDate < today) return `bg-red-500/10 text-red-500 border-red-500/50`;
+ else return `bg-green-500/10 text-green-500 border-green-500/50`;
+ }
+};
+
+export const PeekOverviewIssueProperties: React.FC
= ({ issueDetails, mode }) => {
+ const { setToastAlert } = useToast();
+
+ const startDate = issueDetails.start_date;
+ const targetDate = issueDetails.target_date;
+
+ const minDate = startDate ? new Date(startDate) : null;
+ minDate?.setDate(minDate.getDate());
+
+ const maxDate = targetDate ? new Date(targetDate) : null;
+ maxDate?.setDate(maxDate.getDate());
+
+ const state = issueDetails.state_detail;
+ const stateGroup = issueGroupFilter(state.group);
+
+ const priority = issueDetails.priority ? issuePriorityFilter(issueDetails.priority) : null;
+
+ const handleCopyLink = () => {
+ const urlToCopy = window.location.href;
+
+ copyTextToClipboard(urlToCopy).then(() => {
+ setToastAlert({
+ type: "success",
+ title: "Link copied!",
+ message: "Issue link copied to clipboard",
+ });
+ });
+ };
+
+ return (
+
+ {mode === "full" && (
+
+
+ {/* {getStateGroupIcon(issue.state_detail.group, "16", "16", issue.state_detail.color)} */}
+ {issueDetails.project_detail.identifier}-{issueDetails.sequence_id}
+
+
+
+
+
+
+
+ )}
+
+
+
+
+ State
+
+
+ {stateGroup && (
+
+
+
+ {addSpaceIfCamelCase(state?.name ?? "")}
+
+
+ )}
+
+
+
+
+
+
+ Priority
+
+
+
+ {priority && (
+
+
+
+ )}
+ {priority?.title ?? "None"}
+
+
+
+
+
+
+ Due date
+
+
+ {issueDetails.target_date ? (
+
+ {renderDateFormat(issueDetails.target_date)}
+
+ ) : (
+
Empty
+ )}
+
+
+
+
+ );
+};
diff --git a/space/components/issues/peek-overview/issue-reaction.tsx b/space/components/issues/peek-overview/issue-reaction.tsx
new file mode 100644
index 000000000..643ec7119
--- /dev/null
+++ b/space/components/issues/peek-overview/issue-reaction.tsx
@@ -0,0 +1,24 @@
+import { IssueEmojiReactions, IssueVotes } from "components/issues/peek-overview";
+import { useMobxStore } from "lib/mobx/store-provider";
+
+export const IssueReactions: React.FC = () => {
+ const { project: projectStore } = useMobxStore();
+
+ return (
+
+ {projectStore?.deploySettings?.votes && (
+ <>
+
+
+
+
+ >
+ )}
+ {projectStore?.deploySettings?.reactions && (
+
+
+
+ )}
+
+ );
+};
diff --git a/space/components/issues/peek-overview/issue-vote-reactions.tsx b/space/components/issues/peek-overview/issue-vote-reactions.tsx
new file mode 100644
index 000000000..ac20565ea
--- /dev/null
+++ b/space/components/issues/peek-overview/issue-vote-reactions.tsx
@@ -0,0 +1,129 @@
+import { useState, useEffect } from "react";
+
+import { useRouter } from "next/router";
+
+// mobx
+import { observer } from "mobx-react-lite";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+import { Tooltip } from "components/ui";
+
+export const IssueVotes: React.FC = observer(() => {
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ const router = useRouter();
+
+ const { workspace_slug, project_slug } = router.query;
+
+ const { user: userStore, issueDetails: issueDetailsStore } = useMobxStore();
+
+ const user = userStore?.currentUser;
+ const issueId = issueDetailsStore.peekId;
+
+ const votes = issueId ? issueDetailsStore.details[issueId]?.votes : [];
+
+ const allUpVotes = votes?.filter((vote) => vote.vote === 1);
+ const allDownVotes = votes?.filter((vote) => vote.vote === -1);
+
+ const isUpVotedByUser = allUpVotes?.some((vote) => vote.actor === user?.id);
+ const isDownVotedByUser = allDownVotes?.some((vote) => vote.actor === user?.id);
+
+ const handleVote = async (e: any, voteValue: 1 | -1) => {
+ if (!workspace_slug || !project_slug || !issueId) return;
+
+ setIsSubmitting(true);
+
+ const actionPerformed = votes?.find((vote) => vote.actor === user?.id && vote.vote === voteValue);
+
+ if (actionPerformed)
+ await issueDetailsStore.removeIssueVote(workspace_slug.toString(), project_slug.toString(), issueId);
+ else
+ await issueDetailsStore.addIssueVote(workspace_slug.toString(), project_slug.toString(), issueId, {
+ vote: voteValue,
+ });
+
+ setIsSubmitting(false);
+ };
+
+ useEffect(() => {
+ if (user) return;
+
+ userStore.fetchCurrentUser();
+ }, [user, userStore]);
+
+ const VOTES_LIMIT = 1000;
+
+ return (
+
+ {/* upvote button 👇 */}
+
+ {allUpVotes.length > 0 ? (
+ <>
+ {allUpVotes
+ .map((r) => r.actor_detail.display_name)
+ .splice(0, VOTES_LIMIT)
+ .join(", ")}
+ {allUpVotes.length > VOTES_LIMIT && " and " + (allUpVotes.length - VOTES_LIMIT) + " more"}
+ >
+ ) : (
+ "No upvotes yet"
+ )}
+
+ }
+ >
+ {
+ userStore.requiredLogin(() => {
+ handleVote(e, 1);
+ });
+ }}
+ className={`flex items-center justify-center overflow-hidden px-2 gap-x-1 border rounded focus:outline-none ${
+ isUpVotedByUser ? "border-custom-primary-200 text-custom-primary-200" : "border-custom-border-300"
+ }`}
+ >
+ arrow_upward_alt
+ {allUpVotes.length}
+
+
+
+ {/* downvote button 👇 */}
+
+ {allDownVotes.length > 0 ? (
+ <>
+ {allDownVotes
+ .map((r) => r.actor_detail.display_name)
+ .splice(0, VOTES_LIMIT)
+ .join(", ")}
+ {allDownVotes.length > VOTES_LIMIT && " and " + (allDownVotes.length - VOTES_LIMIT) + " more"}
+ >
+ ) : (
+ "No downvotes yet"
+ )}
+
+ }
+ >
+
{
+ userStore.requiredLogin(() => {
+ handleVote(e, -1);
+ });
+ }}
+ className={`flex items-center justify-center overflow-hidden px-2 gap-x-1 border rounded focus:outline-none ${
+ isDownVotedByUser ? "border-red-600 text-red-600" : "border-custom-border-300"
+ }`}
+ >
+ arrow_downward_alt
+ {allDownVotes.length}
+
+
+
+ );
+});
diff --git a/space/components/issues/peek-overview/layout.tsx b/space/components/issues/peek-overview/layout.tsx
new file mode 100644
index 000000000..a3d7386eb
--- /dev/null
+++ b/space/components/issues/peek-overview/layout.tsx
@@ -0,0 +1,125 @@
+import React, { useEffect, useState } from "react";
+
+import { useRouter } from "next/router";
+
+// mobx
+import { observer } from "mobx-react-lite";
+// headless ui
+import { Dialog, Transition } from "@headlessui/react";
+// components
+import { FullScreenPeekView, SidePeekView } from "components/issues/peek-overview";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+
+type Props = {};
+
+export const IssuePeekOverview: React.FC
= observer((props) => {
+ const [isSidePeekOpen, setIsSidePeekOpen] = useState(false);
+ const [isModalPeekOpen, setIsModalPeekOpen] = useState(false);
+
+ // router
+ const router = useRouter();
+ const { workspace_slug, project_slug, peekId, board } = router.query;
+ // store
+ const { issueDetails: issueDetailStore, issue: issueStore } = useMobxStore();
+
+ const issueDetails = issueDetailStore.peekId && peekId ? issueDetailStore.details[peekId.toString()] : undefined;
+
+ useEffect(() => {
+ if (workspace_slug && project_slug && peekId && issueStore.issues && issueStore.issues.length > 0) {
+ if (!issueDetails) {
+ issueDetailStore.fetchIssueDetails(workspace_slug.toString(), project_slug.toString(), peekId.toString());
+ }
+ }
+ }, [workspace_slug, project_slug, issueDetailStore, issueDetails, peekId, issueStore.issues]);
+
+ const handleClose = () => {
+ issueDetailStore.setPeekId(null);
+ router.replace(
+ {
+ pathname: `/${workspace_slug?.toString()}/${project_slug}`,
+ query: {
+ board,
+ },
+ },
+ undefined,
+ { shallow: true }
+ );
+ };
+
+ useEffect(() => {
+ if (peekId) {
+ if (issueDetailStore.peekMode === "side") {
+ setIsSidePeekOpen(true);
+ setIsModalPeekOpen(false);
+ } else {
+ setIsModalPeekOpen(true);
+ setIsSidePeekOpen(false);
+ }
+ } else {
+ setIsSidePeekOpen(false);
+ setIsModalPeekOpen(false);
+ }
+ }, [peekId, issueDetailStore.peekMode]);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {issueDetailStore.peekMode === "modal" && (
+
+ )}
+ {issueDetailStore.peekMode === "full" && (
+
+ )}
+
+
+
+
+
+ >
+ );
+});
diff --git a/space/components/issues/peek-overview/side-peek-view.tsx b/space/components/issues/peek-overview/side-peek-view.tsx
new file mode 100644
index 000000000..bacf83420
--- /dev/null
+++ b/space/components/issues/peek-overview/side-peek-view.tsx
@@ -0,0 +1,55 @@
+import { observer } from "mobx-react-lite";
+// components
+import {
+ PeekOverviewHeader,
+ PeekOverviewIssueActivity,
+ PeekOverviewIssueDetails,
+ PeekOverviewIssueProperties,
+} from "components/issues/peek-overview";
+
+import { Loader } from "components/ui/loader";
+import { IIssue } from "types/issue";
+
+type Props = {
+ handleClose: () => void;
+ issueDetails: IIssue | undefined;
+};
+
+export const SidePeekView: React.FC = observer((props) => {
+ const { handleClose, issueDetails } = props;
+
+ return (
+
+
+ {issueDetails ? (
+
+ {/* issue title and description */}
+
+ {/* issue properties */}
+
+ {/* divider */}
+
+ {/* issue activity/comments */}
+
+
+ ) : (
+
+
+
+
+
+
+
+
+ )}
+
+ );
+});
diff --git a/apps/app/components/tiptap/bubble-menu/index.tsx b/space/components/tiptap/bubble-menu/index.tsx
similarity index 100%
rename from apps/app/components/tiptap/bubble-menu/index.tsx
rename to space/components/tiptap/bubble-menu/index.tsx
diff --git a/apps/app/components/tiptap/bubble-menu/link-selector.tsx b/space/components/tiptap/bubble-menu/link-selector.tsx
similarity index 92%
rename from apps/app/components/tiptap/bubble-menu/link-selector.tsx
rename to space/components/tiptap/bubble-menu/link-selector.tsx
index 1596870f7..559521db6 100644
--- a/apps/app/components/tiptap/bubble-menu/link-selector.tsx
+++ b/space/components/tiptap/bubble-menu/link-selector.tsx
@@ -9,7 +9,6 @@ interface LinkSelectorProps {
setIsOpen: Dispatch>;
}
-
export const LinkSelector: FC = ({ editor, isOpen, setIsOpen }) => {
const inputRef = useRef(null);
@@ -52,7 +51,8 @@ export const LinkSelector: FC = ({ editor, isOpen, setIsOpen
className="fixed top-full z-[99999] mt-1 flex w-60 overflow-hidden rounded border border-custom-border-300 bg-custom-background-100 dow-xl animate-in fade-in slide-in-from-top-1"
onKeyDown={(e) => {
if (e.key === "Enter") {
- e.preventDefault(); onLinkSubmit();
+ e.preventDefault();
+ onLinkSubmit();
}
}}
>
@@ -75,7 +75,9 @@ export const LinkSelector: FC = ({ editor, isOpen, setIsOpen
) : (
- {
onLinkSubmit();
}}
diff --git a/space/components/tiptap/bubble-menu/node-selector.tsx b/space/components/tiptap/bubble-menu/node-selector.tsx
new file mode 100644
index 000000000..ff4ae0b53
--- /dev/null
+++ b/space/components/tiptap/bubble-menu/node-selector.tsx
@@ -0,0 +1,126 @@
+import { Editor } from "@tiptap/core";
+import {
+ Check,
+ ChevronDown,
+ Heading1,
+ Heading2,
+ Heading3,
+ TextQuote,
+ ListOrdered,
+ TextIcon,
+ Code,
+ CheckSquare,
+} from "lucide-react";
+import { Dispatch, FC, SetStateAction } from "react";
+
+import { BubbleMenuItem } from ".";
+import { cn } from "../utils";
+
+interface NodeSelectorProps {
+ editor: Editor;
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+}
+
+export const NodeSelector: FC = ({ editor, isOpen, setIsOpen }) => {
+ const items: BubbleMenuItem[] = [
+ {
+ name: "Text",
+ icon: TextIcon,
+ command: () => editor.chain().focus().toggleNode("paragraph", "paragraph").run(),
+ isActive: () => editor.isActive("paragraph") && !editor.isActive("bulletList") && !editor.isActive("orderedList"),
+ },
+ {
+ name: "H1",
+ icon: Heading1,
+ command: () => editor.chain().focus().toggleHeading({ level: 1 }).run(),
+ isActive: () => editor.isActive("heading", { level: 1 }),
+ },
+ {
+ name: "H2",
+ icon: Heading2,
+ command: () => editor.chain().focus().toggleHeading({ level: 2 }).run(),
+ isActive: () => editor.isActive("heading", { level: 2 }),
+ },
+ {
+ name: "H3",
+ icon: Heading3,
+ command: () => editor.chain().focus().toggleHeading({ level: 3 }).run(),
+ isActive: () => editor.isActive("heading", { level: 3 }),
+ },
+ {
+ name: "To-do List",
+ icon: CheckSquare,
+ command: () => editor.chain().focus().toggleTaskList().run(),
+ isActive: () => editor.isActive("taskItem"),
+ },
+ {
+ name: "Bullet List",
+ icon: ListOrdered,
+ command: () => editor.chain().focus().toggleBulletList().run(),
+ isActive: () => editor.isActive("bulletList"),
+ },
+ {
+ name: "Numbered List",
+ icon: ListOrdered,
+ command: () => editor.chain().focus().toggleOrderedList().run(),
+ isActive: () => editor.isActive("orderedList"),
+ },
+ {
+ name: "Quote",
+ icon: TextQuote,
+ command: () => editor.chain().focus().toggleNode("paragraph", "paragraph").toggleBlockquote().run(),
+ isActive: () => editor.isActive("blockquote"),
+ },
+ {
+ name: "Code",
+ icon: Code,
+ command: () => editor.chain().focus().toggleCodeBlock().run(),
+ isActive: () => editor.isActive("codeBlock"),
+ },
+ ];
+
+ const activeItem = items.filter((item) => item.isActive()).pop() ?? {
+ name: "Multiple",
+ };
+
+ return (
+
+
setIsOpen(!isOpen)}
+ className="flex h-full items-center gap-1 whitespace-nowrap p-2 text-sm font-medium text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5"
+ >
+ {activeItem?.name}
+
+
+
+ {isOpen && (
+
+ {items.map((item, index) => (
+ {
+ item.command();
+ setIsOpen(false);
+ }}
+ className={cn(
+ "flex items-center justify-between rounded-sm px-2 py-1 text-sm text-custom-text-200 hover:bg-custom-primary-100/5 hover:text-custom-text-100",
+ { "bg-custom-primary-100/5 text-custom-text-100": activeItem.name === item.name }
+ )}
+ >
+
+ {activeItem.name === item.name && }
+
+ ))}
+
+ )}
+
+ );
+};
diff --git a/apps/app/components/tiptap/bubble-menu/utils/link-validator.tsx b/space/components/tiptap/bubble-menu/utils/link-validator.tsx
similarity index 99%
rename from apps/app/components/tiptap/bubble-menu/utils/link-validator.tsx
rename to space/components/tiptap/bubble-menu/utils/link-validator.tsx
index 5b05811d6..9af366c02 100644
--- a/apps/app/components/tiptap/bubble-menu/utils/link-validator.tsx
+++ b/space/components/tiptap/bubble-menu/utils/link-validator.tsx
@@ -9,4 +9,3 @@ export default function isValidHttpUrl(string: string): boolean {
return url.protocol === "http:" || url.protocol === "https:";
}
-
diff --git a/apps/app/components/tiptap/extensions/image-resize.tsx b/space/components/tiptap/extensions/image-resize.tsx
similarity index 78%
rename from apps/app/components/tiptap/extensions/image-resize.tsx
rename to space/components/tiptap/extensions/image-resize.tsx
index 7b2d1a2d3..448b8811c 100644
--- a/apps/app/components/tiptap/extensions/image-resize.tsx
+++ b/space/components/tiptap/extensions/image-resize.tsx
@@ -3,9 +3,7 @@ import Moveable from "react-moveable";
export const ImageResizer = ({ editor }: { editor: Editor }) => {
const updateMediaSize = () => {
- const imageInfo = document.querySelector(
- ".ProseMirror-selectednode",
- ) as HTMLImageElement;
+ const imageInfo = document.querySelector(".ProseMirror-selectednode") as HTMLImageElement;
if (imageInfo) {
const selection = editor.state.selection;
editor.commands.setImage({
@@ -28,13 +26,7 @@ export const ImageResizer = ({ editor }: { editor: Editor }) => {
keepRatio={true}
resizable={true}
throttleResize={0}
- onResize={({
- target,
- width,
- height,
- delta,
- }:
- any) => {
+ onResize={({ target, width, height, delta }: any) => {
delta[0] && (target!.style.width = `${width}px`);
delta[1] && (target!.style.height = `${height}px`);
}}
@@ -43,15 +35,10 @@ export const ImageResizer = ({ editor }: { editor: Editor }) => {
}}
scalable={true}
renderDirections={["w", "e"]}
- onScale={({
- target,
- transform,
- }:
- any) => {
+ onScale={({ target, transform }: any) => {
target!.style.transform = transform;
}}
/>
>
);
};
-
diff --git a/apps/app/components/tiptap/extensions/index.tsx b/space/components/tiptap/extensions/index.tsx
similarity index 93%
rename from apps/app/components/tiptap/extensions/index.tsx
rename to space/components/tiptap/extensions/index.tsx
index 2c5ffd10a..1aa0e2685 100644
--- a/apps/app/components/tiptap/extensions/index.tsx
+++ b/space/components/tiptap/extensions/index.tsx
@@ -23,7 +23,10 @@ import isValidHttpUrl from "../bubble-menu/utils/link-validator";
lowlight.registerLanguage("ts", ts);
-export const TiptapExtensions = (workspaceSlug: string, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void) => [
+export const TiptapExtensions = (
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+) => [
StarterKit.configure({
bulletList: {
HTMLAttributes: {
@@ -47,8 +50,7 @@ export const TiptapExtensions = (workspaceSlug: string, setIsSubmitting?: (isSub
},
code: {
HTMLAttributes: {
- class:
- "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000",
+ class: "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000",
spellcheck: "false",
},
},
diff --git a/apps/app/components/tiptap/extensions/updated-image.tsx b/space/components/tiptap/extensions/updated-image.tsx
similarity index 95%
rename from apps/app/components/tiptap/extensions/updated-image.tsx
rename to space/components/tiptap/extensions/updated-image.tsx
index 01648dcd7..b62050953 100644
--- a/apps/app/components/tiptap/extensions/updated-image.tsx
+++ b/space/components/tiptap/extensions/updated-image.tsx
@@ -10,7 +10,7 @@ const UpdatedImage = Image.extend({
return {
...this.parent?.(),
width: {
- default: '35%',
+ default: "35%",
},
height: {
default: null,
diff --git a/space/components/tiptap/index.tsx b/space/components/tiptap/index.tsx
new file mode 100644
index 000000000..3fb44fbf7
--- /dev/null
+++ b/space/components/tiptap/index.tsx
@@ -0,0 +1,113 @@
+import { useImperativeHandle, useRef, forwardRef, useEffect } from "react";
+import { useEditor, EditorContent, Editor } from "@tiptap/react";
+import { useDebouncedCallback } from "use-debounce";
+// components
+import { EditorBubbleMenu } from "./bubble-menu";
+import { TiptapExtensions } from "./extensions";
+import { TiptapEditorProps } from "./props";
+import { ImageResizer } from "./extensions/image-resize";
+
+export interface ITipTapRichTextEditor {
+ value: string;
+ noBorder?: boolean;
+ borderOnFocus?: boolean;
+ customClassName?: string;
+ editorContentCustomClassNames?: string;
+ onChange?: (json: any, html: string) => void;
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void;
+ setShouldShowAlert?: (showAlert: boolean) => void;
+ workspaceSlug: string;
+ editable?: boolean;
+ forwardedRef?: any;
+ debouncedUpdatesEnabled?: boolean;
+}
+
+const Tiptap = (props: ITipTapRichTextEditor) => {
+ const {
+ onChange,
+ debouncedUpdatesEnabled,
+ forwardedRef,
+ editable,
+ setIsSubmitting,
+ setShouldShowAlert,
+ editorContentCustomClassNames,
+ value,
+ noBorder,
+ workspaceSlug,
+ borderOnFocus,
+ customClassName,
+ } = props;
+ const editor = useEditor({
+ editable: editable ?? true,
+ editorProps: TiptapEditorProps(workspaceSlug, setIsSubmitting),
+ extensions: TiptapExtensions(workspaceSlug, setIsSubmitting),
+ content: value,
+ onUpdate: async ({ editor }) => {
+ // for instant feedback loop
+ setIsSubmitting?.("submitting");
+ setShouldShowAlert?.(true);
+ if (debouncedUpdatesEnabled) {
+ debouncedUpdates({ onChange, editor });
+ } else {
+ onChange?.(editor.getJSON(), editor.getHTML());
+ }
+ },
+ });
+
+ useEffect(() => {
+ if (editor) {
+ editor.commands.setContent(value);
+ }
+ }, [value]);
+
+ const editorRef: React.MutableRefObject = useRef(null);
+
+ useImperativeHandle(forwardedRef, () => ({
+ clearEditor: () => {
+ editorRef.current?.commands.clearContent();
+ },
+ setEditorValue: (content: string) => {
+ editorRef.current?.commands.setContent(content);
+ },
+ }));
+
+ const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => {
+ setTimeout(async () => {
+ if (onChange) {
+ onChange(editor.getJSON(), editor.getHTML());
+ }
+ }, 500);
+ }, 1000);
+
+ const editorClassNames = `relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md
+ ${noBorder ? "" : "border border-custom-border-200"} ${
+ borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0"
+ } ${customClassName}`;
+
+ if (!editor) return null;
+ editorRef.current = editor;
+
+ return (
+ {
+ editor?.chain().focus().run();
+ }}
+ className={`tiptap-editor-container cursor-text ${editorClassNames}`}
+ >
+ {editor &&
}
+
+
+ {editor?.isActive("image") && }
+
+
+ );
+};
+
+const TipTapEditor = forwardRef((props, ref) => (
+
+));
+
+TipTapEditor.displayName = "TipTapEditor";
+
+export { TipTapEditor };
diff --git a/apps/app/components/tiptap/plugins/delete-image.tsx b/space/components/tiptap/plugins/delete-image.tsx
similarity index 90%
rename from apps/app/components/tiptap/plugins/delete-image.tsx
rename to space/components/tiptap/plugins/delete-image.tsx
index 57ab65c63..a1b90fe57 100644
--- a/apps/app/components/tiptap/plugins/delete-image.tsx
+++ b/space/components/tiptap/plugins/delete-image.tsx
@@ -1,5 +1,5 @@
import { Plugin, PluginKey } from "@tiptap/pm/state";
-import { Node as ProseMirrorNode } from '@tiptap/pm/model';
+import { Node as ProseMirrorNode } from "@tiptap/pm/model";
import fileService from "services/file.service";
const deleteKey = new PluginKey("delete-image");
@@ -14,13 +14,13 @@ const TrackImageDeletionPlugin = () =>
const removedImages: ProseMirrorNode[] = [];
oldState.doc.descendants((oldNode, oldPos) => {
- if (oldNode.type.name !== 'image') return;
+ if (oldNode.type.name !== "image") return;
if (!newState.doc.resolve(oldPos).parent) return;
const newNode = newState.doc.nodeAt(oldPos);
// Check if the node has been deleted or replaced
- if (!newNode || newNode.type.name !== 'image') {
+ if (!newNode || newNode.type.name !== "image") {
// Check if the node still exists elsewhere in the document
let nodeExists = false;
newState.doc.descendants((node) => {
diff --git a/space/components/tiptap/plugins/upload-image.tsx b/space/components/tiptap/plugins/upload-image.tsx
new file mode 100644
index 000000000..8b14793b1
--- /dev/null
+++ b/space/components/tiptap/plugins/upload-image.tsx
@@ -0,0 +1,122 @@
+// @ts-nocheck
+import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state";
+import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view";
+import fileService from "services/file.service";
+
+const uploadKey = new PluginKey("upload-image");
+
+const UploadImagesPlugin = () =>
+ new Plugin({
+ key: uploadKey,
+ state: {
+ init() {
+ return DecorationSet.empty;
+ },
+ apply(tr, set) {
+ set = set.map(tr.mapping, tr.doc);
+ // See if the transaction adds or removes any placeholders
+ const action = tr.getMeta(uploadKey);
+ if (action && action.add) {
+ const { id, pos, src } = action.add;
+
+ const placeholder = document.createElement("div");
+ placeholder.setAttribute("class", "img-placeholder");
+ const image = document.createElement("img");
+ image.setAttribute("class", "opacity-10 rounded-lg border border-custom-border-300");
+ image.src = src;
+ placeholder.appendChild(image);
+ const deco = Decoration.widget(pos + 1, placeholder, {
+ id,
+ });
+ set = set.add(tr.doc, [deco]);
+ } else if (action && action.remove) {
+ set = set.remove(set.find(undefined, undefined, (spec) => spec.id == action.remove.id));
+ }
+ return set;
+ },
+ },
+ props: {
+ decorations(state) {
+ return this.getState(state);
+ },
+ },
+ });
+
+export default UploadImagesPlugin;
+
+function findPlaceholder(state: EditorState, id: {}) {
+ const decos = uploadKey.getState(state);
+ const found = decos.find(undefined, undefined, (spec: { id: number | undefined }) => spec.id == id);
+ return found.length ? found[0].from : null;
+}
+
+export async function startImageUpload(
+ file: File,
+ view: EditorView,
+ pos: number,
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+) {
+ if (!file.type.includes("image/")) {
+ return;
+ } else if (file.size / 1024 / 1024 > 20) {
+ return;
+ }
+
+ const id = {};
+
+ const tr = view.state.tr;
+ if (!tr.selection.empty) tr.deleteSelection();
+
+ const reader = new FileReader();
+ reader.readAsDataURL(file);
+ reader.onload = () => {
+ tr.setMeta(uploadKey, {
+ add: {
+ id,
+ pos,
+ src: reader.result,
+ },
+ });
+ view.dispatch(tr);
+ };
+
+ if (!workspaceSlug) {
+ return;
+ }
+ setIsSubmitting?.("submitting");
+ const src = await UploadImageHandler(file, workspaceSlug);
+ const { schema } = view.state;
+ pos = findPlaceholder(view.state, id);
+
+ if (pos == null) return;
+ const imageSrc = typeof src === "object" ? reader.result : src;
+
+ const node = schema.nodes.image.create({ src: imageSrc });
+ const transaction = view.state.tr.replaceWith(pos, pos, node).setMeta(uploadKey, { remove: { id } });
+ view.dispatch(transaction);
+}
+
+const UploadImageHandler = (file: File, workspaceSlug: string): Promise => {
+ if (!workspaceSlug) {
+ return Promise.reject("Workspace slug is missing");
+ }
+ try {
+ const formData = new FormData();
+ formData.append("asset", file);
+ formData.append("attributes", JSON.stringify({}));
+
+ return new Promise(async (resolve, reject) => {
+ const imageUrl = await fileService.uploadFile(workspaceSlug, formData).then((response) => response.asset);
+
+ const image = new Image();
+ image.src = imageUrl;
+ image.onload = () => {
+ resolve(imageUrl);
+ };
+ });
+ } catch (error) {
+ console.log(error);
+ return Promise.reject(error);
+ }
+};
diff --git a/apps/app/components/tiptap/props.tsx b/space/components/tiptap/props.tsx
similarity index 77%
rename from apps/app/components/tiptap/props.tsx
rename to space/components/tiptap/props.tsx
index d50fc29b0..1af40d623 100644
--- a/apps/app/components/tiptap/props.tsx
+++ b/space/components/tiptap/props.tsx
@@ -1,7 +1,10 @@
import { EditorProps } from "@tiptap/pm/view";
import { startImageUpload } from "./plugins/upload-image";
-export function TiptapEditorProps(workspaceSlug: string, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void): EditorProps {
+export function TiptapEditorProps(
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+): EditorProps {
return {
attributes: {
class: `prose prose-brand max-w-full prose-headings:font-display font-default focus:outline-none`,
@@ -18,11 +21,7 @@ export function TiptapEditorProps(workspaceSlug: string, setIsSubmitting?: (isSu
},
},
handlePaste: (view, event) => {
- if (
- event.clipboardData &&
- event.clipboardData.files &&
- event.clipboardData.files[0]
- ) {
+ if (event.clipboardData && event.clipboardData.files && event.clipboardData.files[0]) {
event.preventDefault();
const file = event.clipboardData.files[0];
const pos = view.state.selection.from;
@@ -32,12 +31,7 @@ export function TiptapEditorProps(workspaceSlug: string, setIsSubmitting?: (isSu
return false;
},
handleDrop: (view, event, _slice, moved) => {
- if (
- !moved &&
- event.dataTransfer &&
- event.dataTransfer.files &&
- event.dataTransfer.files[0]
- ) {
+ if (!moved && event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]) {
event.preventDefault();
const file = event.dataTransfer.files[0];
const coordinates = view.posAtCoords({
diff --git a/apps/app/components/tiptap/slash-command/index.tsx b/space/components/tiptap/slash-command/index.tsx
similarity index 53%
rename from apps/app/components/tiptap/slash-command/index.tsx
rename to space/components/tiptap/slash-command/index.tsx
index 38f5c9c0a..90287404f 100644
--- a/apps/app/components/tiptap/slash-command/index.tsx
+++ b/space/components/tiptap/slash-command/index.tsx
@@ -52,134 +52,129 @@ const Command = Extension.create({
},
});
-const getSuggestionItems = (workspaceSlug: string, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void) => ({ query }: { query: string }) =>
- [
- {
- title: "Text",
- description: "Just start typing with plain text.",
- searchTerms: ["p", "paragraph"],
- icon: ,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
+const getSuggestionItems =
+ (workspaceSlug: string, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void) =>
+ ({ query }: { query: string }) =>
+ [
+ {
+ title: "Text",
+ description: "Just start typing with plain text.",
+ searchTerms: ["p", "paragraph"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
+ },
},
- },
- {
- title: "Heading 1",
- description: "Big section heading.",
- searchTerms: ["title", "big", "large"],
- icon: ,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
+ {
+ title: "Heading 1",
+ description: "Big section heading.",
+ searchTerms: ["title", "big", "large"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
+ },
},
- },
- {
- title: "Heading 2",
- description: "Medium section heading.",
- searchTerms: ["subtitle", "medium"],
- icon: ,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
+ {
+ title: "Heading 2",
+ description: "Medium section heading.",
+ searchTerms: ["subtitle", "medium"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
+ },
},
- },
- {
- title: "Heading 3",
- description: "Small section heading.",
- searchTerms: ["subtitle", "small"],
- icon: ,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
+ {
+ title: "Heading 3",
+ description: "Small section heading.",
+ searchTerms: ["subtitle", "small"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
+ },
},
- },
- {
- title: "To-do List",
- description: "Track tasks with a to-do list.",
- searchTerms: ["todo", "task", "list", "check", "checkbox"],
- icon: ,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).toggleTaskList().run();
+ {
+ title: "To-do List",
+ description: "Track tasks with a to-do list.",
+ searchTerms: ["todo", "task", "list", "check", "checkbox"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).toggleTaskList().run();
+ },
},
- },
- {
- title: "Bullet List",
- description: "Create a simple bullet list.",
- searchTerms: ["unordered", "point"],
- icon:
,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).toggleBulletList().run();
+ {
+ title: "Bullet List",
+ description: "Create a simple bullet list.",
+ searchTerms: ["unordered", "point"],
+ icon:
,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).toggleBulletList().run();
+ },
},
- },
- {
- title: "Divider",
- description: "Visually divide blocks",
- searchTerms: ["line", "divider", "horizontal", "rule", "separate"],
- icon: ,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).setHorizontalRule().run();
+ {
+ title: "Divider",
+ description: "Visually divide blocks",
+ searchTerms: ["line", "divider", "horizontal", "rule", "separate"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).setHorizontalRule().run();
+ },
},
- },
- {
- title: "Numbered List",
- description: "Create a list with numbering.",
- searchTerms: ["ordered"],
- icon: ,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).toggleOrderedList().run();
+ {
+ title: "Numbered List",
+ description: "Create a list with numbering.",
+ searchTerms: ["ordered"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).toggleOrderedList().run();
+ },
},
- },
- {
- title: "Quote",
- description: "Capture a quote.",
- searchTerms: ["blockquote"],
- icon: ,
- command: ({ editor, range }: CommandProps) =>
- editor
- .chain()
- .focus()
- .deleteRange(range)
- .toggleNode("paragraph", "paragraph")
- .toggleBlockquote()
- .run(),
- },
- {
- title: "Code",
- description: "Capture a code snippet.",
- searchTerms: ["codeblock"],
- icon:
,
- command: ({ editor, range }: CommandProps) =>
- editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
- },
- {
- title: "Image",
- description: "Upload an image from your computer.",
- searchTerms: ["photo", "picture", "media"],
- icon: ,
- command: ({ editor, range }: CommandProps) => {
- editor.chain().focus().deleteRange(range).run();
- // upload image
- const input = document.createElement("input");
- input.type = "file";
- input.accept = "image/*";
- input.onchange = async () => {
- if (input.files?.length) {
- const file = input.files[0];
- const pos = editor.view.state.selection.from;
- startImageUpload(file, editor.view, pos, workspaceSlug, setIsSubmitting);
- }
- };
- input.click();
+ {
+ title: "Quote",
+ description: "Capture a quote.",
+ searchTerms: ["blockquote"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) =>
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run(),
},
- },
- ].filter((item) => {
- if (typeof query === "string" && query.length > 0) {
- const search = query.toLowerCase();
- return (
- item.title.toLowerCase().includes(search) ||
- item.description.toLowerCase().includes(search) ||
- (item.searchTerms && item.searchTerms.some((term: string) => term.includes(search)))
- );
- }
- return true;
- });
+ {
+ title: "Code",
+ description: "Capture a code snippet.",
+ searchTerms: ["codeblock"],
+ icon:
,
+ command: ({ editor, range }: CommandProps) => editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
+ },
+ {
+ title: "Image",
+ description: "Upload an image from your computer.",
+ searchTerms: ["photo", "picture", "media"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).run();
+ // upload image
+ const input = document.createElement("input");
+ input.type = "file";
+ input.accept = "image/*";
+ input.onchange = async () => {
+ if (input.files?.length) {
+ const file = input.files[0];
+ const pos = editor.view.state.selection.from;
+ startImageUpload(file, editor.view, pos, workspaceSlug, setIsSubmitting);
+ }
+ };
+ input.click();
+ },
+ },
+ ].filter((item) => {
+ if (typeof query === "string" && query.length > 0) {
+ const search = query.toLowerCase();
+ return (
+ item.title.toLowerCase().includes(search) ||
+ item.description.toLowerCase().includes(search) ||
+ (item.searchTerms && item.searchTerms.some((term: string) => term.includes(search)))
+ );
+ }
+ return true;
+ });
export const updateScrollView = (container: HTMLElement, item: HTMLElement) => {
const containerHeight = container.offsetHeight;
@@ -195,15 +190,7 @@ export const updateScrollView = (container: HTMLElement, item: HTMLElement) => {
}
};
-const CommandList = ({
- items,
- command,
-}: {
- items: CommandItemProps[];
- command: any;
- editor: any;
- range: any;
-}) => {
+const CommandList = ({ items, command }: { items: CommandItemProps[]; command: any; editor: any; range: any }) => {
const [selectedIndex, setSelectedIndex] = useState(0);
const selectItem = useCallback(
@@ -328,7 +315,10 @@ const renderItems = () => {
};
};
-export const SlashCommand = (workspaceSlug: string, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void) =>
+export const SlashCommand = (
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+) =>
Command.configure({
suggestion: {
items: getSuggestionItems(workspaceSlug, setIsSubmitting),
diff --git a/apps/app/components/tiptap/utils.ts b/space/components/tiptap/utils.ts
similarity index 100%
rename from apps/app/components/tiptap/utils.ts
rename to space/components/tiptap/utils.ts
diff --git a/space/components/ui/dropdown.tsx b/space/components/ui/dropdown.tsx
new file mode 100644
index 000000000..d1791de00
--- /dev/null
+++ b/space/components/ui/dropdown.tsx
@@ -0,0 +1,149 @@
+"use client";
+
+import { Fragment, useState, useRef } from "react";
+
+// next
+import Link from "next/link";
+
+// headless
+import { Popover, Transition } from "@headlessui/react";
+import { ChevronLeftIcon, CheckIcon } from "@heroicons/react/20/solid";
+
+// hooks
+import useOutSideClick from "hooks/use-outside-click";
+
+type ItemOptionType = {
+ display: React.ReactNode;
+ as?: "button" | "link" | "div";
+ href?: string;
+ isSelected?: boolean;
+ onClick?: () => void;
+ children?: ItemOptionType[] | null;
+};
+
+type DropdownItemProps = {
+ item: ItemOptionType;
+};
+
+type DropDownListProps = {
+ open: boolean;
+ handleClose?: () => void;
+ items: ItemOptionType[];
+};
+
+type DropdownProps = {
+ button: React.ReactNode | (() => React.ReactNode);
+ items: ItemOptionType[];
+};
+
+const DropdownList: React.FC = (props) => {
+ const { open, items, handleClose } = props;
+
+ const ref = useRef(null);
+
+ useOutSideClick(ref, () => {
+ if (handleClose) handleClose();
+ });
+
+ return (
+
+
+
+
+ {items.map((item, index) => (
+
+ ))}
+
+
+
+
+ );
+};
+
+const DropdownItem: React.FC = (props) => {
+ const { item } = props;
+ const { display, children, as: as_, href, onClick, isSelected } = item;
+
+ const [open, setOpen] = useState(false);
+
+ return (
+
+ {(!as_ || as_ === "button" || as_ === "div") && (
+ {
+ if (!children) {
+ if (onClick) onClick();
+ return;
+ }
+ setOpen((prev) => !prev);
+ }}
+ className={`w-full flex items-center gap-1 rounded px-1 py-1.5 text-custom-text-200 hover:bg-custom-background-80 ${
+ isSelected ? "bg-custom-background-80" : ""
+ }`}
+ >
+ {children && }
+ {!children && }
+ {display}
+
+
+ )}
+
+ {as_ === "link" && {display}}
+
+ {children && setOpen(false)} items={children} />}
+
+ );
+};
+
+const Dropdown: React.FC = (props) => {
+ const { button, items } = props;
+
+ return (
+
+ {({ open }) => (
+ <>
+
+ {typeof button === "function" ? button() : button}
+
+
+
+
+
+ {items.map((item, index) => (
+
+ ))}
+
+
+
+ >
+ )}
+
+ );
+};
+
+export { Dropdown };
diff --git a/space/components/ui/icon.tsx b/space/components/ui/icon.tsx
new file mode 100644
index 000000000..418186291
--- /dev/null
+++ b/space/components/ui/icon.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+
+type Props = {
+ iconName: string;
+ className?: string;
+};
+
+export const Icon: React.FC = ({ iconName, className = "" }) => (
+ {iconName}
+);
diff --git a/space/components/ui/index.ts b/space/components/ui/index.ts
new file mode 100644
index 000000000..e44096909
--- /dev/null
+++ b/space/components/ui/index.ts
@@ -0,0 +1,8 @@
+export * from "./dropdown";
+export * from "./input";
+export * from "./loader";
+export * from "./primary-button";
+export * from "./secondary-button";
+export * from "./icon";
+export * from "./reaction-selector";
+export * from "./tooltip";
diff --git a/space/components/ui/input.tsx b/space/components/ui/input.tsx
new file mode 100644
index 000000000..b6be82ae5
--- /dev/null
+++ b/space/components/ui/input.tsx
@@ -0,0 +1,37 @@
+import React, { forwardRef, Ref } from "react";
+
+// types
+interface Props extends React.InputHTMLAttributes {
+ mode?: "primary" | "transparent" | "trueTransparent";
+ error?: boolean;
+ inputSize?: "rg" | "lg";
+ fullWidth?: boolean;
+}
+
+export const Input = forwardRef((props: Props, ref: Ref) => {
+ const { mode = "primary", error, className = "", type, fullWidth = true, id, inputSize = "rg", ...rest } = props;
+
+ return (
+
+ );
+});
+
+Input.displayName = "Input";
+
+export default Input;
diff --git a/apps/app/components/ui/loader.tsx b/space/components/ui/loader.tsx
similarity index 100%
rename from apps/app/components/ui/loader.tsx
rename to space/components/ui/loader.tsx
diff --git a/space/components/ui/primary-button.tsx b/space/components/ui/primary-button.tsx
new file mode 100644
index 000000000..b3e1b82ee
--- /dev/null
+++ b/space/components/ui/primary-button.tsx
@@ -0,0 +1,35 @@
+interface ButtonProps extends React.ButtonHTMLAttributes {
+ size?: "sm" | "md" | "lg";
+ outline?: boolean;
+ loading?: boolean;
+}
+
+export const PrimaryButton: React.FC = ({
+ children,
+ className = "",
+ onClick,
+ type = "button",
+ disabled = false,
+ loading = false,
+ size = "sm",
+ outline = false,
+}) => (
+
+ {children}
+
+);
diff --git a/space/components/ui/reaction-selector.tsx b/space/components/ui/reaction-selector.tsx
new file mode 100644
index 000000000..70994460c
--- /dev/null
+++ b/space/components/ui/reaction-selector.tsx
@@ -0,0 +1,77 @@
+import { Fragment } from "react";
+
+// headless ui
+import { Popover, Transition } from "@headlessui/react";
+
+// helper
+import { renderEmoji } from "helpers/emoji.helper";
+
+// icons
+import { Icon } from "components/ui";
+
+const reactionEmojis = ["128077", "128078", "128516", "128165", "128533", "129505", "9992", "128064"];
+
+interface Props {
+ size?: "sm" | "md" | "lg";
+ position?: "top" | "bottom";
+ onSelect: (emoji: string) => void;
+}
+
+export const ReactionSelector: React.FC = (props) => {
+ const { onSelect, position, size } = props;
+
+ return (
+
+ {({ open, close: closePopover }) => (
+ <>
+
+
+
+
+
+
+
+
+
+ {reactionEmojis.map((emoji) => (
+ {
+ onSelect(emoji);
+ closePopover();
+ }}
+ className="flex select-none items-center justify-between rounded-md text-sm p-1 hover:bg-custom-sidebar-background-90"
+ >
+ {renderEmoji(emoji)}
+
+ ))}
+
+
+
+
+ >
+ )}
+
+ );
+};
diff --git a/space/components/ui/secondary-button.tsx b/space/components/ui/secondary-button.tsx
new file mode 100644
index 000000000..2a9b3d528
--- /dev/null
+++ b/space/components/ui/secondary-button.tsx
@@ -0,0 +1,35 @@
+interface ButtonProps extends React.ButtonHTMLAttributes {
+ size?: "sm" | "md" | "lg";
+ outline?: boolean;
+ loading?: boolean;
+}
+
+export const SecondaryButton: React.FC = ({
+ children,
+ className = "",
+ onClick,
+ type = "button",
+ disabled = false,
+ loading = false,
+ size = "sm",
+ outline = false,
+}) => (
+
+ {children}
+
+);
diff --git a/apps/app/components/toast-alert/index.tsx b/space/components/ui/toast-alert.tsx
similarity index 100%
rename from apps/app/components/toast-alert/index.tsx
rename to space/components/ui/toast-alert.tsx
diff --git a/space/components/ui/tooltip.tsx b/space/components/ui/tooltip.tsx
new file mode 100644
index 000000000..994c0f32a
--- /dev/null
+++ b/space/components/ui/tooltip.tsx
@@ -0,0 +1,71 @@
+import React from "react";
+
+// next-themes
+import { useTheme } from "next-themes";
+// tooltip2
+import { Tooltip2 } from "@blueprintjs/popover2";
+
+type Props = {
+ tooltipHeading?: string;
+ tooltipContent: string | React.ReactNode;
+ position?:
+ | "top"
+ | "right"
+ | "bottom"
+ | "left"
+ | "auto"
+ | "auto-end"
+ | "auto-start"
+ | "bottom-left"
+ | "bottom-right"
+ | "left-bottom"
+ | "left-top"
+ | "right-bottom"
+ | "right-top"
+ | "top-left"
+ | "top-right";
+ children: JSX.Element;
+ disabled?: boolean;
+ className?: string;
+ openDelay?: number;
+ closeDelay?: number;
+};
+
+export const Tooltip: React.FC = ({
+ tooltipHeading,
+ tooltipContent,
+ position = "top",
+ children,
+ disabled = false,
+ className = "",
+ openDelay = 200,
+ closeDelay,
+}) => {
+ const { theme } = useTheme();
+
+ return (
+
+ {tooltipHeading && (
+
+ {tooltipHeading}
+
+ )}
+ {tooltipContent}
+
+ }
+ position={position}
+ renderTarget={({ isOpen: isTooltipOpen, ref: eleReference, ...tooltipProps }) =>
+ React.cloneElement(children, { ref: eleReference, ...tooltipProps, ...children.props })
+ }
+ />
+ );
+};
diff --git a/space/components/views/home.tsx b/space/components/views/home.tsx
new file mode 100644
index 000000000..999fce073
--- /dev/null
+++ b/space/components/views/home.tsx
@@ -0,0 +1,13 @@
+// mobx
+import { observer } from "mobx-react-lite";
+import { useMobxStore } from "lib/mobx/store-provider";
+// components
+import { SignInView, UserLoggedIn } from "components/accounts";
+
+export const HomeView = observer(() => {
+ const { user: userStore } = useMobxStore();
+
+ if (!userStore.currentUser) return
;
+
+ return
;
+});
diff --git a/space/components/views/index.ts b/space/components/views/index.ts
new file mode 100644
index 000000000..84d36cd29
--- /dev/null
+++ b/space/components/views/index.ts
@@ -0,0 +1 @@
+export * from "./home";
diff --git a/space/components/views/project-details.tsx b/space/components/views/project-details.tsx
new file mode 100644
index 000000000..1c9c6ddc9
--- /dev/null
+++ b/space/components/views/project-details.tsx
@@ -0,0 +1,98 @@
+import { useEffect } from "react";
+
+import Image from "next/image";
+import { useRouter } from "next/router";
+
+// mobx
+import { observer } from "mobx-react-lite";
+// components
+import { IssueListView } from "components/issues/board-views/list";
+import { IssueKanbanView } from "components/issues/board-views/kanban";
+import { IssueCalendarView } from "components/issues/board-views/calendar";
+import { IssueSpreadsheetView } from "components/issues/board-views/spreadsheet";
+import { IssueGanttView } from "components/issues/board-views/gantt";
+import { IssuePeekOverview } from "components/issues/peek-overview";
+// mobx store
+import { RootStore } from "store/root";
+import { useMobxStore } from "lib/mobx/store-provider";
+// assets
+import SomethingWentWrongImage from "public/something-went-wrong.svg";
+
+export const ProjectDetailsView = observer(() => {
+ const router = useRouter();
+ const { workspace_slug, project_slug, states, labels, priorities, board, peekId } = router.query;
+
+ const {
+ issue: issueStore,
+ project: projectStore,
+ issueDetails: issueDetailStore,
+ user: userStore,
+ }: RootStore = useMobxStore();
+
+ useEffect(() => {
+ if (!userStore.currentUser) {
+ userStore.fetchCurrentUser();
+ }
+ }, [userStore]);
+
+ useEffect(() => {
+ if (workspace_slug && project_slug) {
+ const params = {
+ state: states || null,
+ labels: labels || null,
+ priority: priorities || null,
+ };
+ issueStore.fetchPublicIssues(workspace_slug?.toString(), project_slug.toString(), params);
+ }
+ }, [workspace_slug, project_slug, issueStore, states, labels, priorities]);
+
+ useEffect(() => {
+ if (peekId && workspace_slug && project_slug) {
+ issueDetailStore.setPeekId(peekId.toString());
+ }
+ }, [peekId, issueDetailStore, project_slug, workspace_slug]);
+
+ return (
+
+ {workspace_slug &&
}
+
+ {issueStore?.loader && !issueStore.issues ? (
+
Loading...
+ ) : (
+ <>
+ {issueStore?.error ? (
+
+
+
+
Oops! Something went wrong.
+
The public board does not exist. Please check the URL.
+
+
+ ) : (
+ projectStore?.activeBoard && (
+ <>
+ {projectStore?.activeBoard === "list" && (
+
+
+
+ )}
+ {projectStore?.activeBoard === "kanban" && (
+
+
+
+ )}
+ {projectStore?.activeBoard === "calendar" &&
}
+ {projectStore?.activeBoard === "spreadsheet" &&
}
+ {projectStore?.activeBoard === "gantt" &&
}
+ >
+ )
+ )}
+ >
+ )}
+
+ );
+});
diff --git a/apps/space/constants/data.ts b/space/constants/data.ts
similarity index 67%
rename from apps/space/constants/data.ts
rename to space/constants/data.ts
index 81ccae116..29d411342 100644
--- a/apps/space/constants/data.ts
+++ b/space/constants/data.ts
@@ -7,7 +7,7 @@ import {
TIssueGroupKey,
IIssuePriorityFilters,
IIssueGroup,
-} from "store/types/issue";
+} from "types/issue";
// icons
import {
BacklogStateIcon,
@@ -18,69 +18,49 @@ import {
} from "components/icons";
// all issue views
-export const issueViews: IIssueBoardViews[] = [
- {
- key: "list",
+export const issueViews: any = {
+ list: {
title: "List View",
icon: "format_list_bulleted",
className: "",
},
- {
- key: "kanban",
+ kanban: {
title: "Board View",
icon: "grid_view",
className: "",
},
- // {
- // key: "calendar",
- // title: "Calendar View",
- // icon: "calendar_month",
- // className: "",
- // },
- // {
- // key: "spreadsheet",
- // title: "Spreadsheet View",
- // icon: "table_chart",
- // className: "",
- // },
- // {
- // key: "gantt",
- // title: "Gantt Chart View",
- // icon: "waterfall_chart",
- // className: "rotate-90",
- // },
-];
+};
// issue priority filters
export const issuePriorityFilters: IIssuePriorityFilters[] = [
{
key: "urgent",
title: "Urgent",
- className: "border border-red-500/50 bg-red-500/20 text-red-500",
+ className: "bg-red-500 border-red-500 text-white",
icon: "error",
},
{
key: "high",
title: "High",
- className: "border border-orange-500/50 bg-orange-500/20 text-orange-500",
+ className: "text-orange-500 border-custom-border-300",
icon: "signal_cellular_alt",
},
{
key: "medium",
title: "Medium",
- className: "border border-yellow-500/50 bg-yellow-500/20 text-yellow-500",
+ className: "text-yellow-500 border-custom-border-300",
icon: "signal_cellular_alt_2_bar",
},
{
key: "low",
title: "Low",
- className: "border border-green-500/50 bg-green-500/20 text-green-500",
+ className: "text-green-500 border-custom-border-300",
icon: "signal_cellular_alt_1_bar",
},
{
key: "none",
title: "None",
- className: "border border-gray-500/50 bg-gray-500/20 text-gray-500",
+ className: "text-gray-500 border-custom-border-300",
icon: "block",
},
];
@@ -111,35 +91,35 @@ export const issueGroups: IIssueGroup[] = [
key: "backlog",
title: "Backlog",
color: "#d9d9d9",
- className: `border-[#d9d9d9]/50 text-[#d9d9d9] bg-[#d9d9d9]/10`,
+ className: `text-[#d9d9d9] bg-[#d9d9d9]/10`,
icon: BacklogStateIcon,
},
{
key: "unstarted",
title: "Unstarted",
color: "#3f76ff",
- className: `border-[#3f76ff]/50 text-[#3f76ff] bg-[#3f76ff]/10`,
+ className: `text-[#3f76ff] bg-[#3f76ff]/10`,
icon: UnstartedStateIcon,
},
{
key: "started",
title: "Started",
color: "#f59e0b",
- className: `border-[#f59e0b]/50 text-[#f59e0b] bg-[#f59e0b]/10`,
+ className: `text-[#f59e0b] bg-[#f59e0b]/10`,
icon: StartedStateIcon,
},
{
key: "completed",
title: "Completed",
color: "#16a34a",
- className: `border-[#16a34a]/50 text-[#16a34a] bg-[#16a34a]/10`,
+ className: `text-[#16a34a] bg-[#16a34a]/10`,
icon: CompletedStateIcon,
},
{
key: "cancelled",
title: "Cancelled",
color: "#dc2626",
- className: `border-[#dc2626]/50 text-[#dc2626] bg-[#dc2626]/10`,
+ className: `text-[#dc2626] bg-[#dc2626]/10`,
icon: CancelledStateIcon,
},
];
diff --git a/space/constants/helpers.ts b/space/constants/helpers.ts
new file mode 100644
index 000000000..0cf142353
--- /dev/null
+++ b/space/constants/helpers.ts
@@ -0,0 +1,36 @@
+export const renderDateFormat = (date: string | Date | null) => {
+ if (!date) return "N/A";
+
+ var d = new Date(date),
+ month = "" + (d.getMonth() + 1),
+ day = "" + d.getDate(),
+ year = d.getFullYear();
+
+ if (month.length < 2) month = "0" + month;
+ if (day.length < 2) day = "0" + day;
+
+ return [year, month, day].join("-");
+};
+
+/**
+ * @description Returns date and month, if date is of the current year
+ * @description Returns date, month adn year, if date is of a different year than current
+ * @param {string} date
+ * @example renderFullDate("2023-01-01") // 1 Jan
+ * @example renderFullDate("2021-01-01") // 1 Jan, 2021
+ */
+
+export const renderFullDate = (date: string): string => {
+ if (!date) return "";
+
+ const months: string[] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+
+ const currentDate: Date = new Date();
+ const [year, month, day]: number[] = date.split("-").map(Number);
+
+ const formattedMonth: string = months[month - 1];
+ const formattedDay: string = day < 10 ? `0${day}` : day.toString();
+
+ if (currentDate.getFullYear() === year) return `${formattedDay} ${formattedMonth}`;
+ else return `${formattedDay} ${formattedMonth}, ${year}`;
+};
diff --git a/space/constants/seo.ts b/space/constants/seo.ts
new file mode 100644
index 000000000..b2baca612
--- /dev/null
+++ b/space/constants/seo.ts
@@ -0,0 +1,7 @@
+export const SITE_NAME = "Plane Deploy | Make your Plane boards and roadmaps pubic with just one-click. ";
+export const SITE_TITLE = "Plane Deploy | Make your Plane boards public with one-click";
+export const SITE_DESCRIPTION = "Plane Deploy is a customer feedback management tool built on top of plane.so";
+export const SITE_KEYWORDS =
+ "software development, customer feedback, software, accelerate, code management, release management, project management, issue tracking, agile, scrum, kanban, collaboration";
+export const SITE_URL = "https://app.plane.so/";
+export const TWITTER_USER_NAME = "planepowers";
diff --git a/space/constants/workspace.ts b/space/constants/workspace.ts
new file mode 100644
index 000000000..5ae5a7cf4
--- /dev/null
+++ b/space/constants/workspace.ts
@@ -0,0 +1,12 @@
+export const USER_ROLES = [
+ { value: "Product / Project Manager", label: "Product / Project Manager" },
+ { value: "Development / Engineering", label: "Development / Engineering" },
+ { value: "Founder / Executive", label: "Founder / Executive" },
+ { value: "Freelancer / Consultant", label: "Freelancer / Consultant" },
+ { value: "Marketing / Growth", label: "Marketing / Growth" },
+ { value: "Sales / Business Development", label: "Sales / Business Development" },
+ { value: "Support / Operations", label: "Support / Operations" },
+ { value: "Student / Professor", label: "Student / Professor" },
+ { value: "Human Resources", label: "Human Resources" },
+ { value: "Other", label: "Other" },
+];
diff --git a/space/contexts/toast.context.tsx b/space/contexts/toast.context.tsx
new file mode 100644
index 000000000..a382b4fd2
--- /dev/null
+++ b/space/contexts/toast.context.tsx
@@ -0,0 +1,97 @@
+import React, { createContext, useCallback, useReducer } from "react";
+// uuid
+import { v4 as uuid } from "uuid";
+// components
+import ToastAlert from "components/ui/toast-alert";
+
+export const toastContext = createContext
({} as ContextType);
+
+// types
+type ToastAlert = {
+ id: string;
+ title: string;
+ message?: string;
+ type: "success" | "error" | "warning" | "info";
+};
+
+type ReducerActionType = {
+ type: "SET_TOAST_ALERT" | "REMOVE_TOAST_ALERT";
+ payload: ToastAlert;
+};
+
+type ContextType = {
+ alerts?: ToastAlert[];
+ removeAlert: (id: string) => void;
+ setToastAlert: (data: {
+ title: string;
+ type?: "success" | "error" | "warning" | "info" | undefined;
+ message?: string | undefined;
+ }) => void;
+};
+
+type StateType = {
+ toastAlerts?: ToastAlert[];
+};
+
+type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
+
+export const initialState: StateType = {
+ toastAlerts: [],
+};
+
+export const reducer: ReducerFunctionType = (state, action) => {
+ const { type, payload } = action;
+
+ switch (type) {
+ case "SET_TOAST_ALERT":
+ return {
+ ...state,
+ toastAlerts: [...(state.toastAlerts ?? []), payload],
+ };
+
+ case "REMOVE_TOAST_ALERT":
+ return {
+ ...state,
+ toastAlerts: state.toastAlerts?.filter((toastAlert) => toastAlert.id !== payload.id),
+ };
+
+ default: {
+ return state;
+ }
+ }
+};
+
+export const ToastContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ const [state, dispatch] = useReducer(reducer, initialState);
+
+ const removeAlert = useCallback((id: string) => {
+ dispatch({
+ type: "REMOVE_TOAST_ALERT",
+ payload: { id, title: "", message: "", type: "success" },
+ });
+ }, []);
+
+ const setToastAlert = useCallback(
+ (data: { title: string; type?: "success" | "error" | "warning" | "info"; message?: string }) => {
+ const id = uuid();
+ const { title, type, message } = data;
+ dispatch({
+ type: "SET_TOAST_ALERT",
+ payload: { id, title, message, type: type ?? "success" },
+ });
+
+ const timer = setTimeout(() => {
+ removeAlert(id);
+ clearTimeout(timer);
+ }, 3000);
+ },
+ [removeAlert]
+ );
+
+ return (
+
+
+ {children}
+
+ );
+};
diff --git a/space/helpers/date-time.helper.ts b/space/helpers/date-time.helper.ts
new file mode 100644
index 000000000..625871625
--- /dev/null
+++ b/space/helpers/date-time.helper.ts
@@ -0,0 +1,14 @@
+export const timeAgo = (time: any) => {
+ switch (typeof time) {
+ case "number":
+ break;
+ case "string":
+ time = +new Date(time);
+ break;
+ case "object":
+ if (time.constructor === Date) time = time.getTime();
+ break;
+ default:
+ time = +new Date();
+ }
+};
diff --git a/apps/app/helpers/emoji.helper.tsx b/space/helpers/emoji.helper.tsx
similarity index 77%
rename from apps/app/helpers/emoji.helper.tsx
rename to space/helpers/emoji.helper.tsx
index 06bf8ba15..7c9f3cfcb 100644
--- a/apps/app/helpers/emoji.helper.tsx
+++ b/space/helpers/emoji.helper.tsx
@@ -41,13 +41,16 @@ export const groupReactions: (reactions: any[], key: string) => { [key: string]:
reactions: any,
key: string
) => {
- const groupedReactions = reactions.reduce((acc: any, reaction: any) => {
- if (!acc[reaction[key]]) {
- acc[reaction[key]] = [];
- }
- acc[reaction[key]].push(reaction);
- return acc;
- }, {} as { [key: string]: any[] });
+ const groupedReactions = reactions.reduce(
+ (acc: any, reaction: any) => {
+ if (!acc[reaction[key]]) {
+ acc[reaction[key]] = [];
+ }
+ acc[reaction[key]].push(reaction);
+ return acc;
+ },
+ {} as { [key: string]: any[] }
+ );
return groupedReactions;
};
diff --git a/space/helpers/string.helper.ts b/space/helpers/string.helper.ts
new file mode 100644
index 000000000..1b676ca57
--- /dev/null
+++ b/space/helpers/string.helper.ts
@@ -0,0 +1,31 @@
+export const addSpaceIfCamelCase = (str: string) => str.replace(/([a-z])([A-Z])/g, "$1 $2");
+
+const fallbackCopyTextToClipboard = (text: string) => {
+ var textArea = document.createElement("textarea");
+ textArea.value = text;
+
+ // Avoid scrolling to bottom
+ textArea.style.top = "0";
+ textArea.style.left = "0";
+ textArea.style.position = "fixed";
+
+ document.body.appendChild(textArea);
+ textArea.focus();
+ textArea.select();
+
+ try {
+ // FIXME: Even though we are using this as a fallback, execCommand is deprecated 👎. We should find a better way to do this.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
+ var successful = document.execCommand("copy");
+ } catch (err) {}
+
+ document.body.removeChild(textArea);
+};
+
+export const copyTextToClipboard = async (text: string) => {
+ if (!navigator.clipboard) {
+ fallbackCopyTextToClipboard(text);
+ return;
+ }
+ await navigator.clipboard.writeText(text);
+};
diff --git a/space/hooks/use-outside-click.tsx b/space/hooks/use-outside-click.tsx
new file mode 100644
index 000000000..f2bed415f
--- /dev/null
+++ b/space/hooks/use-outside-click.tsx
@@ -0,0 +1,21 @@
+"use client";
+
+import { useEffect } from "react";
+
+const useOutSideClick = (ref: any, callback: any) => {
+ const handleClick = (e: any) => {
+ if (ref.current && !ref.current.contains(e.target)) {
+ callback();
+ }
+ };
+
+ useEffect(() => {
+ document.addEventListener("click", handleClick);
+
+ return () => {
+ document.removeEventListener("click", handleClick);
+ };
+ });
+};
+
+export default useOutSideClick;
diff --git a/apps/app/hooks/use-timer.tsx b/space/hooks/use-timer.tsx
similarity index 100%
rename from apps/app/hooks/use-timer.tsx
rename to space/hooks/use-timer.tsx
diff --git a/apps/app/hooks/use-toast.tsx b/space/hooks/use-toast.tsx
similarity index 100%
rename from apps/app/hooks/use-toast.tsx
rename to space/hooks/use-toast.tsx
diff --git a/space/layouts/project-layout.tsx b/space/layouts/project-layout.tsx
new file mode 100644
index 000000000..1a0b7899e
--- /dev/null
+++ b/space/layouts/project-layout.tsx
@@ -0,0 +1,33 @@
+import Link from "next/link";
+import Image from "next/image";
+
+// mobx
+import { observer } from "mobx-react-lite";
+import planeLogo from "public/plane-logo.svg";
+// components
+import IssueNavbar from "components/issues/navbar";
+
+const ProjectLayout = ({ children }: { children: React.ReactNode }) => (
+
+);
+
+export default observer(ProjectLayout);
diff --git a/apps/space/lib/index.ts b/space/lib/index.ts
similarity index 100%
rename from apps/space/lib/index.ts
rename to space/lib/index.ts
diff --git a/space/lib/mobx/store-init.tsx b/space/lib/mobx/store-init.tsx
new file mode 100644
index 000000000..6e38d9c6d
--- /dev/null
+++ b/space/lib/mobx/store-init.tsx
@@ -0,0 +1,25 @@
+"use client";
+
+import { useEffect } from "react";
+// next imports
+import { useRouter } from "next/router";
+// mobx store
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+
+const MobxStoreInit = () => {
+ const store: RootStore = useMobxStore();
+
+ const router = useRouter();
+ const { states, labels, priorities } = router.query as { states: string[]; labels: string[]; priorities: string[] };
+
+ // useEffect(() => {
+ // store.issue.userSelectedLabels = labels || [];
+ // store.issue.userSelectedPriorities = priorities || [];
+ // store.issue.userSelectedStates = states || [];
+ // }, [store.issue]);
+
+ return <>>;
+};
+
+export default MobxStoreInit;
diff --git a/apps/app/lib/mobx/store-provider.tsx b/space/lib/mobx/store-provider.tsx
similarity index 100%
rename from apps/app/lib/mobx/store-provider.tsx
rename to space/lib/mobx/store-provider.tsx
diff --git a/space/next.config.js b/space/next.config.js
new file mode 100644
index 000000000..392a4cab9
--- /dev/null
+++ b/space/next.config.js
@@ -0,0 +1,19 @@
+/** @type {import('next').NextConfig} */
+const path = require("path");
+const withImages = require("next-images");
+
+const nextConfig = {
+ reactStrictMode: false,
+ swcMinify: true,
+ experimental: {
+ outputFileTracingRoot: path.join(__dirname, "../"),
+ },
+ output: "standalone",
+};
+
+if (parseInt(process.env.NEXT_PUBLIC_DEPLOY_WITH_NGINX || "0")) {
+ const nextConfigWithNginx = withImages({ basePath: "/spaces", ...nextConfig });
+ module.exports = nextConfigWithNginx;
+} else {
+ module.exports = nextConfig;
+}
diff --git a/space/package.json b/space/package.json
new file mode 100644
index 000000000..768abb8ff
--- /dev/null
+++ b/space/package.json
@@ -0,0 +1,80 @@
+{
+ "name": "space",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "dev": "next dev -p 4000",
+ "build": "next build",
+ "start": "next start -p 4000",
+ "lint": "next lint"
+ },
+ "dependencies": {
+ "@blueprintjs/core": "^4.16.3",
+ "@blueprintjs/popover2": "^1.13.3",
+ "@emotion/react": "^11.11.1",
+ "@emotion/styled": "^11.11.0",
+ "@headlessui/react": "^1.7.13",
+ "@heroicons/react": "^2.0.12",
+ "@mui/icons-material": "^5.14.1",
+ "@mui/material": "^5.14.1",
+ "@tailwindcss/typography": "^0.5.9",
+ "@tiptap-pro/extension-unique-id": "^2.1.0",
+ "@tiptap/extension-code-block-lowlight": "^2.0.4",
+ "@tiptap/extension-color": "^2.0.4",
+ "@tiptap/extension-gapcursor": "^2.1.7",
+ "@tiptap/extension-highlight": "^2.0.4",
+ "@tiptap/extension-horizontal-rule": "^2.0.4",
+ "@tiptap/extension-image": "^2.0.4",
+ "@tiptap/extension-link": "^2.0.4",
+ "@tiptap/extension-placeholder": "^2.0.4",
+ "@tiptap/extension-table": "^2.1.6",
+ "@tiptap/extension-table-cell": "^2.1.6",
+ "@tiptap/extension-table-header": "^2.1.6",
+ "@tiptap/extension-table-row": "^2.1.6",
+ "@tiptap/extension-task-item": "^2.0.4",
+ "@tiptap/extension-task-list": "^2.0.4",
+ "@tiptap/extension-text-style": "^2.0.4",
+ "@tiptap/extension-underline": "^2.0.4",
+ "@tiptap/pm": "^2.0.4",
+ "@tiptap/react": "^2.0.4",
+ "@tiptap/starter-kit": "^2.0.4",
+ "@tiptap/suggestion": "^2.0.4",
+ "axios": "^1.3.4",
+ "clsx": "^2.0.0",
+ "js-cookie": "^3.0.1",
+ "lowlight": "^2.9.0",
+ "lucide-react": "^0.263.1",
+ "mobx": "^6.10.0",
+ "mobx-react-lite": "^4.0.3",
+ "next": "12.3.2",
+ "next-images": "^1.8.5",
+ "next-themes": "^0.2.1",
+ "nprogress": "^0.2.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.38.0",
+ "react-moveable": "^0.54.1",
+ "swr": "^2.2.2",
+ "tailwind-merge": "^1.14.0",
+ "tiptap-markdown": "^0.8.2",
+ "typescript": "4.9.5",
+ "use-debounce": "^9.0.4",
+ "uuid": "^9.0.0"
+ },
+ "devDependencies": {
+ "@tailwindcss/typography": "^0.5.9",
+ "@types/js-cookie": "^3.0.3",
+ "@types/node": "18.14.1",
+ "@types/nprogress": "^0.2.0",
+ "@types/react": "18.0.28",
+ "@types/react-dom": "18.0.11",
+ "@types/uuid": "^9.0.1",
+ "autoprefixer": "^10.4.13",
+ "eslint": "8.34.0",
+ "eslint-config-custom": "*",
+ "eslint-config-next": "13.2.1",
+ "postcss": "^8.4.21",
+ "tsconfig": "*",
+ "tailwindcss": "^3.2.7"
+ }
+}
diff --git a/apps/space/pages/404.tsx b/space/pages/404.tsx
similarity index 90%
rename from apps/space/pages/404.tsx
rename to space/pages/404.tsx
index d10d95fb9..be40bd501 100644
--- a/apps/space/pages/404.tsx
+++ b/space/pages/404.tsx
@@ -1,12 +1,13 @@
// next imports
import Image from "next/image";
+import notFoundImage from "public/404.svg";
const Custom404Error = () => (
-
+
Oops! Something went wrong.
diff --git a/space/pages/[workspace_slug]/[project_slug]/index.tsx b/space/pages/[workspace_slug]/[project_slug]/index.tsx
new file mode 100644
index 000000000..220a5b8c7
--- /dev/null
+++ b/space/pages/[workspace_slug]/[project_slug]/index.tsx
@@ -0,0 +1,50 @@
+import useSWR from "swr";
+import type { GetServerSideProps } from "next";
+import { useRouter } from "next/router";
+import Head from "next/head";
+/// layouts
+import ProjectLayout from "layouts/project-layout";
+// components
+import { ProjectDetailsView } from "components/views/project-details";
+// lib
+import { useMobxStore } from "lib/mobx/store-provider";
+
+const WorkspaceProjectPage = (props: any) => {
+ const SITE_TITLE = props?.project_settings?.project_details?.name || "Plane | Deploy";
+
+ const router = useRouter();
+ const { workspace_slug, project_slug, states, labels, priorities } = router.query;
+
+ const { project: projectStore, issue: issueStore } = useMobxStore();
+
+ useSWR("REVALIDATE_ALL", () => {
+ if (workspace_slug && project_slug) {
+ projectStore.fetchProjectSettings(workspace_slug.toString(), project_slug.toString());
+ const params = {
+ state: states || null,
+ labels: labels || null,
+ priority: priorities || null,
+ };
+ issueStore.fetchPublicIssues(workspace_slug.toString(), project_slug.toString(), params);
+ }
+ });
+
+ return (
+
+
+ {SITE_TITLE}
+
+
+
+ );
+};
+
+// export const getServerSideProps: GetServerSideProps
= async ({ query: { workspace_slug, project_slug } }) => {
+// const res = await fetch(
+// `${process.env.NEXT_PUBLIC_API_BASE_URL}/api/public/workspaces/${workspace_slug}/project-boards/${project_slug}/settings/`
+// );
+// const project_settings = await res.json();
+// return { props: { project_settings } };
+// };
+
+export default WorkspaceProjectPage;
diff --git a/apps/space/app/[workspace_slug]/page.tsx b/space/pages/[workspace_slug]/index.tsx
similarity index 92%
rename from apps/space/app/[workspace_slug]/page.tsx
rename to space/pages/[workspace_slug]/index.tsx
index c35662f5a..a844c0763 100644
--- a/apps/space/app/[workspace_slug]/page.tsx
+++ b/space/pages/[workspace_slug]/index.tsx
@@ -1,5 +1,3 @@
-"use client";
-
const WorkspaceProjectPage = () => (
Plane Workspace Space
);
diff --git a/space/pages/_app.tsx b/space/pages/_app.tsx
new file mode 100644
index 000000000..33c137d41
--- /dev/null
+++ b/space/pages/_app.tsx
@@ -0,0 +1,45 @@
+import Head from "next/head";
+import type { AppProps } from "next/app";
+import { ThemeProvider } from "next-themes";
+// styles
+import "styles/globals.css";
+import "styles/editor.css";
+// contexts
+import { ToastContextProvider } from "contexts/toast.context";
+// mobx store provider
+import { MobxStoreProvider } from "lib/mobx/store-provider";
+import MobxStoreInit from "lib/mobx/store-init";
+// constants
+import { SITE_NAME, SITE_DESCRIPTION, SITE_URL, TWITTER_USER_NAME, SITE_KEYWORDS, SITE_TITLE } from "constants/seo";
+
+const prefix = parseInt(process.env.NEXT_PUBLIC_DEPLOY_WITH_NGINX || "0") === 0 ? "/" : "/spaces/";
+
+function MyApp({ Component, pageProps }: AppProps) {
+ return (
+
+
+
+ {SITE_TITLE}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default MyApp;
diff --git a/apps/space/pages/_document.tsx b/space/pages/_document.tsx
similarity index 80%
rename from apps/space/pages/_document.tsx
rename to space/pages/_document.tsx
index 8b41d05fc..ca023f4a4 100644
--- a/apps/space/pages/_document.tsx
+++ b/space/pages/_document.tsx
@@ -5,7 +5,7 @@ class MyDocument extends Document {
return (
-
+
diff --git a/space/pages/index.tsx b/space/pages/index.tsx
new file mode 100644
index 000000000..fe0b7d33a
--- /dev/null
+++ b/space/pages/index.tsx
@@ -0,0 +1,8 @@
+import React from "react";
+
+// components
+import { HomeView } from "components/views";
+
+const HomePage = () =>
;
+
+export default HomePage;
diff --git a/space/pages/onboarding/index.tsx b/space/pages/onboarding/index.tsx
new file mode 100644
index 000000000..1d2f19519
--- /dev/null
+++ b/space/pages/onboarding/index.tsx
@@ -0,0 +1,52 @@
+import React, { useEffect } from "react";
+import Image from "next/image";
+// assets
+import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.svg";
+// mobx
+import { observer } from "mobx-react-lite";
+import { useMobxStore } from "lib/mobx/store-provider";
+// services
+import authenticationService from "services/authentication.service";
+// hooks
+import useToast from "hooks/use-toast";
+// components
+import { OnBoardingForm } from "components/accounts/onboarding-form";
+
+const OnBoardingPage = () => {
+ const { user: userStore } = useMobxStore();
+
+ const user = userStore?.currentUser;
+
+ const { setToastAlert } = useToast();
+
+ useEffect(() => {
+ const user = userStore?.currentUser;
+
+ if (!user) {
+ userStore.fetchCurrentUser();
+ }
+ }, [userStore]);
+
+ return (
+
+
+
+
+
+
+ {user?.email}
+
+
+
+
+
+
+
+ );
+};
+
+export default observer(OnBoardingPage);
diff --git a/apps/space/app/project-not-published/page.tsx b/space/pages/project-not-published/index.tsx
similarity index 87%
rename from apps/space/app/project-not-published/page.tsx
rename to space/pages/project-not-published/index.tsx
index 82a2ff5da..985b7bc41 100644
--- a/apps/space/app/project-not-published/page.tsx
+++ b/space/pages/project-not-published/index.tsx
@@ -1,12 +1,13 @@
// next imports
import Image from "next/image";
+import projectNotPublishedImage from "public/project-not-published.svg";
const CustomProjectNotPublishedError = () => (
-
+
Oops! The page you{`'`}re looking for isn{`'`}t live at the moment.
diff --git a/apps/app/postcss.config.js b/space/postcss.config.js
similarity index 100%
rename from apps/app/postcss.config.js
rename to space/postcss.config.js
diff --git a/apps/app/public/404.svg b/space/public/404.svg
similarity index 100%
rename from apps/app/public/404.svg
rename to space/public/404.svg
diff --git a/apps/app/public/favicon/android-chrome-192x192.png b/space/public/favicon/android-chrome-192x192.png
similarity index 100%
rename from apps/app/public/favicon/android-chrome-192x192.png
rename to space/public/favicon/android-chrome-192x192.png
diff --git a/apps/app/public/favicon/android-chrome-512x512.png b/space/public/favicon/android-chrome-512x512.png
similarity index 100%
rename from apps/app/public/favicon/android-chrome-512x512.png
rename to space/public/favicon/android-chrome-512x512.png
diff --git a/apps/app/public/favicon/apple-touch-icon.png b/space/public/favicon/apple-touch-icon.png
similarity index 100%
rename from apps/app/public/favicon/apple-touch-icon.png
rename to space/public/favicon/apple-touch-icon.png
diff --git a/apps/app/public/favicon/favicon-16x16.png b/space/public/favicon/favicon-16x16.png
similarity index 100%
rename from apps/app/public/favicon/favicon-16x16.png
rename to space/public/favicon/favicon-16x16.png
diff --git a/apps/app/public/favicon/favicon-32x32.png b/space/public/favicon/favicon-32x32.png
similarity index 100%
rename from apps/app/public/favicon/favicon-32x32.png
rename to space/public/favicon/favicon-32x32.png
diff --git a/apps/app/public/favicon/favicon.ico b/space/public/favicon/favicon.ico
similarity index 100%
rename from apps/app/public/favicon/favicon.ico
rename to space/public/favicon/favicon.ico
diff --git a/apps/app/public/favicon/site.webmanifest b/space/public/favicon/site.webmanifest
similarity index 100%
rename from apps/app/public/favicon/site.webmanifest
rename to space/public/favicon/site.webmanifest
diff --git a/space/public/logos/github-black.svg b/space/public/logos/github-black.svg
new file mode 100644
index 000000000..ad04a798e
--- /dev/null
+++ b/space/public/logos/github-black.svg
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
diff --git a/space/public/logos/github-square.svg b/space/public/logos/github-square.svg
new file mode 100644
index 000000000..a7836db8f
--- /dev/null
+++ b/space/public/logos/github-square.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
diff --git a/space/public/logos/github-white.svg b/space/public/logos/github-white.svg
new file mode 100644
index 000000000..90fe34d8b
--- /dev/null
+++ b/space/public/logos/github-white.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/space/public/plane-logo.svg b/space/public/plane-logo.svg
new file mode 100644
index 000000000..11179417c
--- /dev/null
+++ b/space/public/plane-logo.svg
@@ -0,0 +1,94 @@
+
+
+
+
diff --git a/apps/app/public/plane-logos/black-horizontal-with-blue-logo.svg b/space/public/plane-logos/black-horizontal-with-blue-logo.svg
similarity index 100%
rename from apps/app/public/plane-logos/black-horizontal-with-blue-logo.svg
rename to space/public/plane-logos/black-horizontal-with-blue-logo.svg
diff --git a/space/public/plane-logos/blue-without-text.svg b/space/public/plane-logos/blue-without-text.svg
new file mode 100644
index 000000000..715aee503
--- /dev/null
+++ b/space/public/plane-logos/blue-without-text.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/app/public/plane-logos/white-horizontal-with-blue-logo.svg b/space/public/plane-logos/white-horizontal-with-blue-logo.svg
similarity index 100%
rename from apps/app/public/plane-logos/white-horizontal-with-blue-logo.svg
rename to space/public/plane-logos/white-horizontal-with-blue-logo.svg
diff --git a/apps/app/public/plane-logos/white-horizontal.svg b/space/public/plane-logos/white-horizontal.svg
similarity index 100%
rename from apps/app/public/plane-logos/white-horizontal.svg
rename to space/public/plane-logos/white-horizontal.svg
diff --git a/apps/space/public/project-not-published.svg b/space/public/project-not-published.svg
similarity index 100%
rename from apps/space/public/project-not-published.svg
rename to space/public/project-not-published.svg
diff --git a/space/public/site.webmanifest.json b/space/public/site.webmanifest.json
new file mode 100644
index 000000000..4c32ec6e3
--- /dev/null
+++ b/space/public/site.webmanifest.json
@@ -0,0 +1,13 @@
+{
+ "name": "Plane Space",
+ "short_name": "Plane Space",
+ "description": "Plane helps you plan your issues, cycles, and product modules.",
+ "start_url": ".",
+ "display": "standalone",
+ "background_color": "#f9fafb",
+ "theme_color": "#3f76ff",
+ "icons": [
+ { "src": "/favicon/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" },
+ { "src": "/favicon/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" }
+ ]
+}
diff --git a/space/public/something-went-wrong.svg b/space/public/something-went-wrong.svg
new file mode 100644
index 000000000..bd51f7f49
--- /dev/null
+++ b/space/public/something-went-wrong.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/space/public/user-logged-in.svg b/space/public/user-logged-in.svg
new file mode 100644
index 000000000..e20b49e82
--- /dev/null
+++ b/space/public/user-logged-in.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/apps/space/services/api.service.ts b/space/services/api.service.ts
similarity index 87%
rename from apps/space/services/api.service.ts
rename to space/services/api.service.ts
index 4cf26d9ee..d3ad3949b 100644
--- a/apps/space/services/api.service.ts
+++ b/space/services/api.service.ts
@@ -90,6 +90,16 @@ abstract class APIService {
});
}
+ mediaUpload(url: string, data = {}, config = {}): Promise
{
+ return axios({
+ method: "post",
+ url: this.baseURL + url,
+ data,
+ headers: this.getAccessToken() ? { ...this.getHeaders(), "Content-Type": "multipart/form-data" } : {},
+ ...config,
+ });
+ }
+
request(config = {}) {
return axios(config);
}
diff --git a/space/services/authentication.service.ts b/space/services/authentication.service.ts
new file mode 100644
index 000000000..a6f1ec90f
--- /dev/null
+++ b/space/services/authentication.service.ts
@@ -0,0 +1,92 @@
+// services
+import APIService from "services/api.service";
+
+class AuthService extends APIService {
+ constructor() {
+ super(process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
+ }
+
+ async emailLogin(data: any) {
+ return this.post("/api/sign-in/", data, { headers: {} })
+ .then((response) => {
+ this.setAccessToken(response?.data?.access_token);
+ this.setRefreshToken(response?.data?.refresh_token);
+ return response?.data;
+ })
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
+ async emailSignUp(data: { email: string; password: string }) {
+ return this.post("/api/sign-up/", data, { headers: {} })
+ .then((response) => {
+ this.setAccessToken(response?.data?.access_token);
+ this.setRefreshToken(response?.data?.refresh_token);
+ return response?.data;
+ })
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
+ async socialAuth(data: any): Promise<{
+ access_token: string;
+ refresh_toke: string;
+ user: any;
+ }> {
+ return this.post("/api/social-auth/", data, { headers: {} })
+ .then((response) => {
+ this.setAccessToken(response?.data?.access_token);
+ this.setRefreshToken(response?.data?.refresh_token);
+ return response?.data;
+ })
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
+ async emailCode(data: any) {
+ return this.post("/api/magic-generate/", data, { headers: {} })
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
+ async forgotPassword(data: { email: string }): Promise {
+ return this.post(`/api/forgot-password/`, data)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async magicSignIn(data: any) {
+ const response = await this.post("/api/magic-sign-in/", data, { headers: {} });
+ if (response?.status === 200) {
+ this.setAccessToken(response?.data?.access_token);
+ this.setRefreshToken(response?.data?.refresh_token);
+ return response?.data;
+ }
+ throw response.response.data;
+ }
+
+ async signOut() {
+ return this.post("/api/sign-out/", { refresh_token: this.getRefreshToken() })
+ .then((response) => {
+ this.purgeAccessToken();
+ this.purgeRefreshToken();
+ return response?.data;
+ })
+ .catch((error) => {
+ this.purgeAccessToken();
+ this.purgeRefreshToken();
+ throw error?.response?.data;
+ });
+ }
+}
+
+const authService = new AuthService();
+
+export default authService;
diff --git a/space/services/file.service.ts b/space/services/file.service.ts
new file mode 100644
index 000000000..5ef34fc76
--- /dev/null
+++ b/space/services/file.service.ts
@@ -0,0 +1,101 @@
+// services
+import APIService from "services/api.service";
+
+const { NEXT_PUBLIC_API_BASE_URL } = process.env;
+
+interface UnSplashImage {
+ id: string;
+ created_at: Date;
+ updated_at: Date;
+ promoted_at: Date;
+ width: number;
+ height: number;
+ color: string;
+ blur_hash: string;
+ description: null;
+ alt_description: string;
+ urls: UnSplashImageUrls;
+ [key: string]: any;
+}
+
+interface UnSplashImageUrls {
+ raw: string;
+ full: string;
+ regular: string;
+ small: string;
+ thumb: string;
+ small_s3: string;
+}
+
+class FileServices extends APIService {
+ constructor() {
+ super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
+ }
+
+ async uploadFile(workspaceSlug: string, file: FormData): Promise {
+ return this.mediaUpload(`/api/workspaces/${workspaceSlug}/file-assets/`, file)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
+ async deleteImage(assetUrlWithWorkspaceId: string): Promise {
+ return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`)
+ .then((response) => response?.status)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
+ async deleteFile(workspaceId: string, assetUrl: string): Promise {
+ const lastIndex = assetUrl.lastIndexOf("/");
+ const assetId = assetUrl.substring(lastIndex + 1);
+
+ return this.delete(`/api/workspaces/file-assets/${workspaceId}/${assetId}/`)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+ async uploadUserFile(file: FormData): Promise {
+ return this.mediaUpload(`/api/users/file-assets/`, file)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
+ async deleteUserFile(assetUrl: string): Promise {
+ const lastIndex = assetUrl.lastIndexOf("/");
+ const assetId = assetUrl.substring(lastIndex + 1);
+
+ return this.delete(`/api/users/file-assets/${assetId}`)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
+ async getUnsplashImages(page: number = 1, query?: string): Promise {
+ const url = "/api/unsplash";
+
+ return this.request({
+ method: "get",
+ url,
+ params: {
+ page,
+ per_page: 20,
+ query,
+ },
+ })
+ .then((response) => response?.data?.results ?? response?.data)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+}
+
+const fileServices = new FileServices();
+
+export default fileServices;
diff --git a/space/services/issue.service.ts b/space/services/issue.service.ts
new file mode 100644
index 000000000..03a94654b
--- /dev/null
+++ b/space/services/issue.service.ts
@@ -0,0 +1,145 @@
+// services
+import APIService from "services/api.service";
+
+class IssueService extends APIService {
+ constructor() {
+ super(process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
+ }
+
+ async getPublicIssues(workspace_slug: string, project_slug: string, params: any): Promise {
+ return this.get(`/api/public/workspaces/${workspace_slug}/project-boards/${project_slug}/issues/`, {
+ params,
+ })
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async getIssueById(workspaceSlug: string, projectId: string, issueId: string): Promise {
+ return this.get(`/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/`)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async getIssueVotes(workspaceSlug: string, projectId: string, issueId: string): Promise {
+ return this.get(`/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/votes/`)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async createIssueVote(workspaceSlug: string, projectId: string, issueId: string, data: any): Promise {
+ return this.post(
+ `/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/votes/`,
+ data
+ )
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async deleteIssueVote(workspaceSlug: string, projectId: string, issueId: string): Promise {
+ return this.delete(`/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/votes/`)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async getIssueReactions(workspaceSlug: string, projectId: string, issueId: string): Promise {
+ return this.get(`/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/reactions/`)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async createIssueReaction(workspaceSlug: string, projectId: string, issueId: string, data: any): Promise {
+ return this.post(
+ `/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/reactions/`,
+ data
+ )
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async deleteIssueReaction(
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string,
+ reactionId: string
+ ): Promise {
+ return this.delete(
+ `/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/reactions/${reactionId}/`
+ )
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async getIssueComments(workspaceSlug: string, projectId: string, issueId: string): Promise {
+ return this.get(`/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/comments/`)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async getCommentsReactions(workspaceSlug: string, projectId: string, commentId: string): Promise {
+ return this.get(
+ `/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/comments/${commentId}/reactions/`
+ )
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async createIssueComment(workspaceSlug: string, projectId: string, issueId: string, data: any): Promise {
+ return this.post(
+ `/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/comments/`,
+ data
+ )
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async updateIssueComment(
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string,
+ commentId: string,
+ data: any
+ ): Promise {
+ return this.patch(
+ `/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/comments/${commentId}/`,
+ data
+ )
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+
+ async deleteIssueComment(workspaceSlug: string, projectId: string, issueId: string, commentId: string): Promise {
+ return this.delete(
+ `/api/public/workspaces/${workspaceSlug}/project-boards/${projectId}/issues/${issueId}/comments/${commentId}/`
+ )
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
+ }
+}
+
+export default IssueService;
diff --git a/apps/space/services/project.service.ts b/space/services/project.service.ts
similarity index 82%
rename from apps/space/services/project.service.ts
rename to space/services/project.service.ts
index 6f0275877..291a5f323 100644
--- a/apps/space/services/project.service.ts
+++ b/space/services/project.service.ts
@@ -6,7 +6,7 @@ class ProjectService extends APIService {
super(process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
}
- async getProjectSettingsAsync(workspace_slug: string, project_slug: string): Promise {
+ async getProjectSettings(workspace_slug: string, project_slug: string): Promise {
return this.get(`/api/public/workspaces/${workspace_slug}/project-boards/${project_slug}/settings/`)
.then((response) => response?.data)
.catch((error) => {
diff --git a/apps/space/services/user.service.ts b/space/services/user.service.ts
similarity index 66%
rename from apps/space/services/user.service.ts
rename to space/services/user.service.ts
index a84358a96..9a324bb95 100644
--- a/apps/space/services/user.service.ts
+++ b/space/services/user.service.ts
@@ -13,6 +13,14 @@ class UserService extends APIService {
throw error?.response;
});
}
+
+ async updateMe(data: any): Promise {
+ return this.patch("/api/users/me/", data)
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
}
export default UserService;
diff --git a/space/store/issue.ts b/space/store/issue.ts
new file mode 100644
index 000000000..d47336984
--- /dev/null
+++ b/space/store/issue.ts
@@ -0,0 +1,103 @@
+import { observable, action, computed, makeObservable, runInAction, reaction } from "mobx";
+// services
+import IssueService from "services/issue.service";
+// store
+import { RootStore } from "./root";
+// types
+// import { IssueDetailType, TIssueBoardKeys } from "types/issue";
+import { IIssue, IIssueState, IIssueLabel } from "types/issue";
+
+export interface IIssueStore {
+ loader: boolean;
+ error: any;
+ // issue options
+ issues: IIssue[] | null;
+ states: IIssueState[] | null;
+ labels: IIssueLabel[] | null;
+ // filtering
+ filteredStates: string[];
+ filteredLabels: string[];
+ filteredPriorities: string[];
+ // service
+ issueService: any;
+ // actions
+ fetchPublicIssues: (workspace_slug: string, project_slug: string, params: any) => void;
+ getCountOfIssuesByState: (state: string) => number;
+ getFilteredIssuesByState: (state: string) => IIssue[];
+}
+
+class IssueStore implements IIssueStore {
+ loader: boolean = false;
+ error: any | null = null;
+
+ states: IIssueState[] | null = [];
+ labels: IIssueLabel[] | null = [];
+
+ filteredStates: string[] = [];
+ filteredLabels: string[] = [];
+ filteredPriorities: string[] = [];
+
+ issues: IIssue[] | null = [];
+ issue_detail: any = {};
+
+ rootStore: RootStore;
+ issueService: any;
+
+ constructor(_rootStore: any) {
+ makeObservable(this, {
+ // observable
+ loader: observable,
+ error: observable,
+ // issue options
+ states: observable.ref,
+ labels: observable.ref,
+ // filtering
+ filteredStates: observable.ref,
+ filteredLabels: observable.ref,
+ filteredPriorities: observable.ref,
+ // issues
+ issues: observable.ref,
+ issue_detail: observable.ref,
+ // actions
+ fetchPublicIssues: action,
+ getFilteredIssuesByState: action,
+ });
+
+ this.rootStore = _rootStore;
+ this.issueService = new IssueService();
+ }
+
+ fetchPublicIssues = async (workspaceSlug: string, projectId: string, params: any) => {
+ try {
+ this.loader = true;
+ this.error = null;
+
+ const response = await this.issueService.getPublicIssues(workspaceSlug, projectId, params);
+
+ if (response) {
+ const _states: IIssueState[] = [...response?.states];
+ const _labels: IIssueLabel[] = [...response?.labels];
+ const _issues: IIssue[] = [...response?.issues];
+ runInAction(() => {
+ this.states = _states;
+ this.labels = _labels;
+ this.issues = _issues;
+ this.loader = false;
+ });
+ }
+ } catch (error) {
+ this.loader = false;
+ this.error = error;
+ }
+ };
+
+ // computed
+ getCountOfIssuesByState(state_id: string): number {
+ return this.issues?.filter((issue) => issue.state == state_id).length || 0;
+ }
+
+ getFilteredIssuesByState = (state_id: string): IIssue[] | [] =>
+ this.issues?.filter((issue) => issue.state == state_id) || [];
+}
+
+export default IssueStore;
diff --git a/space/store/issue_details.ts b/space/store/issue_details.ts
new file mode 100644
index 000000000..10679cf17
--- /dev/null
+++ b/space/store/issue_details.ts
@@ -0,0 +1,320 @@
+import { makeObservable, observable, action, runInAction } from "mobx";
+import { v4 as uuidv4 } from "uuid";
+// store
+import { RootStore } from "./root";
+// services
+import IssueService from "services/issue.service";
+import { IIssue, IVote } from "types/issue";
+
+export type IPeekMode = "side" | "modal" | "full";
+
+export interface IIssueDetailStore {
+ loader: boolean;
+ error: any;
+ // peek info
+ peekId: string | null;
+ peekMode: IPeekMode;
+ details: {
+ [key: string]: IIssue;
+ };
+ // peek actions
+ setPeekId: (issueId: string | null) => void;
+ setPeekMode: (mode: IPeekMode) => void;
+ // issue details
+ fetchIssueDetails: (workspaceId: string, projectId: string, issueId: string) => void;
+ // issue comments
+ addIssueComment: (workspaceId: string, projectId: string, issueId: string, data: any) => Promise;
+ updateIssueComment: (
+ workspaceId: string,
+ projectId: string,
+ issueId: string,
+ comment_id: string,
+ data: any
+ ) => Promise;
+ deleteIssueComment: (workspaceId: string, projectId: string, issueId: string, comment_id: string) => void;
+ // issue reactions
+ addIssueReaction: (workspaceId: string, projectId: string, issueId: string, reactionHex: string) => void;
+ removeIssueReaction: (workspaceId: string, projectId: string, issueId: string, reactionHex: string) => void;
+ // issue votes
+ addIssueVote: (workspaceId: string, projectId: string, issueId: string, data: { vote: 1 | -1 }) => Promise;
+ removeIssueVote: (workspaceId: string, projectId: string, issueId: string) => Promise;
+}
+
+class IssueDetailStore implements IssueDetailStore {
+ loader: boolean = false;
+ error: any = null;
+ peekId: string | null = null;
+ peekMode: IPeekMode = "side";
+ details: {
+ [key: string]: IIssue;
+ } = {};
+ issueService;
+ rootStore: RootStore;
+
+ constructor(_rootStore: RootStore) {
+ makeObservable(this, {
+ loader: observable.ref,
+ error: observable.ref,
+ // peek
+ peekId: observable.ref,
+ peekMode: observable.ref,
+ details: observable.ref,
+ // actions
+ setPeekId: action,
+ fetchIssueDetails: action,
+ setPeekMode: action,
+ });
+ this.issueService = new IssueService();
+ this.rootStore = _rootStore;
+ }
+
+ setPeekId = (issueId: string | null) => {
+ this.peekId = issueId;
+ };
+
+ setPeekMode = (mode: IPeekMode) => {
+ this.peekMode = mode;
+ };
+
+ fetchIssueDetails = async (workspaceSlug: string, projectId: string, issueId: string) => {
+ try {
+ this.loader = true;
+ this.error = null;
+
+ const issueDetails = this.rootStore.issue.issues?.find((i) => i.id === issueId);
+ const commentsResponse = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId);
+
+ if (issueDetails) {
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...(this.details[issueId] ?? issueDetails),
+ comments: commentsResponse,
+ },
+ };
+ });
+ }
+ } catch (error) {
+ this.loader = false;
+ this.error = error;
+ }
+ };
+
+ addIssueComment = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => {
+ try {
+ const issueDetails = this.rootStore.issue.issues?.find((i) => i.id === issueId);
+ const issueCommentResponse = await this.issueService.createIssueComment(workspaceSlug, projectId, issueId, data);
+ if (issueDetails) {
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...issueDetails,
+ comments: [...this.details[issueId].comments, issueCommentResponse],
+ },
+ };
+ });
+ }
+ return issueCommentResponse;
+ } catch (error) {
+ console.log("Failed to add issue comment");
+ throw error;
+ }
+ };
+
+ updateIssueComment = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string,
+ commentId: string,
+ data: any
+ ) => {
+ try {
+ const issueCommentUpdateResponse = await this.issueService.updateIssueComment(
+ workspaceSlug,
+ projectId,
+ issueId,
+ commentId,
+ data
+ );
+
+ if (issueCommentUpdateResponse) {
+ const remainingComments = this.details[issueId].comments.filter((com) => com.id != commentId);
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ comments: [...remainingComments, issueCommentUpdateResponse],
+ },
+ };
+ });
+ }
+ return issueCommentUpdateResponse;
+ } catch (error) {
+ console.log("Failed to add issue comment");
+ }
+ };
+
+ deleteIssueComment = async (workspaceSlug: string, projectId: string, issueId: string, comment_id: string) => {
+ try {
+ await this.issueService.deleteIssueComment(workspaceSlug, projectId, issueId, comment_id);
+ const remainingComments = this.details[issueId].comments.filter((c) => c.id != comment_id);
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ comments: remainingComments,
+ },
+ };
+ });
+ } catch (error) {
+ console.log("Failed to add issue vote");
+ }
+ };
+
+ addIssueReaction = async (workspaceSlug: string, projectId: string, issueId: string, reactionHex: string) => {
+ try {
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ reactions: [
+ ...this.details[issueId].reactions,
+ {
+ id: uuidv4(),
+ issue: issueId,
+ reaction: reactionHex,
+ actor_detail: this.rootStore.user.currentActor,
+ },
+ ],
+ },
+ };
+ });
+
+ await this.issueService.createIssueReaction(workspaceSlug, projectId, issueId, {
+ reaction: reactionHex,
+ });
+ } catch (error) {
+ console.log("Failed to add issue vote");
+ const issueReactions = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId);
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ reactions: issueReactions,
+ },
+ };
+ });
+ }
+ };
+
+ removeIssueReaction = async (workspaceSlug: string, projectId: string, issueId: string, reactionHex: string) => {
+ try {
+ const newReactions = this.details[issueId].reactions.filter(
+ (_r) => !(_r.reaction === reactionHex && _r.actor_detail.id === this.rootStore.user.currentUser?.id)
+ );
+
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ reactions: newReactions,
+ },
+ };
+ });
+
+ await this.issueService.deleteIssueReaction(workspaceSlug, projectId, issueId, reactionHex);
+ } catch (error) {
+ console.log("Failed to remove issue reaction");
+ const reactions = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId);
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ reactions: reactions,
+ },
+ };
+ });
+ }
+ };
+
+ addIssueVote = async (workspaceSlug: string, projectId: string, issueId: string, data: { vote: 1 | -1 }) => {
+ const newVote: IVote = {
+ actor: this.rootStore.user.currentUser?.id ?? "",
+ actor_detail: this.rootStore.user.currentActor,
+ issue: issueId,
+ project: projectId,
+ workspace: workspaceSlug,
+ vote: data.vote,
+ };
+
+ const filteredVotes = this.details[issueId].votes.filter((v) => v.actor !== this.rootStore.user.currentUser?.id);
+
+ try {
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ votes: [...filteredVotes, newVote],
+ },
+ };
+ });
+
+ await this.issueService.createIssueVote(workspaceSlug, projectId, issueId, data);
+ } catch (error) {
+ console.log("Failed to add issue vote");
+ const issueVotes = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId);
+
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ votes: issueVotes,
+ },
+ };
+ });
+ }
+ };
+
+ removeIssueVote = async (workspaceSlug: string, projectId: string, issueId: string) => {
+ const newVotes = this.details[issueId].votes.filter((v) => v.actor !== this.rootStore.user.currentUser?.id);
+
+ try {
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ votes: newVotes,
+ },
+ };
+ });
+
+ await this.issueService.deleteIssueVote(workspaceSlug, projectId, issueId);
+ } catch (error) {
+ console.log("Failed to remove issue vote");
+ const issueVotes = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId);
+
+ runInAction(() => {
+ this.details = {
+ ...this.details,
+ [issueId]: {
+ ...this.details[issueId],
+ votes: issueVotes,
+ },
+ };
+ });
+ }
+ };
+}
+
+export default IssueDetailStore;
diff --git a/apps/space/store/project.ts b/space/store/project.ts
similarity index 52%
rename from apps/space/store/project.ts
rename to space/store/project.ts
index e5ac58261..ddd589f9a 100644
--- a/apps/space/store/project.ts
+++ b/space/store/project.ts
@@ -3,15 +3,29 @@ import { observable, action, makeObservable, runInAction } from "mobx";
// service
import ProjectService from "services/project.service";
// types
-import { IProjectStore, IWorkspace, IProject, IProjectSettings } from "./types";
+import { IWorkspace, IProject, IProjectSettings } from "types/project";
+
+export interface IProjectStore {
+ loader: boolean;
+ error: any | null;
+ workspace: IWorkspace | null;
+ project: IProject | null;
+ deploySettings: IProjectSettings | null;
+ viewOptions: any;
+ activeBoard: string | null;
+ fetchProjectSettings: (workspace_slug: string, project_slug: string) => Promise;
+ setActiveBoard: (value: string) => void;
+}
class ProjectStore implements IProjectStore {
loader: boolean = false;
error: any | null = null;
-
+ // data
workspace: IWorkspace | null = null;
project: IProject | null = null;
- workspaceProjectSettings: IProjectSettings | null = null;
+ deploySettings: IProjectSettings | null = null;
+ viewOptions: any = null;
+ activeBoard: string | null = null;
// root store
rootStore;
// service
@@ -19,14 +33,18 @@ class ProjectStore implements IProjectStore {
constructor(_rootStore: any | null = null) {
makeObservable(this, {
+ // loaders and error observables
+ loader: observable,
+ error: observable.ref,
// observable
workspace: observable.ref,
project: observable.ref,
- workspaceProjectSettings: observable.ref,
- loader: observable,
- error: observable.ref,
- // action
- getProjectSettingsAsync: action,
+ deploySettings: observable.ref,
+ viewOptions: observable.ref,
+ activeBoard: observable.ref,
+ // actions
+ fetchProjectSettings: action,
+ setActiveBoard: action,
// computed
});
@@ -34,26 +52,23 @@ class ProjectStore implements IProjectStore {
this.projectService = new ProjectService();
}
- getProjectSettingsAsync = async (workspace_slug: string, project_slug: string) => {
+ fetchProjectSettings = async (workspace_slug: string, project_slug: string) => {
try {
this.loader = true;
this.error = null;
- const response = await this.projectService.getProjectSettingsAsync(workspace_slug, project_slug);
+ const response = await this.projectService.getProjectSettings(workspace_slug, project_slug);
if (response) {
const _project: IProject = { ...response?.project_details };
const _workspace: IWorkspace = { ...response?.workspace_detail };
- const _workspaceProjectSettings: IProjectSettings = {
- comments: response?.comments,
- reactions: response?.reactions,
- votes: response?.votes,
- views: { ...response?.views },
- };
+ const _viewOptions = { ...response?.views };
+ const _deploySettings = { ...response };
runInAction(() => {
this.project = _project;
this.workspace = _workspace;
- this.workspaceProjectSettings = _workspaceProjectSettings;
+ this.viewOptions = _viewOptions;
+ this.deploySettings = _deploySettings;
this.loader = false;
});
}
@@ -64,6 +79,10 @@ class ProjectStore implements IProjectStore {
return error;
}
};
+
+ setActiveBoard = (boardValue: string) => {
+ this.activeBoard = boardValue;
+ };
}
export default ProjectStore;
diff --git a/apps/space/store/root.ts b/space/store/root.ts
similarity index 57%
rename from apps/space/store/root.ts
rename to space/store/root.ts
index dd6d620c0..6b87020ef 100644
--- a/apps/space/store/root.ts
+++ b/space/store/root.ts
@@ -2,24 +2,22 @@
import { enableStaticRendering } from "mobx-react-lite";
// store imports
import UserStore from "./user";
-import ThemeStore from "./theme";
-import IssueStore from "./issue";
-import ProjectStore from "./project";
-// types
-import { IIssueStore, IProjectStore, IThemeStore, IUserStore } from "./types";
+import IssueStore, { IIssueStore } from "./issue";
+import ProjectStore, { IProjectStore } from "./project";
+import IssueDetailStore, { IIssueDetailStore } from "./issue_details";
enableStaticRendering(typeof window === "undefined");
export class RootStore {
- user: IUserStore;
- theme: IThemeStore;
+ user: UserStore;
issue: IIssueStore;
+ issueDetails: IIssueDetailStore;
project: IProjectStore;
constructor() {
this.user = new UserStore(this);
- this.theme = new ThemeStore(this);
this.issue = new IssueStore(this);
this.project = new ProjectStore(this);
+ this.issueDetails = new IssueDetailStore(this);
}
}
diff --git a/space/store/user.ts b/space/store/user.ts
new file mode 100644
index 000000000..8d34b0bdc
--- /dev/null
+++ b/space/store/user.ts
@@ -0,0 +1,92 @@
+// mobx
+import { observable, action, computed, makeObservable, runInAction } from "mobx";
+// service
+import UserService from "services/user.service";
+import { ActorDetail } from "types/issue";
+// types
+import { IUser } from "types/user";
+
+export interface IUserStore {
+ currentUser: any | null;
+ fetchCurrentUser: () => void;
+ currentActor: () => any;
+}
+
+class UserStore implements IUserStore {
+ currentUser: IUser | null = null;
+ // root store
+ rootStore;
+ // service
+ userService;
+
+ constructor(_rootStore: any) {
+ makeObservable(this, {
+ // observable
+ currentUser: observable.ref,
+ // actions
+ setCurrentUser: action,
+ // computed
+ currentActor: computed,
+ });
+ this.rootStore = _rootStore;
+ this.userService = new UserService();
+ }
+
+ setCurrentUser = (user: any) => {
+ runInAction(() => {
+ this.currentUser = { ...user };
+ });
+ };
+
+ get currentActor(): any {
+ return {
+ avatar: this.currentUser?.avatar,
+ display_name: this.currentUser?.display_name,
+ first_name: this.currentUser?.first_name,
+ id: this.currentUser?.id,
+ is_bot: false,
+ last_name: this.currentUser?.last_name,
+ };
+ }
+
+ /**
+ *
+ * @param callback
+ * @description A wrapper function to check user authentication; it redirects to the login page if not authenticated, otherwise, it executes a callback.
+ * @example this.requiredLogin(() => { // do something });
+ */
+
+ requiredLogin = (callback: () => void) => {
+ if (this.currentUser) {
+ callback();
+ return;
+ }
+
+ this.fetchCurrentUser()
+ .then(() => {
+ if (!this.currentUser) {
+ const currentPath = window.location.pathname;
+ window.location.href = `/?next_path=${currentPath}`;
+ } else callback();
+ })
+ .catch(() => {
+ const currentPath = window.location.pathname;
+ window.location.href = `/?next_path=${currentPath}`;
+ });
+ };
+
+ fetchCurrentUser = async () => {
+ try {
+ const response = await this.userService.currentUser();
+ if (response) {
+ runInAction(() => {
+ this.currentUser = response;
+ });
+ }
+ } catch (error) {
+ console.error("Failed to fetch current user", error);
+ }
+ };
+}
+
+export default UserStore;
diff --git a/apps/app/styles/editor.css b/space/styles/editor.css
similarity index 66%
rename from apps/app/styles/editor.css
rename to space/styles/editor.css
index 57c23c911..9da250dd1 100644
--- a/apps/app/styles/editor.css
+++ b/space/styles/editor.css
@@ -30,6 +30,10 @@
}
}
+.ProseMirror-gapcursor:after {
+ border-top: 1px solid rgb(var(--color-text-100)) !important;
+}
+
/* Custom TODO list checkboxes – shoutout to this awesome tutorial: https://moderncss.dev/pure-css-custom-checkbox-style/ */
ul[data-type="taskList"] li > label {
@@ -140,7 +144,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
height: 20px;
border-radius: 50%;
border: 3px solid rgba(var(--color-text-200));
- border-top-color: rgba(var(--color-text-800));
+ border-top-color: rgba(var(--color-text-800));
animation: spinning 0.6s linear infinite;
}
}
@@ -150,3 +154,78 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
transform: rotate(360deg);
}
}
+
+#tiptap-container {
+ table {
+ border-collapse: collapse;
+ table-layout: fixed;
+ margin: 0;
+ border: 1px solid rgb(var(--color-border-200));
+ width: 100%;
+
+ td,
+ th {
+ min-width: 1em;
+ border: 1px solid rgb(var(--color-border-200));
+ padding: 10px 15px;
+ vertical-align: top;
+ box-sizing: border-box;
+ position: relative;
+ transition: background-color 0.3s ease;
+
+ > * {
+ margin-bottom: 0;
+ }
+ }
+
+ th {
+ font-weight: bold;
+ text-align: left;
+ background-color: rgb(var(--color-primary-100));
+ }
+
+ td:hover {
+ background-color: rgba(var(--color-primary-300), 0.1);
+ }
+
+ .selectedCell:after {
+ z-index: 2;
+ position: absolute;
+ content: "";
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ background-color: rgba(var(--color-primary-300), 0.1);
+ pointer-events: none;
+ }
+
+ .column-resize-handle {
+ position: absolute;
+ right: -2px;
+ top: 0;
+ bottom: -2px;
+ width: 2px;
+ background-color: rgb(var(--color-primary-400));
+ pointer-events: none;
+ }
+ }
+}
+
+.tableWrapper {
+ overflow-x: auto;
+}
+
+.resize-cursor {
+ cursor: ew-resize;
+ cursor: col-resize;
+}
+
+.ProseMirror table * p {
+ padding: 0px 1px;
+ margin: 6px 2px;
+}
+
+.ProseMirror table * .is-empty::before {
+ opacity: 0;
+}
diff --git a/space/styles/globals.css b/space/styles/globals.css
new file mode 100644
index 000000000..1782b9b81
--- /dev/null
+++ b/space/styles/globals.css
@@ -0,0 +1,234 @@
+@import url("https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700;800&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,0,0&display=swap");
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ html {
+ font-family: "Inter", sans-serif;
+ }
+
+ :root {
+ color-scheme: light !important;
+
+ --color-primary-10: 236, 241, 255;
+ --color-primary-20: 217, 228, 255;
+ --color-primary-30: 197, 214, 255;
+ --color-primary-40: 178, 200, 255;
+ --color-primary-50: 159, 187, 255;
+ --color-primary-60: 140, 173, 255;
+ --color-primary-70: 121, 159, 255;
+ --color-primary-80: 101, 145, 255;
+ --color-primary-90: 82, 132, 255;
+ --color-primary-100: 63, 118, 255;
+ --color-primary-200: 57, 106, 230;
+ --color-primary-300: 50, 94, 204;
+ --color-primary-400: 44, 83, 179;
+ --color-primary-500: 38, 71, 153;
+ --color-primary-600: 32, 59, 128;
+ --color-primary-700: 25, 47, 102;
+ --color-primary-800: 19, 35, 76;
+ --color-primary-900: 13, 24, 51;
+
+ --color-background-100: 255, 255, 255; /* primary bg */
+ --color-background-90: 250, 250, 250; /* secondary bg */
+ --color-background-80: 245, 245, 245; /* tertiary bg */
+
+ --color-text-100: 23, 23, 23; /* primary text */
+ --color-text-200: 58, 58, 58; /* secondary text */
+ --color-text-300: 82, 82, 82; /* tertiary text */
+ --color-text-400: 163, 163, 163; /* placeholder text */
+
+ --color-border-100: 245, 245, 245; /* subtle border= 1 */
+ --color-border-200: 229, 229, 229; /* subtle border- 2 */
+ --color-border-300: 212, 212, 212; /* strong border- 1 */
+ --color-border-400: 185, 185, 185; /* strong border- 2 */
+
+ --color-shadow-2xs: 0px 0px 1px 0px rgba(23, 23, 23, 0.06), 0px 1px 2px 0px rgba(23, 23, 23, 0.06),
+ 0px 1px 2px 0px rgba(23, 23, 23, 0.14);
+ --color-shadow-xs: 0px 1px 2px 0px rgba(0, 0, 0, 0.16), 0px 2px 4px 0px rgba(16, 24, 40, 0.12),
+ 0px 1px 8px -1px rgba(16, 24, 40, 0.1);
+ --color-shadow-sm: 0px 1px 4px 0px rgba(0, 0, 0, 0.01), 0px 4px 8px 0px rgba(0, 0, 0, 0.02),
+ 0px 1px 12px 0px rgba(0, 0, 0, 0.12);
+ --color-shadow-rg: 0px 3px 6px 0px rgba(0, 0, 0, 0.1), 0px 4px 4px 0px rgba(16, 24, 40, 0.08),
+ 0px 1px 12px 0px rgba(16, 24, 40, 0.04);
+ --color-shadow-md: 0px 4px 8px 0px rgba(0, 0, 0, 0.12), 0px 6px 12px 0px rgba(16, 24, 40, 0.12),
+ 0px 1px 16px 0px rgba(16, 24, 40, 0.12);
+ --color-shadow-lg: 0px 6px 12px 0px rgba(0, 0, 0, 0.12), 0px 8px 16px 0px rgba(0, 0, 0, 0.12),
+ 0px 1px 24px 0px rgba(16, 24, 40, 0.12);
+ --color-shadow-xl: 0px 0px 18px 0px rgba(0, 0, 0, 0.16), 0px 0px 24px 0px rgba(16, 24, 40, 0.16),
+ 0px 0px 52px 0px rgba(16, 24, 40, 0.16);
+ --color-shadow-2xl: 0px 8px 16px 0px rgba(0, 0, 0, 0.12), 0px 12px 24px 0px rgba(16, 24, 40, 0.12),
+ 0px 1px 32px 0px rgba(16, 24, 40, 0.12);
+ --color-shadow-3xl: 0px 12px 24px 0px rgba(0, 0, 0, 0.12), 0px 16px 32px 0px rgba(0, 0, 0, 0.12),
+ 0px 1px 48px 0px rgba(16, 24, 40, 0.12);
+
+ --color-sidebar-background-100: var(--color-background-100); /* primary sidebar bg */
+ --color-sidebar-background-90: var(--color-background-90); /* secondary sidebar bg */
+ --color-sidebar-background-80: var(--color-background-80); /* tertiary sidebar bg */
+
+ --color-sidebar-text-100: var(--color-text-100); /* primary sidebar text */
+ --color-sidebar-text-200: var(--color-text-200); /* secondary sidebar text */
+ --color-sidebar-text-300: var(--color-text-300); /* tertiary sidebar text */
+ --color-sidebar-text-400: var(--color-text-400); /* sidebar placeholder text */
+
+ --color-sidebar-border-100: var(--color-border-100); /* subtle sidebar border= 1 */
+ --color-sidebar-border-200: var(--color-border-100); /* subtle sidebar border- 2 */
+ --color-sidebar-border-300: var(--color-border-100); /* strong sidebar border- 1 */
+ --color-sidebar-border-400: var(--color-border-100); /* strong sidebar border- 2 */
+
+ --color-sidebar-shadow-2xs: var(--color-shadow-2xs);
+ --color-sidebar-shadow-xs: var(--color-shadow-xs);
+ --color-sidebar-shadow-sm: var(--color-shadow-sm);
+ --color-sidebar-shadow-rg: var(--color-shadow-rg);
+ --color-sidebar-shadow-md: var(--color-shadow-md);
+ --color-sidebar-shadow-lg: var(--color-shadow-lg);
+ --color-sidebar-shadow-xl: var(--color-shadow-xl);
+ --color-sidebar-shadow-2xl: var(--color-shadow-2xl);
+ --color-sidebar-shadow-3xl: var(--color-shadow-3xl);
+ }
+
+ [data-theme="light"],
+ [data-theme="light-contrast"] {
+ color-scheme: light !important;
+
+ --color-background-100: 255, 255, 255; /* primary bg */
+ --color-background-90: 250, 250, 250; /* secondary bg */
+ --color-background-80: 245, 245, 245; /* tertiary bg */
+ }
+
+ [data-theme="light"] {
+ --color-text-100: 23, 23, 23; /* primary text */
+ --color-text-200: 58, 58, 58; /* secondary text */
+ --color-text-300: 82, 82, 82; /* tertiary text */
+ --color-text-400: 163, 163, 163; /* placeholder text */
+
+ --color-border-100: 245, 245, 245; /* subtle border= 1 */
+ --color-border-200: 229, 229, 229; /* subtle border- 2 */
+ --color-border-300: 212, 212, 212; /* strong border- 1 */
+ --color-border-400: 185, 185, 185; /* strong border- 2 */
+ }
+
+ [data-theme="light-contrast"] {
+ --color-text-100: 11, 11, 11; /* primary text */
+ --color-text-200: 38, 38, 38; /* secondary text */
+ --color-text-300: 58, 58, 58; /* tertiary text */
+ --color-text-400: 115, 115, 115; /* placeholder text */
+
+ --color-border-100: 34, 34, 34; /* subtle border= 1 */
+ --color-border-200: 38, 38, 38; /* subtle border- 2 */
+ --color-border-300: 46, 46, 46; /* strong border- 1 */
+ --color-border-400: 58, 58, 58; /* strong border- 2 */
+ }
+
+ [data-theme="dark"],
+ [data-theme="dark-contrast"] {
+ color-scheme: dark !important;
+
+ --color-background-100: 7, 7, 7; /* primary bg */
+ --color-background-90: 11, 11, 11; /* secondary bg */
+ --color-background-80: 23, 23, 23; /* tertiary bg */
+
+ --color-shadow-2xs: 0px 0px 1px 0px rgba(0, 0, 0, 0.15), 0px 1px 3px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-xs: 0px 0px 2px 0px rgba(0, 0, 0, 0.2), 0px 2px 4px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-sm: 0px 0px 4px 0px rgba(0, 0, 0, 0.2), 0px 2px 6px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-rg: 0px 0px 6px 0px rgba(0, 0, 0, 0.2), 0px 4px 6px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-md: 0px 2px 8px 0px rgba(0, 0, 0, 0.2), 0px 4px 8px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-lg: 0px 4px 12px 0px rgba(0, 0, 0, 0.25), 0px 4px 10px 0px rgba(0, 0, 0, 0.55);
+ --color-shadow-xl: 0px 0px 14px 0px rgba(0, 0, 0, 0.25), 0px 6px 10px 0px rgba(0, 0, 0, 0.55);
+ --color-shadow-2xl: 0px 0px 18px 0px rgba(0, 0, 0, 0.25), 0px 8px 12px 0px rgba(0, 0, 0, 0.6);
+ --color-shadow-3xl: 0px 4px 24px 0px rgba(0, 0, 0, 0.3), 0px 12px 40px 0px rgba(0, 0, 0, 0.65);
+ }
+
+ [data-theme="dark"] {
+ --color-text-100: 229, 229, 229; /* primary text */
+ --color-text-200: 163, 163, 163; /* secondary text */
+ --color-text-300: 115, 115, 115; /* tertiary text */
+ --color-text-400: 82, 82, 82; /* placeholder text */
+
+ --color-border-100: 34, 34, 34; /* subtle border= 1 */
+ --color-border-200: 38, 38, 38; /* subtle border- 2 */
+ --color-border-300: 46, 46, 46; /* strong border- 1 */
+ --color-border-400: 58, 58, 58; /* strong border- 2 */
+ }
+
+ [data-theme="dark-contrast"] {
+ --color-text-100: 250, 250, 250; /* primary text */
+ --color-text-200: 241, 241, 241; /* secondary text */
+ --color-text-300: 212, 212, 212; /* tertiary text */
+ --color-text-400: 115, 115, 115; /* placeholder text */
+
+ --color-border-100: 245, 245, 245; /* subtle border= 1 */
+ --color-border-200: 229, 229, 229; /* subtle border- 2 */
+ --color-border-300: 212, 212, 212; /* strong border- 1 */
+ --color-border-400: 185, 185, 185; /* strong border- 2 */
+ }
+
+ [data-theme="light"],
+ [data-theme="dark"],
+ [data-theme="light-contrast"],
+ [data-theme="dark-contrast"] {
+ --color-primary-10: 236, 241, 255;
+ --color-primary-20: 217, 228, 255;
+ --color-primary-30: 197, 214, 255;
+ --color-primary-40: 178, 200, 255;
+ --color-primary-50: 159, 187, 255;
+ --color-primary-60: 140, 173, 255;
+ --color-primary-70: 121, 159, 255;
+ --color-primary-80: 101, 145, 255;
+ --color-primary-90: 82, 132, 255;
+ --color-primary-100: 63, 118, 255;
+ --color-primary-200: 57, 106, 230;
+ --color-primary-300: 50, 94, 204;
+ --color-primary-400: 44, 83, 179;
+ --color-primary-500: 38, 71, 153;
+ --color-primary-600: 32, 59, 128;
+ --color-primary-700: 25, 47, 102;
+ --color-primary-800: 19, 35, 76;
+ --color-primary-900: 13, 24, 51;
+
+ --color-sidebar-background-100: var(--color-background-100); /* primary sidebar bg */
+ --color-sidebar-background-90: var(--color-background-90); /* secondary sidebar bg */
+ --color-sidebar-background-80: var(--color-background-80); /* tertiary sidebar bg */
+
+ --color-sidebar-text-100: var(--color-text-100); /* primary sidebar text */
+ --color-sidebar-text-200: var(--color-text-200); /* secondary sidebar text */
+ --color-sidebar-text-300: var(--color-text-300); /* tertiary sidebar text */
+ --color-sidebar-text-400: var(--color-text-400); /* sidebar placeholder text */
+
+ --color-sidebar-border-100: var(--color-border-100); /* subtle sidebar border= 1 */
+ --color-sidebar-border-200: var(--color-border-100); /* subtle sidebar border- 2 */
+ --color-sidebar-border-300: var(--color-border-100); /* strong sidebar border- 1 */
+ --color-sidebar-border-400: var(--color-border-100); /* strong sidebar border- 2 */
+ }
+}
+
+::-webkit-scrollbar {
+ width: 5px;
+ height: 5px;
+ border-radius: 5px;
+}
+
+::-webkit-scrollbar-track {
+ background-color: rgba(var(--color-background-100));
+}
+
+::-webkit-scrollbar-thumb {
+ border-radius: 5px;
+ background-color: rgba(var(--color-background-80));
+}
+
+.hide-vertical-scrollbar::-webkit-scrollbar {
+ width: 0 !important;
+}
+
+.hide-horizontal-scrollbar::-webkit-scrollbar {
+ height: 0 !important;
+}
+
+.hide-both-scrollbars::-webkit-scrollbar {
+ height: 0 !important;
+ width: 0 !important;
+}
diff --git a/space/tailwind.config.js b/space/tailwind.config.js
new file mode 100644
index 000000000..0347ad9f9
--- /dev/null
+++ b/space/tailwind.config.js
@@ -0,0 +1,203 @@
+/** @type {import('tailwindcss').Config} */
+
+const convertToRGB = (variableName) => `rgba(var(${variableName}))`;
+
+module.exports = {
+ content: [
+ "./app/**/*.{js,ts,jsx,tsx}",
+ "./pages/**/*.{js,ts,jsx,tsx}",
+ "./layouts/**/*.tsx",
+ "./components/**/*.{js,ts,jsx,tsx}",
+ "./constants/**/*.{js,ts,jsx,tsx}",
+ ],
+ theme: {
+ extend: {
+ boxShadow: {
+ "custom-shadow-2xs": "var(--color-shadow-2xs)",
+ "custom-shadow-xs": "var(--color-shadow-xs)",
+ "custom-shadow-sm": "var(--color-shadow-sm)",
+ "custom-shadow-rg": "var(--color-shadow-rg)",
+ "custom-shadow-md": "var(--color-shadow-md)",
+ "custom-shadow-lg": "var(--color-shadow-lg)",
+ "custom-shadow-xl": "var(--color-shadow-xl)",
+ "custom-shadow-2xl": "var(--color-shadow-2xl)",
+ "custom-shadow-3xl": "var(--color-shadow-3xl)",
+ "custom-sidebar-shadow-2xs": "var(--color-sidebar-shadow-2xs)",
+ "custom-sidebar-shadow-xs": "var(--color-sidebar-shadow-xs)",
+ "custom-sidebar-shadow-sm": "var(--color-sidebar-shadow-sm)",
+ "custom-sidebar-shadow-rg": "var(--color-sidebar-shadow-rg)",
+ "custom-sidebar-shadow-md": "var(--color-sidebar-shadow-md)",
+ "custom-sidebar-shadow-lg": "var(--color-sidebar-shadow-lg)",
+ "custom-sidebar-shadow-xl": "var(--color-sidebar-shadow-xl)",
+ "custom-sidebar-shadow-2xl": "var(--color-sidebar-shadow-2xl)",
+ "custom-sidebar-shadow-3xl": "var(--color-sidebar-shadow-3xl)",
+ },
+ colors: {
+ custom: {
+ primary: {
+ 0: "rgb(255, 255, 255)",
+ 10: convertToRGB("--color-primary-10"),
+ 20: convertToRGB("--color-primary-20"),
+ 30: convertToRGB("--color-primary-30"),
+ 40: convertToRGB("--color-primary-40"),
+ 50: convertToRGB("--color-primary-50"),
+ 60: convertToRGB("--color-primary-60"),
+ 70: convertToRGB("--color-primary-70"),
+ 80: convertToRGB("--color-primary-80"),
+ 90: convertToRGB("--color-primary-90"),
+ 100: convertToRGB("--color-primary-100"),
+ 200: convertToRGB("--color-primary-200"),
+ 300: convertToRGB("--color-primary-300"),
+ 400: convertToRGB("--color-primary-400"),
+ 500: convertToRGB("--color-primary-500"),
+ 600: convertToRGB("--color-primary-600"),
+ 700: convertToRGB("--color-primary-700"),
+ 800: convertToRGB("--color-primary-800"),
+ 900: convertToRGB("--color-primary-900"),
+ 1000: "rgb(0, 0, 0)",
+ DEFAULT: convertToRGB("--color-primary-100"),
+ },
+ background: {
+ 0: "rgb(255, 255, 255)",
+ 10: convertToRGB("--color-background-10"),
+ 20: convertToRGB("--color-background-20"),
+ 30: convertToRGB("--color-background-30"),
+ 40: convertToRGB("--color-background-40"),
+ 50: convertToRGB("--color-background-50"),
+ 60: convertToRGB("--color-background-60"),
+ 70: convertToRGB("--color-background-70"),
+ 80: convertToRGB("--color-background-80"),
+ 90: convertToRGB("--color-background-90"),
+ 100: convertToRGB("--color-background-100"),
+ 200: convertToRGB("--color-background-200"),
+ 300: convertToRGB("--color-background-300"),
+ 400: convertToRGB("--color-background-400"),
+ 500: convertToRGB("--color-background-500"),
+ 600: convertToRGB("--color-background-600"),
+ 700: convertToRGB("--color-background-700"),
+ 800: convertToRGB("--color-background-800"),
+ 900: convertToRGB("--color-background-900"),
+ 1000: "rgb(0, 0, 0)",
+ DEFAULT: convertToRGB("--color-background-100"),
+ },
+ text: {
+ 0: "rgb(255, 255, 255)",
+ 10: convertToRGB("--color-text-10"),
+ 20: convertToRGB("--color-text-20"),
+ 30: convertToRGB("--color-text-30"),
+ 40: convertToRGB("--color-text-40"),
+ 50: convertToRGB("--color-text-50"),
+ 60: convertToRGB("--color-text-60"),
+ 70: convertToRGB("--color-text-70"),
+ 80: convertToRGB("--color-text-80"),
+ 90: convertToRGB("--color-text-90"),
+ 100: convertToRGB("--color-text-100"),
+ 200: convertToRGB("--color-text-200"),
+ 300: convertToRGB("--color-text-300"),
+ 400: convertToRGB("--color-text-400"),
+ 500: convertToRGB("--color-text-500"),
+ 600: convertToRGB("--color-text-600"),
+ 700: convertToRGB("--color-text-700"),
+ 800: convertToRGB("--color-text-800"),
+ 900: convertToRGB("--color-text-900"),
+ 1000: "rgb(0, 0, 0)",
+ DEFAULT: convertToRGB("--color-text-100"),
+ },
+ border: {
+ 0: "rgb(255, 255, 255)",
+ 100: convertToRGB("--color-border-100"),
+ 200: convertToRGB("--color-border-200"),
+ 300: convertToRGB("--color-border-300"),
+ 400: convertToRGB("--color-border-400"),
+ 1000: "rgb(0, 0, 0)",
+ DEFAULT: convertToRGB("--color-border-200"),
+ },
+ sidebar: {
+ background: {
+ 0: "rgb(255, 255, 255)",
+ 10: convertToRGB("--color-sidebar-background-10"),
+ 20: convertToRGB("--color-sidebar-background-20"),
+ 30: convertToRGB("--color-sidebar-background-30"),
+ 40: convertToRGB("--color-sidebar-background-40"),
+ 50: convertToRGB("--color-sidebar-background-50"),
+ 60: convertToRGB("--color-sidebar-background-60"),
+ 70: convertToRGB("--color-sidebar-background-70"),
+ 80: convertToRGB("--color-sidebar-background-80"),
+ 90: convertToRGB("--color-sidebar-background-90"),
+ 100: convertToRGB("--color-sidebar-background-100"),
+ 200: convertToRGB("--color-sidebar-background-200"),
+ 300: convertToRGB("--color-sidebar-background-300"),
+ 400: convertToRGB("--color-sidebar-background-400"),
+ 500: convertToRGB("--color-sidebar-background-500"),
+ 600: convertToRGB("--color-sidebar-background-600"),
+ 700: convertToRGB("--color-sidebar-background-700"),
+ 800: convertToRGB("--color-sidebar-background-800"),
+ 900: convertToRGB("--color-sidebar-background-900"),
+ 1000: "rgb(0, 0, 0)",
+ DEFAULT: convertToRGB("--color-sidebar-background-100"),
+ },
+ text: {
+ 0: "rgb(255, 255, 255)",
+ 10: convertToRGB("--color-sidebar-text-10"),
+ 20: convertToRGB("--color-sidebar-text-20"),
+ 30: convertToRGB("--color-sidebar-text-30"),
+ 40: convertToRGB("--color-sidebar-text-40"),
+ 50: convertToRGB("--color-sidebar-text-50"),
+ 60: convertToRGB("--color-sidebar-text-60"),
+ 70: convertToRGB("--color-sidebar-text-70"),
+ 80: convertToRGB("--color-sidebar-text-80"),
+ 90: convertToRGB("--color-sidebar-text-90"),
+ 100: convertToRGB("--color-sidebar-text-100"),
+ 200: convertToRGB("--color-sidebar-text-200"),
+ 300: convertToRGB("--color-sidebar-text-300"),
+ 400: convertToRGB("--color-sidebar-text-400"),
+ 500: convertToRGB("--color-sidebar-text-500"),
+ 600: convertToRGB("--color-sidebar-text-600"),
+ 700: convertToRGB("--color-sidebar-text-700"),
+ 800: convertToRGB("--color-sidebar-text-800"),
+ 900: convertToRGB("--color-sidebar-text-900"),
+ 1000: "rgb(0, 0, 0)",
+ DEFAULT: convertToRGB("--color-sidebar-text-100"),
+ },
+ border: {
+ 0: "rgb(255, 255, 255)",
+ 100: convertToRGB("--color-sidebar-border-100"),
+ 200: convertToRGB("--color-sidebar-border-200"),
+ 300: convertToRGB("--color-sidebar-border-300"),
+ 400: convertToRGB("--color-sidebar-border-400"),
+ 1000: "rgb(0, 0, 0)",
+ DEFAULT: convertToRGB("--color-sidebar-border-200"),
+ },
+ },
+ backdrop: "#131313",
+ },
+ },
+ typography: ({ theme }) => ({
+ brand: {
+ css: {
+ "--tw-prose-body": convertToRGB("--color-text-100"),
+ "--tw-prose-p": convertToRGB("--color-text-100"),
+ "--tw-prose-headings": convertToRGB("--color-text-100"),
+ "--tw-prose-lead": convertToRGB("--color-text-100"),
+ "--tw-prose-links": convertToRGB("--color-primary-100"),
+ "--tw-prose-bold": convertToRGB("--color-text-100"),
+ "--tw-prose-counters": convertToRGB("--color-text-100"),
+ "--tw-prose-bullets": convertToRGB("--color-text-100"),
+ "--tw-prose-hr": convertToRGB("--color-text-100"),
+ "--tw-prose-quotes": convertToRGB("--color-text-100"),
+ "--tw-prose-quote-borders": convertToRGB("--color-border"),
+ "--tw-prose-code": convertToRGB("--color-text-100"),
+ "--tw-prose-pre-code": convertToRGB("--color-text-100"),
+ "--tw-prose-pre-bg": convertToRGB("--color-background-100"),
+ "--tw-prose-th-borders": convertToRGB("--color-border"),
+ "--tw-prose-td-borders": convertToRGB("--color-border"),
+ },
+ },
+ }),
+ },
+ fontFamily: {
+ custom: ["Inter", "sans-serif"],
+ },
+ },
+ plugins: [require("@tailwindcss/typography")],
+};
diff --git a/apps/app/tsconfig.json b/space/tsconfig.json
similarity index 100%
rename from apps/app/tsconfig.json
rename to space/tsconfig.json
diff --git a/space/types/issue.ts b/space/types/issue.ts
new file mode 100644
index 000000000..754da6ae3
--- /dev/null
+++ b/space/types/issue.ts
@@ -0,0 +1,163 @@
+export type TIssueBoardKeys = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt";
+
+export interface IIssueBoardViews {
+ key: TIssueBoardKeys;
+ title: string;
+ icon: string;
+ className: string;
+}
+
+export type TIssuePriorityKey = "urgent" | "high" | "medium" | "low" | "none";
+export type TIssuePriorityTitle = "Urgent" | "High" | "Medium" | "Low" | "None";
+export interface IIssuePriorityFilters {
+ key: TIssuePriorityKey;
+ title: TIssuePriorityTitle;
+ className: string;
+ icon: string;
+}
+
+export type TIssueGroupKey = "backlog" | "unstarted" | "started" | "completed" | "cancelled";
+export type TIssueGroupTitle = "Backlog" | "Unstarted" | "Started" | "Completed" | "Cancelled";
+
+export interface IIssueGroup {
+ key: TIssueGroupKey;
+ title: TIssueGroupTitle;
+ color: string;
+ className: string;
+ icon: React.FC;
+}
+
+export interface IIssue {
+ id: string;
+ comments: Comment[];
+ description_html: string;
+ label_details: any;
+ name: string;
+ priority: TIssuePriorityKey | null;
+ project: string;
+ project_detail: any;
+ reactions: IIssueReaction[];
+ sequence_id: number;
+ start_date: any;
+ state: string;
+ state_detail: any;
+ target_date: any;
+ votes: IVote[];
+}
+
+export interface IIssueState {
+ id: string;
+ name: string;
+ group: TIssueGroupKey;
+ color: string;
+}
+
+export interface IIssueLabel {
+ id: string;
+ name: string;
+ color: string;
+}
+
+export interface IVote {
+ issue: string;
+ vote: -1 | 1;
+ workspace: string;
+ project: string;
+ actor: string;
+ actor_detail: ActorDetail;
+}
+
+export interface Comment {
+ id: string;
+ actor_detail: ActorDetail;
+ issue_detail: IssueDetail;
+ project_detail: ProjectDetail;
+ workspace_detail: WorkspaceDetail;
+ comment_reactions: any[];
+ is_member: boolean;
+ created_at: Date;
+ updated_at: Date;
+ comment_stripped: string;
+ comment_html: string;
+ attachments: any[];
+ access: string;
+ created_by: string;
+ updated_by: string;
+ project: string;
+ workspace: string;
+ issue: string;
+ actor: string;
+}
+
+export interface IIssueReaction {
+ actor_detail: ActorDetail;
+ id: string;
+ issue: string;
+ reaction: string;
+}
+
+export interface ActorDetail {
+ avatar?: string;
+ display_name?: string;
+ first_name?: string;
+ id?: string;
+ is_bot?: boolean;
+ last_name?: string;
+}
+
+export interface IssueDetail {
+ id: string;
+ name: string;
+ description: Description;
+ description_html: string;
+ priority: string;
+ start_date: null;
+ target_date: null;
+ sequence_id: number;
+ sort_order: number;
+}
+
+export interface Description {
+ type: string;
+ content: DescriptionContent[];
+}
+
+export interface DescriptionContent {
+ type: string;
+ attrs?: Attrs;
+ content: ContentContent[];
+}
+
+export interface Attrs {
+ level: number;
+}
+
+export interface ContentContent {
+ text: string;
+ type: string;
+}
+
+export interface ProjectDetail {
+ id: string;
+ identifier: string;
+ name: string;
+ cover_image: string;
+ icon_prop: null;
+ emoji: string;
+ description: string;
+}
+
+export interface WorkspaceDetail {
+ name: string;
+ slug: string;
+ id: string;
+}
+
+export interface IssueDetailType {
+ [issueId: string]: {
+ issue: IIssue;
+ comments: Comment[];
+ reactions: any[];
+ votes: any[];
+ };
+}
diff --git a/apps/space/store/types/project.ts b/space/types/project.ts
similarity index 64%
rename from apps/space/store/types/project.ts
rename to space/types/project.ts
index 41f4c2f44..e0e1bba9e 100644
--- a/apps/space/store/types/project.ts
+++ b/space/types/project.ts
@@ -27,14 +27,3 @@ export interface IProjectSettings {
spreadsheet: boolean;
};
}
-
-export interface IProjectStore {
- loader: boolean;
- error: any | null;
-
- workspace: IWorkspace | null;
- project: IProject | null;
- workspaceProjectSettings: IProjectSettings | null;
-
- getProjectSettingsAsync: (workspace_slug: string, project_slug: string) => Promise;
-}
diff --git a/apps/space/store/types/theme.ts b/space/types/theme.ts
similarity index 100%
rename from apps/space/store/types/theme.ts
rename to space/types/theme.ts
diff --git a/space/types/user.ts b/space/types/user.ts
new file mode 100644
index 000000000..8c6d5f681
--- /dev/null
+++ b/space/types/user.ts
@@ -0,0 +1,23 @@
+export interface IUser {
+ avatar: string;
+ cover_image: string | null;
+ created_at: Date;
+ created_location: string;
+ date_joined: Date;
+ email: string;
+ display_name: string;
+ first_name: string;
+ id: string;
+ is_email_verified: boolean;
+ is_onboarded: boolean;
+ is_tour_completed: boolean;
+ last_location: string;
+ last_login: Date;
+ last_name: string;
+ mobile_number: string;
+ role: string;
+ token: string;
+ updated_at: Date;
+ username: string;
+ user_timezone: string;
+}
diff --git a/turbo.json b/turbo.json
index 69da3c552..47b92f0db 100644
--- a/turbo.json
+++ b/turbo.json
@@ -24,7 +24,8 @@
"NEXT_PUBLIC_SLACK_CLIENT_SECRET",
"NEXT_PUBLIC_SUPABASE_URL",
"NEXT_PUBLIC_SUPABASE_ANON_KEY",
- "NEXT_PUBLIC_PLAUSIBLE_DOMAIN"
+ "NEXT_PUBLIC_PLAUSIBLE_DOMAIN",
+ "NEXT_PUBLIC_DEPLOY_WITH_NGINX"
],
"pipeline": {
"build": {
diff --git a/web/.env.example b/web/.env.example
new file mode 100644
index 000000000..50a6209b2
--- /dev/null
+++ b/web/.env.example
@@ -0,0 +1,26 @@
+# Base url for the API requests
+NEXT_PUBLIC_API_BASE_URL=""
+# Extra image domains that need to be added for Next Image
+NEXT_PUBLIC_EXTRA_IMAGE_DOMAINS=
+# Google Client ID for Google OAuth
+NEXT_PUBLIC_GOOGLE_CLIENTID=""
+# GitHub App ID for GitHub OAuth
+NEXT_PUBLIC_GITHUB_ID=""
+# GitHub App Name for GitHub Integration
+NEXT_PUBLIC_GITHUB_APP_NAME=""
+# Sentry DSN for error monitoring
+NEXT_PUBLIC_SENTRY_DSN=""
+# Enable/Disable OAUTH - default 0 for selfhosted instance
+NEXT_PUBLIC_ENABLE_OAUTH=0
+# Enable/Disable Sentry
+NEXT_PUBLIC_ENABLE_SENTRY=0
+# Enable/Disable session recording
+NEXT_PUBLIC_ENABLE_SESSION_RECORDER=0
+# Enable/Disable event tracking
+NEXT_PUBLIC_TRACK_EVENTS=0
+# Slack Client ID for Slack Integration
+NEXT_PUBLIC_SLACK_CLIENT_ID=""
+# For Telemetry, set it to "app.plane.so"
+NEXT_PUBLIC_PLAUSIBLE_DOMAIN=""
+# Public boards deploy URL
+NEXT_PUBLIC_DEPLOY_URL=""
\ No newline at end of file
diff --git a/web/.eslintrc.js b/web/.eslintrc.js
new file mode 100644
index 000000000..38e6a5f4c
--- /dev/null
+++ b/web/.eslintrc.js
@@ -0,0 +1,7 @@
+module.exports = {
+ root: true,
+ extends: ["custom"],
+ rules: {
+ "@next/next/no-img-element": "off",
+ },
+};
diff --git a/apps/app/.prettierrc b/web/.prettierrc
similarity index 100%
rename from apps/app/.prettierrc
rename to web/.prettierrc
diff --git a/apps/app/Dockerfile.dev b/web/Dockerfile.dev
similarity index 100%
rename from apps/app/Dockerfile.dev
rename to web/Dockerfile.dev
diff --git a/apps/space/Dockerfile.space b/web/Dockerfile.web
similarity index 69%
rename from apps/space/Dockerfile.space
rename to web/Dockerfile.web
index 0240ddbf7..40946fa2d 100644
--- a/apps/space/Dockerfile.space
+++ b/web/Dockerfile.web
@@ -7,7 +7,7 @@ ENV NEXT_PUBLIC_API_BASE_URL=http://NEXT_PUBLIC_API_BASE_URL_PLACEHOLDER
RUN yarn global add turbo
COPY . .
-RUN turbo prune --scope=space --docker
+RUN turbo prune --scope=web --docker
# Add lockfile and package.json's of isolated subworkspace
FROM node:18-alpine AS installer
@@ -15,6 +15,7 @@ FROM node:18-alpine AS installer
RUN apk add --no-cache libc6-compat
WORKDIR /app
ARG NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
+ARG NEXT_PUBLIC_DEPLOY_URL=http://localhost/spaces
# First install the dependencies (as they change less often)
COPY .gitignore .gitignore
@@ -29,12 +30,13 @@ COPY replace-env-vars.sh /usr/local/bin/
USER root
RUN chmod +x /usr/local/bin/replace-env-vars.sh
-RUN yarn turbo run build --filter=space
-
ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL \
- BUILT_NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL
+ BUILT_NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL \
+ NEXT_PUBLIC_DEPLOY_URL=$NEXT_PUBLIC_DEPLOY_URL
-RUN /usr/local/bin/replace-env-vars.sh http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER ${NEXT_PUBLIC_API_BASE_URL} space
+RUN yarn turbo run build --filter=web
+
+RUN /usr/local/bin/replace-env-vars.sh http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER ${NEXT_PUBLIC_API_BASE_URL} web
FROM node:18-alpine AS runner
WORKDIR /app
@@ -44,18 +46,21 @@ RUN addgroup --system --gid 1001 plane
RUN adduser --system --uid 1001 captain
USER captain
-COPY --from=installer /app/apps/space/next.config.js .
-COPY --from=installer /app/apps/space/package.json .
+COPY --from=installer /app/web/next.config.js .
+COPY --from=installer /app/web/package.json .
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
-COPY --from=installer --chown=captain:plane /app/apps/space/.next/standalone ./
+COPY --from=installer --chown=captain:plane /app/web/.next/standalone ./
-COPY --from=installer --chown=captain:plane /app/apps/space/.next ./apps/space/.next
+COPY --from=installer --chown=captain:plane /app/web/.next ./web/.next
ARG NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
+ARG NEXT_PUBLIC_DEPLOY_URL=http://localhost/spaces
+
ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL \
- BUILT_NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL
+ BUILT_NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL \
+ NEXT_PUBLIC_DEPLOY_URL=$NEXT_PUBLIC_DEPLOY_URL
USER root
COPY replace-env-vars.sh /usr/local/bin/
diff --git a/apps/app/components/account/email-code-form.tsx b/web/components/account/email-code-form.tsx
similarity index 100%
rename from apps/app/components/account/email-code-form.tsx
rename to web/components/account/email-code-form.tsx
diff --git a/apps/app/components/account/email-password-form.tsx b/web/components/account/email-password-form.tsx
similarity index 100%
rename from apps/app/components/account/email-password-form.tsx
rename to web/components/account/email-password-form.tsx
diff --git a/apps/app/components/account/email-reset-password-form.tsx b/web/components/account/email-reset-password-form.tsx
similarity index 100%
rename from apps/app/components/account/email-reset-password-form.tsx
rename to web/components/account/email-reset-password-form.tsx
diff --git a/apps/app/components/account/github-login-button.tsx b/web/components/account/github-login-button.tsx
similarity index 100%
rename from apps/app/components/account/github-login-button.tsx
rename to web/components/account/github-login-button.tsx
diff --git a/apps/app/components/account/google-login.tsx b/web/components/account/google-login.tsx
similarity index 100%
rename from apps/app/components/account/google-login.tsx
rename to web/components/account/google-login.tsx
diff --git a/apps/app/components/account/index.ts b/web/components/account/index.ts
similarity index 100%
rename from apps/app/components/account/index.ts
rename to web/components/account/index.ts
diff --git a/apps/app/components/analytics/custom-analytics/create-update-analytics-modal.tsx b/web/components/analytics/custom-analytics/create-update-analytics-modal.tsx
similarity index 100%
rename from apps/app/components/analytics/custom-analytics/create-update-analytics-modal.tsx
rename to web/components/analytics/custom-analytics/create-update-analytics-modal.tsx
diff --git a/apps/app/components/analytics/custom-analytics/custom-analytics.tsx b/web/components/analytics/custom-analytics/custom-analytics.tsx
similarity index 100%
rename from apps/app/components/analytics/custom-analytics/custom-analytics.tsx
rename to web/components/analytics/custom-analytics/custom-analytics.tsx
diff --git a/apps/app/components/analytics/custom-analytics/graph/custom-tooltip.tsx b/web/components/analytics/custom-analytics/graph/custom-tooltip.tsx
similarity index 100%
rename from apps/app/components/analytics/custom-analytics/graph/custom-tooltip.tsx
rename to web/components/analytics/custom-analytics/graph/custom-tooltip.tsx
diff --git a/apps/app/components/analytics/custom-analytics/graph/index.tsx b/web/components/analytics/custom-analytics/graph/index.tsx
similarity index 100%
rename from apps/app/components/analytics/custom-analytics/graph/index.tsx
rename to web/components/analytics/custom-analytics/graph/index.tsx
diff --git a/apps/app/components/analytics/custom-analytics/index.ts b/web/components/analytics/custom-analytics/index.ts
similarity index 100%
rename from apps/app/components/analytics/custom-analytics/index.ts
rename to web/components/analytics/custom-analytics/index.ts
diff --git a/apps/app/components/analytics/custom-analytics/select-bar.tsx b/web/components/analytics/custom-analytics/select-bar.tsx
similarity index 100%
rename from apps/app/components/analytics/custom-analytics/select-bar.tsx
rename to web/components/analytics/custom-analytics/select-bar.tsx
diff --git a/apps/app/components/analytics/custom-analytics/sidebar.tsx b/web/components/analytics/custom-analytics/sidebar.tsx
similarity index 100%
rename from apps/app/components/analytics/custom-analytics/sidebar.tsx
rename to web/components/analytics/custom-analytics/sidebar.tsx
diff --git a/apps/app/components/analytics/custom-analytics/table.tsx b/web/components/analytics/custom-analytics/table.tsx
similarity index 100%
rename from apps/app/components/analytics/custom-analytics/table.tsx
rename to web/components/analytics/custom-analytics/table.tsx
diff --git a/apps/app/components/analytics/index.ts b/web/components/analytics/index.ts
similarity index 100%
rename from apps/app/components/analytics/index.ts
rename to web/components/analytics/index.ts
diff --git a/apps/app/components/analytics/project-modal.tsx b/web/components/analytics/project-modal.tsx
similarity index 100%
rename from apps/app/components/analytics/project-modal.tsx
rename to web/components/analytics/project-modal.tsx
diff --git a/apps/app/components/analytics/scope-and-demand/demand.tsx b/web/components/analytics/scope-and-demand/demand.tsx
similarity index 100%
rename from apps/app/components/analytics/scope-and-demand/demand.tsx
rename to web/components/analytics/scope-and-demand/demand.tsx
diff --git a/apps/app/components/analytics/scope-and-demand/index.ts b/web/components/analytics/scope-and-demand/index.ts
similarity index 100%
rename from apps/app/components/analytics/scope-and-demand/index.ts
rename to web/components/analytics/scope-and-demand/index.ts
diff --git a/apps/app/components/analytics/scope-and-demand/leaderboard.tsx b/web/components/analytics/scope-and-demand/leaderboard.tsx
similarity index 100%
rename from apps/app/components/analytics/scope-and-demand/leaderboard.tsx
rename to web/components/analytics/scope-and-demand/leaderboard.tsx
diff --git a/apps/app/components/analytics/scope-and-demand/scope-and-demand.tsx b/web/components/analytics/scope-and-demand/scope-and-demand.tsx
similarity index 100%
rename from apps/app/components/analytics/scope-and-demand/scope-and-demand.tsx
rename to web/components/analytics/scope-and-demand/scope-and-demand.tsx
diff --git a/apps/app/components/analytics/scope-and-demand/scope.tsx b/web/components/analytics/scope-and-demand/scope.tsx
similarity index 100%
rename from apps/app/components/analytics/scope-and-demand/scope.tsx
rename to web/components/analytics/scope-and-demand/scope.tsx
diff --git a/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx b/web/components/analytics/scope-and-demand/year-wise-issues.tsx
similarity index 100%
rename from apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx
rename to web/components/analytics/scope-and-demand/year-wise-issues.tsx
diff --git a/apps/app/components/analytics/select/index.ts b/web/components/analytics/select/index.ts
similarity index 100%
rename from apps/app/components/analytics/select/index.ts
rename to web/components/analytics/select/index.ts
diff --git a/apps/app/components/analytics/select/project.tsx b/web/components/analytics/select/project.tsx
similarity index 100%
rename from apps/app/components/analytics/select/project.tsx
rename to web/components/analytics/select/project.tsx
diff --git a/apps/app/components/analytics/select/segment.tsx b/web/components/analytics/select/segment.tsx
similarity index 100%
rename from apps/app/components/analytics/select/segment.tsx
rename to web/components/analytics/select/segment.tsx
diff --git a/apps/app/components/analytics/select/x-axis.tsx b/web/components/analytics/select/x-axis.tsx
similarity index 100%
rename from apps/app/components/analytics/select/x-axis.tsx
rename to web/components/analytics/select/x-axis.tsx
diff --git a/apps/app/components/analytics/select/y-axis.tsx b/web/components/analytics/select/y-axis.tsx
similarity index 100%
rename from apps/app/components/analytics/select/y-axis.tsx
rename to web/components/analytics/select/y-axis.tsx
diff --git a/apps/app/components/auth-screens/index.ts b/web/components/auth-screens/index.ts
similarity index 100%
rename from apps/app/components/auth-screens/index.ts
rename to web/components/auth-screens/index.ts
diff --git a/apps/app/components/auth-screens/not-authorized-view.tsx b/web/components/auth-screens/not-authorized-view.tsx
similarity index 100%
rename from apps/app/components/auth-screens/not-authorized-view.tsx
rename to web/components/auth-screens/not-authorized-view.tsx
diff --git a/apps/app/components/auth-screens/project/index.ts b/web/components/auth-screens/project/index.ts
similarity index 100%
rename from apps/app/components/auth-screens/project/index.ts
rename to web/components/auth-screens/project/index.ts
diff --git a/apps/app/components/auth-screens/project/join-project.tsx b/web/components/auth-screens/project/join-project.tsx
similarity index 100%
rename from apps/app/components/auth-screens/project/join-project.tsx
rename to web/components/auth-screens/project/join-project.tsx
diff --git a/apps/app/components/auth-screens/workspace/index.ts b/web/components/auth-screens/workspace/index.ts
similarity index 100%
rename from apps/app/components/auth-screens/workspace/index.ts
rename to web/components/auth-screens/workspace/index.ts
diff --git a/apps/app/components/auth-screens/workspace/not-a-member.tsx b/web/components/auth-screens/workspace/not-a-member.tsx
similarity index 100%
rename from apps/app/components/auth-screens/workspace/not-a-member.tsx
rename to web/components/auth-screens/workspace/not-a-member.tsx
diff --git a/apps/app/components/automation/auto-archive-automation.tsx b/web/components/automation/auto-archive-automation.tsx
similarity index 100%
rename from apps/app/components/automation/auto-archive-automation.tsx
rename to web/components/automation/auto-archive-automation.tsx
diff --git a/apps/app/components/automation/auto-close-automation.tsx b/web/components/automation/auto-close-automation.tsx
similarity index 100%
rename from apps/app/components/automation/auto-close-automation.tsx
rename to web/components/automation/auto-close-automation.tsx
diff --git a/apps/app/components/automation/index.ts b/web/components/automation/index.ts
similarity index 100%
rename from apps/app/components/automation/index.ts
rename to web/components/automation/index.ts
diff --git a/apps/app/components/automation/select-month-modal.tsx b/web/components/automation/select-month-modal.tsx
similarity index 100%
rename from apps/app/components/automation/select-month-modal.tsx
rename to web/components/automation/select-month-modal.tsx
diff --git a/apps/app/components/breadcrumbs/index.tsx b/web/components/breadcrumbs/index.tsx
similarity index 100%
rename from apps/app/components/breadcrumbs/index.tsx
rename to web/components/breadcrumbs/index.tsx
diff --git a/apps/app/components/command-palette/change-interface-theme.tsx b/web/components/command-palette/change-interface-theme.tsx
similarity index 100%
rename from apps/app/components/command-palette/change-interface-theme.tsx
rename to web/components/command-palette/change-interface-theme.tsx
diff --git a/apps/app/components/command-palette/command-k.tsx b/web/components/command-palette/command-k.tsx
similarity index 99%
rename from apps/app/components/command-palette/command-k.tsx
rename to web/components/command-palette/command-k.tsx
index a1525a348..d20a44290 100644
--- a/apps/app/components/command-palette/command-k.tsx
+++ b/web/components/command-palette/command-k.tsx
@@ -665,7 +665,7 @@ export const CommandK: React.FC = ({ deleteIssue, isPaletteOpen, setIsPal
className="focus:outline-none"
>
-
+
Join our Discord
diff --git a/apps/app/components/command-palette/command-pallette.tsx b/web/components/command-palette/command-pallette.tsx
similarity index 80%
rename from apps/app/components/command-palette/command-pallette.tsx
rename to web/components/command-palette/command-pallette.tsx
index 4dc29afec..507d8a49c 100644
--- a/apps/app/components/command-palette/command-pallette.tsx
+++ b/web/components/command-palette/command-pallette.tsx
@@ -51,7 +51,7 @@ export const CommandPalette: React.FC = observer(() => {
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
workspaceSlug && projectId && issueId
? () =>
- issuesService.retrieve(workspaceSlug as string, projectId as string, issueId as string)
+ issuesService.retrieve(workspaceSlug as string, projectId as string, issueId as string)
: null
);
@@ -89,37 +89,37 @@ export const CommandPalette: React.FC = observer(() => {
)
return;
- if (cmdClicked) {
- if (keyPressed === "k") {
- e.preventDefault();
- setIsPaletteOpen(true);
- } else if (keyPressed === "c" && altKey) {
- e.preventDefault();
- copyIssueUrlToClipboard();
- } else if (keyPressed === "b") {
- e.preventDefault();
- store.theme.setSidebarCollapsed(!store?.theme?.sidebarCollapsed);
- }
- } else {
- if (keyPressed === "c") {
- setIsIssueModalOpen(true);
- } else if (keyPressed === "p") {
- setIsProjectModalOpen(true);
- } else if (keyPressed === "v") {
- setIsCreateViewModalOpen(true);
- } else if (keyPressed === "d") {
- setIsCreateUpdatePageModalOpen(true);
- } else if (keyPressed === "h") {
- setIsShortcutsModalOpen(true);
- } else if (keyPressed === "q") {
- setIsCreateCycleModalOpen(true);
- } else if (keyPressed === "m") {
- setIsCreateModuleModalOpen(true);
- } else if (keyPressed === "backspace" || keyPressed === "delete") {
- e.preventDefault();
- setIsBulkDeleteIssuesModalOpen(true);
- }
+ if (cmdClicked) {
+ if (keyPressed === "k") {
+ e.preventDefault();
+ setIsPaletteOpen(true);
+ } else if (keyPressed === "c" && altKey) {
+ e.preventDefault();
+ copyIssueUrlToClipboard();
+ } else if (keyPressed === "b") {
+ e.preventDefault();
+ store.theme.setSidebarCollapsed(!store?.theme?.sidebarCollapsed);
}
+ } else {
+ if (keyPressed === "c") {
+ setIsIssueModalOpen(true);
+ } else if (keyPressed === "p") {
+ setIsProjectModalOpen(true);
+ } else if (keyPressed === "v") {
+ setIsCreateViewModalOpen(true);
+ } else if (keyPressed === "d") {
+ setIsCreateUpdatePageModalOpen(true);
+ } else if (keyPressed === "h") {
+ setIsShortcutsModalOpen(true);
+ } else if (keyPressed === "q") {
+ setIsCreateCycleModalOpen(true);
+ } else if (keyPressed === "m") {
+ setIsCreateModuleModalOpen(true);
+ } else if (keyPressed === "backspace" || keyPressed === "delete") {
+ e.preventDefault();
+ setIsBulkDeleteIssuesModalOpen(true);
+ }
+ }
},
[copyIssueUrlToClipboard]
);
@@ -196,4 +196,4 @@ export const CommandPalette: React.FC = observer(() => {
/>
>
);
-})
\ No newline at end of file
+});
diff --git a/apps/app/components/command-palette/helpers.tsx b/web/components/command-palette/helpers.tsx
similarity index 100%
rename from apps/app/components/command-palette/helpers.tsx
rename to web/components/command-palette/helpers.tsx
diff --git a/apps/app/components/command-palette/index.ts b/web/components/command-palette/index.ts
similarity index 100%
rename from apps/app/components/command-palette/index.ts
rename to web/components/command-palette/index.ts
diff --git a/apps/app/components/command-palette/issue/change-issue-assignee.tsx b/web/components/command-palette/issue/change-issue-assignee.tsx
similarity index 100%
rename from apps/app/components/command-palette/issue/change-issue-assignee.tsx
rename to web/components/command-palette/issue/change-issue-assignee.tsx
diff --git a/apps/app/components/command-palette/issue/change-issue-priority.tsx b/web/components/command-palette/issue/change-issue-priority.tsx
similarity index 100%
rename from apps/app/components/command-palette/issue/change-issue-priority.tsx
rename to web/components/command-palette/issue/change-issue-priority.tsx
diff --git a/apps/app/components/command-palette/issue/change-issue-state.tsx b/web/components/command-palette/issue/change-issue-state.tsx
similarity index 100%
rename from apps/app/components/command-palette/issue/change-issue-state.tsx
rename to web/components/command-palette/issue/change-issue-state.tsx
diff --git a/apps/app/components/command-palette/issue/index.ts b/web/components/command-palette/issue/index.ts
similarity index 100%
rename from apps/app/components/command-palette/issue/index.ts
rename to web/components/command-palette/issue/index.ts
diff --git a/apps/app/components/command-palette/shortcuts-modal.tsx b/web/components/command-palette/shortcuts-modal.tsx
similarity index 99%
rename from apps/app/components/command-palette/shortcuts-modal.tsx
rename to web/components/command-palette/shortcuts-modal.tsx
index 86b4aeb46..82f9b398c 100644
--- a/apps/app/components/command-palette/shortcuts-modal.tsx
+++ b/web/components/command-palette/shortcuts-modal.tsx
@@ -22,8 +22,6 @@ const shortcuts = [
{ keys: "↓", description: "Move down" },
{ keys: "←", description: "Move left" },
{ keys: "→", description: "Move right" },
- { keys: "Enter", description: "Select" },
- { keys: "Esc", description: "Close" },
],
},
{
diff --git a/apps/app/components/core/activity.tsx b/web/components/core/activity.tsx
similarity index 79%
rename from apps/app/components/core/activity.tsx
rename to web/components/core/activity.tsx
index 7ddf9c33c..c8f6377b7 100644
--- a/apps/app/components/core/activity.tsx
+++ b/web/components/core/activity.tsx
@@ -53,7 +53,11 @@ const UserLink = ({ activity }: { activity: IIssueActivity }) => {
const activityDetails: {
[key: string]: {
- message: (activity: IIssueActivity, showIssue: boolean) => React.ReactNode;
+ message: (
+ activity: IIssueActivity,
+ showIssue: boolean,
+ workspaceSlug: string
+ ) => React.ReactNode;
icon: React.ReactNode;
};
} = {
@@ -173,26 +177,50 @@ const activityDetails: {
icon: ,
},
cycles: {
- message: (activity) => {
+ message: (activity, showIssue, workspaceSlug) => {
if (activity.verb === "created")
return (
<>
added this issue to the cycle{" "}
- {activity.new_value} .
+
+ {activity.new_value}
+
+
>
);
else if (activity.verb === "updated")
return (
<>
set the cycle to{" "}
- {activity.new_value} .
+
+ {activity.new_value}
+
+
>
);
else
return (
<>
removed the issue from the cycle{" "}
- {activity.old_value} .
+
+ {activity.old_value}
+
+
>
);
},
@@ -325,6 +353,28 @@ const activityDetails: {
.
>
);
+ else if (activity.verb === "updated")
+ return (
+ <>
+ updated the{" "}
+
+ link
+
+
+ {showIssue && (
+ <>
+ {" "}
+ from
+ >
+ )}
+ .
+ >
+ );
else
return (
<>
@@ -351,26 +401,50 @@ const activityDetails: {
icon: ,
},
modules: {
- message: (activity) => {
+ message: (activity, showIssue, workspaceSlug) => {
if (activity.verb === "created")
return (
<>
added this issue to the module{" "}
- {activity.new_value} .
+
+ {activity.new_value}
+
+
>
);
else if (activity.verb === "updated")
return (
<>
set the module to{" "}
- {activity.new_value} .
+
+ {activity.new_value}
+
+
>
);
else
return (
<>
removed the issue from the module{" "}
- {activity.old_value} .
+
+ {activity.old_value}
+
+
>
);
},
@@ -538,8 +612,17 @@ export const ActivityMessage = ({
}: {
activity: IIssueActivity;
showIssue?: boolean;
-}) => (
- <>
- {activityDetails[activity.field as keyof typeof activityDetails]?.message(activity, showIssue)}
- >
-);
+}) => {
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+
+ return (
+ <>
+ {activityDetails[activity.field as keyof typeof activityDetails]?.message(
+ activity,
+ showIssue,
+ workspaceSlug?.toString() ?? ""
+ )}
+ >
+ );
+};
diff --git a/apps/app/components/core/filters/due-date-filter-modal.tsx b/web/components/core/filters/date-filter-modal.tsx
similarity index 90%
rename from apps/app/components/core/filters/due-date-filter-modal.tsx
rename to web/components/core/filters/date-filter-modal.tsx
index 9556bd193..abc2cc7c4 100644
--- a/apps/app/components/core/filters/due-date-filter-modal.tsx
+++ b/web/components/core/filters/date-filter-modal.tsx
@@ -11,15 +11,18 @@ import { Dialog, Transition } from "@headlessui/react";
// hooks
import useIssuesView from "hooks/use-issues-view";
// components
-import { DueDateFilterSelect } from "./due-date-filter-select";
+import { DateFilterSelect } from "./date-filter-select";
// ui
import { PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { XMarkIcon } from "@heroicons/react/20/solid";
// helpers
import { renderDateFormat, renderShortDateWithYearFormat } from "helpers/date-time.helper";
+import { IIssueFilterOptions } from "types";
type Props = {
+ title: string;
+ field: keyof IIssueFilterOptions;
isOpen: boolean;
handleClose: () => void;
};
@@ -36,7 +39,7 @@ const defaultValues: TFormValues = {
date2: new Date(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()),
};
-export const DueDateFilterModal: React.FC = ({ isOpen, handleClose }) => {
+export const DateFilterModal: React.FC = ({ title, field, isOpen, handleClose }) => {
const { filters, setFilters } = useIssuesView();
const router = useRouter();
@@ -51,11 +54,11 @@ export const DueDateFilterModal: React.FC = ({ isOpen, handleClose }) =>
if (filterType === "range") {
setFilters(
- { target_date: [`${renderDateFormat(date1)};after`, `${renderDateFormat(date2)};before`] },
+ { [field]: [`${renderDateFormat(date1)};after`, `${renderDateFormat(date2)};before`] },
!Boolean(viewId)
);
} else {
- const filteredArray = filters?.target_date?.filter((item) => {
+ const filteredArray = (filters?.[field] as string[])?.filter((item) => {
if (item?.includes(filterType)) return false;
return true;
@@ -64,13 +67,13 @@ export const DueDateFilterModal: React.FC = ({ isOpen, handleClose }) =>
const filterOne = filteredArray && filteredArray?.length > 0 ? filteredArray[0] : null;
if (filterOne)
setFilters(
- { target_date: [filterOne, `${renderDateFormat(date1)};${filterType}`] },
+ { [field]: [filterOne, `${renderDateFormat(date1)};${filterType}`] },
!Boolean(viewId)
);
else
setFilters(
{
- target_date: [`${renderDateFormat(date1)};${filterType}`],
+ [field]: [`${renderDateFormat(date1)};${filterType}`],
},
!Boolean(viewId)
);
@@ -116,7 +119,7 @@ export const DueDateFilterModal: React.FC = ({ isOpen, handleClose }) =>
control={control}
name="filterType"
render={({ field: { value, onChange } }) => (
-
+
)}
/>
void;
};
@@ -19,29 +20,31 @@ type DueDate = {
const dueDateRange: DueDate[] = [
{
- name: "Due date before",
+ name: "before",
value: "before",
icon: ,
},
{
- name: "Due date after",
+ name: "after",
value: "after",
icon: ,
},
{
- name: "Due date range",
+ name: "range",
value: "range",
icon: ,
},
];
-export const DueDateFilterSelect: React.FC = ({ value, onChange }) => (
+export const DateFilterSelect: React.FC = ({ title, value, onChange }) => (
{dueDateRange.find((item) => item.value === value)?.icon}
- {dueDateRange.find((item) => item.value === value)?.name}
+
+ {title} {dueDateRange.find((item) => item.value === value)?.name}
+
}
onChange={onChange}
@@ -50,7 +53,7 @@ export const DueDateFilterSelect: React.FC
= ({ value, onChange }) => (
<>
{option.icon}
- {option.name}
+ {title} {option.name}
>
))}
diff --git a/apps/app/components/core/filters/filters-list.tsx b/web/components/core/filters/filters-list.tsx
similarity index 90%
rename from apps/app/components/core/filters/filters-list.tsx
rename to web/components/core/filters/filters-list.tsx
index ffe596258..8192bdf7d 100644
--- a/apps/app/components/core/filters/filters-list.tsx
+++ b/web/components/core/filters/filters-list.tsx
@@ -240,6 +240,34 @@ export const FiltersList: React.FC = ({
);
})
+ : key === "start_date"
+ ? filters.start_date?.map((date: string) => {
+ if (filters.start_date && filters.start_date.length <= 0) return null;
+
+ const splitDate = date.split(";");
+
+ return (
+
+
+
+ {splitDate[1]} {renderShortDateWithYearFormat(splitDate[0])}
+
+
+ setFilters({
+ start_date: filters.start_date?.filter((d: any) => d !== date),
+ })
+ }
+ >
+
+
+
+ );
+ })
: key === "target_date"
? filters.target_date?.map((date: string) => {
if (filters.target_date && filters.target_date.length <= 0) return null;
diff --git a/web/components/core/filters/index.ts b/web/components/core/filters/index.ts
new file mode 100644
index 000000000..d6455151e
--- /dev/null
+++ b/web/components/core/filters/index.ts
@@ -0,0 +1,4 @@
+export * from "./date-filter-modal";
+export * from "./date-filter-select";
+export * from "./filters-list";
+export * from "./issues-view-filter";
diff --git a/apps/app/components/core/filters/issues-view-filter.tsx b/web/components/core/filters/issues-view-filter.tsx
similarity index 91%
rename from apps/app/components/core/filters/issues-view-filter.tsx
rename to web/components/core/filters/issues-view-filter.tsx
index 2fa80c975..1266bd5a3 100644
--- a/apps/app/components/core/filters/issues-view-filter.tsx
+++ b/web/components/core/filters/issues-view-filter.tsx
@@ -113,46 +113,41 @@ export const IssuesFilterView: React.FC = () => {
))}
)}
- {issueView !== "gantt_chart" && (
-
{
- const key = option.key as keyof typeof filters;
+ {
+ const key = option.key as keyof typeof filters;
- if (key === "target_date") {
- const valueExists = checkIfArraysHaveSameElements(
- filters.target_date ?? [],
- option.value
+ if (key === "start_date" || key === "target_date") {
+ const valueExists = checkIfArraysHaveSameElements(filters[key] ?? [], option.value);
+
+ setFilters({
+ [key]: valueExists ? null : option.value,
+ });
+ } else {
+ const valueExists = filters[key]?.includes(option.value);
+
+ if (valueExists)
+ setFilters(
+ {
+ [option.key]: ((filters[key] ?? []) as any[])?.filter(
+ (val) => val !== option.value
+ ),
+ },
+ !Boolean(viewId)
);
-
- setFilters({
- target_date: valueExists ? null : option.value,
- });
- } else {
- const valueExists = filters[key]?.includes(option.value);
-
- if (valueExists)
- setFilters(
- {
- [option.key]: ((filters[key] ?? []) as any[])?.filter(
- (val) => val !== option.value
- ),
- },
- !Boolean(viewId)
- );
- else
- setFilters(
- {
- [option.key]: [...((filters[key] ?? []) as any[]), option.value],
- },
- !Boolean(viewId)
- );
- }
- }}
- direction="left"
- height="rg"
- />
- )}
+ else
+ setFilters(
+ {
+ [option.key]: [...((filters[key] ?? []) as any[]), option.value],
+ },
+ !Boolean(viewId)
+ );
+ }
+ }}
+ direction="left"
+ height="rg"
+ />
{({ open }) => (
<>
@@ -163,7 +158,7 @@ export const IssuesFilterView: React.FC = () => {
: "text-custom-sidebar-text-200"
}`}
>
- View
+ Display
diff --git a/apps/app/components/core/image-picker-popover.tsx b/web/components/core/image-picker-popover.tsx
similarity index 98%
rename from apps/app/components/core/image-picker-popover.tsx
rename to web/components/core/image-picker-popover.tsx
index 402cba022..5f13d960e 100644
--- a/apps/app/components/core/image-picker-popover.tsx
+++ b/web/components/core/image-picker-popover.tsx
@@ -40,9 +40,15 @@ type Props = {
label: string | React.ReactNode;
value: string | null;
onChange: (data: string) => void;
+ disabled?: boolean;
};
-export const ImagePickerPopover: React.FC = ({ label, value, onChange }) => {
+export const ImagePickerPopover: React.FC = ({
+ label,
+ value,
+ onChange,
+ disabled = false,
+}) => {
const ref = useRef(null);
const router = useRouter();
@@ -117,6 +123,7 @@ export const ImagePickerPopover: React.FC = ({ label, value, onChange })
setIsOpen((prev) => !prev)}
+ disabled={disabled}
>
{label}
diff --git a/apps/app/components/core/index.ts b/web/components/core/index.ts
similarity index 100%
rename from apps/app/components/core/index.ts
rename to web/components/core/index.ts
diff --git a/apps/app/components/core/modals/bulk-delete-issues-modal.tsx b/web/components/core/modals/bulk-delete-issues-modal.tsx
similarity index 100%
rename from apps/app/components/core/modals/bulk-delete-issues-modal.tsx
rename to web/components/core/modals/bulk-delete-issues-modal.tsx
diff --git a/apps/app/components/core/modals/existing-issues-list-modal.tsx b/web/components/core/modals/existing-issues-list-modal.tsx
similarity index 100%
rename from apps/app/components/core/modals/existing-issues-list-modal.tsx
rename to web/components/core/modals/existing-issues-list-modal.tsx
diff --git a/apps/app/components/core/modals/gpt-assistant-modal.tsx b/web/components/core/modals/gpt-assistant-modal.tsx
similarity index 92%
rename from apps/app/components/core/modals/gpt-assistant-modal.tsx
rename to web/components/core/modals/gpt-assistant-modal.tsx
index 35f282040..81c9b7d71 100644
--- a/apps/app/components/core/modals/gpt-assistant-modal.tsx
+++ b/web/components/core/modals/gpt-assistant-modal.tsx
@@ -1,7 +1,5 @@
import React, { useEffect, useState, forwardRef, useRef } from "react";
-
import { useRouter } from "next/router";
-
// react-hook-form
import { useForm } from "react-hook-form";
// services
@@ -12,9 +10,10 @@ import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// ui
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
-
+import { TipTapEditor } from "components/tiptap";
+// types
import { IIssue, IPageBlock } from "types";
-import Tiptap, { ITiptapRichTextEditor } from "components/tiptap";
+
type Props = {
isOpen: boolean;
handleClose: () => void;
@@ -32,12 +31,6 @@ type FormData = {
task: string;
};
-const TiptapEditor = React.forwardRef(
- (props, ref) =>
-);
-
-TiptapEditor.displayName = "TiptapEditor";
-
export const GptAssistantModal: React.FC = ({
isOpen,
handleClose,
@@ -140,13 +133,14 @@ export const GptAssistantModal: React.FC = ({
return (
{((content && content !== "") || (htmlContent && htmlContent !== "
")) && (
Content:
-
${content}`}
customClassName="-m-3"
@@ -160,7 +154,7 @@ export const GptAssistantModal: React.FC = ({
{response !== "" && (
Response:
-
${response}`}
customClassName="-mx-3 -my-3"
@@ -180,10 +174,11 @@ export const GptAssistantModal: React.FC = ({
type="text"
name="task"
register={register}
- placeholder={`${content && content !== ""
+ placeholder={`${
+ content && content !== ""
? "Tell AI what action to perform on this content..."
: "Ask AI anything..."
- }`}
+ }`}
autoComplete="off"
/>
@@ -219,8 +214,8 @@ export const GptAssistantModal: React.FC
= ({
{isSubmitting
? "Generating response..."
: response === ""
- ? "Generate response"
- : "Generate again"}
+ ? "Generate response"
+ : "Generate again"}
diff --git a/apps/app/components/core/modals/image-upload-modal.tsx b/web/components/core/modals/image-upload-modal.tsx
similarity index 100%
rename from apps/app/components/core/modals/image-upload-modal.tsx
rename to web/components/core/modals/image-upload-modal.tsx
diff --git a/apps/app/components/core/modals/index.ts b/web/components/core/modals/index.ts
similarity index 100%
rename from apps/app/components/core/modals/index.ts
rename to web/components/core/modals/index.ts
diff --git a/apps/app/components/core/modals/link-modal.tsx b/web/components/core/modals/link-modal.tsx
similarity index 100%
rename from apps/app/components/core/modals/link-modal.tsx
rename to web/components/core/modals/link-modal.tsx
diff --git a/apps/app/components/core/reaction-selector.tsx b/web/components/core/reaction-selector.tsx
similarity index 100%
rename from apps/app/components/core/reaction-selector.tsx
rename to web/components/core/reaction-selector.tsx
diff --git a/apps/app/components/core/sidebar/index.ts b/web/components/core/sidebar/index.ts
similarity index 100%
rename from apps/app/components/core/sidebar/index.ts
rename to web/components/core/sidebar/index.ts
diff --git a/apps/app/components/core/sidebar/links-list.tsx b/web/components/core/sidebar/links-list.tsx
similarity index 100%
rename from apps/app/components/core/sidebar/links-list.tsx
rename to web/components/core/sidebar/links-list.tsx
diff --git a/apps/app/components/core/sidebar/progress-chart.tsx b/web/components/core/sidebar/progress-chart.tsx
similarity index 100%
rename from apps/app/components/core/sidebar/progress-chart.tsx
rename to web/components/core/sidebar/progress-chart.tsx
diff --git a/apps/app/components/core/sidebar/sidebar-progress-stats.tsx b/web/components/core/sidebar/sidebar-progress-stats.tsx
similarity index 100%
rename from apps/app/components/core/sidebar/sidebar-progress-stats.tsx
rename to web/components/core/sidebar/sidebar-progress-stats.tsx
diff --git a/apps/app/components/core/sidebar/single-progress-stats.tsx b/web/components/core/sidebar/single-progress-stats.tsx
similarity index 100%
rename from apps/app/components/core/sidebar/single-progress-stats.tsx
rename to web/components/core/sidebar/single-progress-stats.tsx
diff --git a/apps/app/components/core/theme/color-picker-input.tsx b/web/components/core/theme/color-picker-input.tsx
similarity index 100%
rename from apps/app/components/core/theme/color-picker-input.tsx
rename to web/components/core/theme/color-picker-input.tsx
diff --git a/apps/app/components/core/theme/custom-theme-selector.tsx b/web/components/core/theme/custom-theme-selector.tsx
similarity index 100%
rename from apps/app/components/core/theme/custom-theme-selector.tsx
rename to web/components/core/theme/custom-theme-selector.tsx
diff --git a/apps/app/components/core/theme/index.ts b/web/components/core/theme/index.ts
similarity index 100%
rename from apps/app/components/core/theme/index.ts
rename to web/components/core/theme/index.ts
diff --git a/apps/app/components/core/theme/theme-switch.tsx b/web/components/core/theme/theme-switch.tsx
similarity index 100%
rename from apps/app/components/core/theme/theme-switch.tsx
rename to web/components/core/theme/theme-switch.tsx
diff --git a/apps/app/components/core/views/all-views.tsx b/web/components/core/views/all-views.tsx
similarity index 95%
rename from apps/app/components/core/views/all-views.tsx
rename to web/components/core/views/all-views.tsx
index 4a757649c..eb54ccb2a 100644
--- a/apps/app/components/core/views/all-views.tsx
+++ b/web/components/core/views/all-views.tsx
@@ -53,6 +53,7 @@ type Props = {
handleOnDragEnd: (result: DropResult) => Promise;
openIssuesListModal: (() => void) | null;
removeIssue: ((bridgeId: string, issueId: string) => void) | null;
+ disableAddIssueOption?: boolean;
trashBox: boolean;
setTrashBox: React.Dispatch>;
viewProps: IIssueViewProps;
@@ -68,6 +69,7 @@ export const AllViews: React.FC = ({
handleOnDragEnd,
openIssuesListModal,
removeIssue,
+ disableAddIssueOption = false,
trashBox,
setTrashBox,
viewProps,
@@ -114,7 +116,10 @@ export const AllViews: React.FC = ({
)}
{groupedIssues ? (
- !isEmpty || issueView === "kanban" || issueView === "calendar" ? (
+ !isEmpty ||
+ issueView === "kanban" ||
+ issueView === "calendar" ||
+ issueView === "gantt_chart" ? (
<>
{issueView === "list" ? (
= ({
openIssuesListModal={cycleId || moduleId ? openIssuesListModal : null}
removeIssue={removeIssue}
disableUserActions={disableUserActions}
+ disableAddIssueOption={disableAddIssueOption}
user={user}
userAuth={memberRole}
viewProps={viewProps}
@@ -132,6 +138,7 @@ export const AllViews: React.FC = ({
void;
disableUserActions: boolean;
+ disableAddIssueOption?: boolean;
dragDisabled: boolean;
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
handleTrashBox: (isDragging: boolean) => void;
@@ -24,6 +25,7 @@ type Props = {
export const AllBoards: React.FC = ({
addIssueToGroup,
disableUserActions,
+ disableAddIssueOption = false,
dragDisabled,
handleIssueAction,
handleTrashBox,
@@ -52,6 +54,7 @@ export const AllBoards: React.FC = ({
addIssueToGroup={() => addIssueToGroup(singleGroup)}
currentState={currentState}
disableUserActions={disableUserActions}
+ disableAddIssueOption={disableAddIssueOption}
dragDisabled={dragDisabled}
groupTitle={singleGroup}
handleIssueAction={handleIssueAction}
diff --git a/apps/app/components/core/views/board-view/board-header.tsx b/web/components/core/views/board-view/board-header.tsx
similarity index 90%
rename from apps/app/components/core/views/board-view/board-header.tsx
rename to web/components/core/views/board-view/board-header.tsx
index 919bc36a3..5392774d9 100644
--- a/apps/app/components/core/views/board-view/board-header.tsx
+++ b/web/components/core/views/board-view/board-header.tsx
@@ -12,7 +12,7 @@ import useProjects from "hooks/use-projects";
// component
import { Avatar, Icon } from "components/ui";
// icons
-import { ArrowsPointingInIcon, ArrowsPointingOutIcon, PlusIcon } from "@heroicons/react/24/outline";
+import { PlusIcon } from "@heroicons/react/24/outline";
import { getPriorityIcon, getStateGroupIcon } from "components/icons";
// helpers
import { addSpaceIfCamelCase } from "helpers/string.helper";
@@ -29,6 +29,7 @@ type Props = {
isCollapsed: boolean;
setIsCollapsed: React.Dispatch>;
disableUserActions: boolean;
+ disableAddIssue: boolean;
viewProps: IIssueViewProps;
};
@@ -39,6 +40,7 @@ export const BoardHeader: React.FC = ({
isCollapsed,
setIsCollapsed,
disableUserActions,
+ disableAddIssue,
viewProps,
}) => {
const router = useRouter();
@@ -56,10 +58,10 @@ export const BoardHeader: React.FC = ({
);
const { data: members } = useSWR(
- workspaceSlug && projectId && selectedGroup === "created_by"
+ workspaceSlug && projectId && (selectedGroup === "created_by" || selectedGroup === "assignees")
? PROJECT_MEMBERS(projectId.toString())
: null,
- workspaceSlug && projectId && selectedGroup === "created_by"
+ workspaceSlug && projectId && (selectedGroup === "created_by" || selectedGroup === "assignees")
? () => projectService.projectMembers(workspaceSlug.toString(), projectId.toString())
: null
);
@@ -79,9 +81,11 @@ export const BoardHeader: React.FC = ({
case "project":
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
break;
+ case "assignees":
case "created_by":
const member = members?.find((member) => member.member.id === groupTitle)?.member;
- title = member?.display_name ?? "";
+ title = member ? member.display_name : "None";
+
break;
}
@@ -122,9 +126,10 @@ export const BoardHeader: React.FC = ({
/>
);
break;
+ case "assignees":
case "created_by":
const member = members?.find((member) => member.member.id === groupTitle)?.member;
- icon = ;
+ icon = member ? : <>>;
break;
}
@@ -178,7 +183,7 @@ export const BoardHeader: React.FC = ({
)}
- {!disableUserActions && selectedGroup !== "created_by" && (
+ {!disableAddIssue && !disableUserActions && selectedGroup !== "created_by" && (
void;
currentState?: IState | null;
disableUserActions: boolean;
+ disableAddIssueOption?: boolean;
dragDisabled: boolean;
groupTitle: string;
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
@@ -36,6 +37,7 @@ export const SingleBoard: React.FC = ({
currentState,
groupTitle,
disableUserActions,
+ disableAddIssueOption = false,
dragDisabled,
handleIssueAction,
handleTrashBox,
@@ -70,6 +72,7 @@ export const SingleBoard: React.FC = ({
isCollapsed={isCollapsed}
setIsCollapsed={setIsCollapsed}
disableUserActions={disableUserActions}
+ disableAddIssue={disableAddIssueOption}
viewProps={viewProps}
/>
{isCollapsed && (
@@ -150,41 +153,41 @@ export const SingleBoard: React.FC = ({
{selectedGroup !== "created_by" && (
- {type === "issue" ? (
-
-
- Add Issue
-
- ) : (
- !disableUserActions && (
-
-
- Add Issue
-
- }
- position="left"
- noBorder
- >
-
- Create new
-
- {openIssuesListModal && (
-
- Add an existing issue
+ {type === "issue"
+ ? !disableAddIssueOption && (
+
+
+ Add Issue
+
+ )
+ : !disableUserActions && (
+
+
+ Add Issue
+
+ }
+ position="left"
+ noBorder
+ >
+
+ Create new
- )}
-
- )
- )}
+ {openIssuesListModal && (
+
+ Add an existing issue
+
+ )}
+
+ )}
)}
diff --git a/apps/app/components/core/views/board-view/single-issue.tsx b/web/components/core/views/board-view/single-issue.tsx
similarity index 99%
rename from apps/app/components/core/views/board-view/single-issue.tsx
rename to web/components/core/views/board-view/single-issue.tsx
index b676e809c..455ba48e6 100644
--- a/apps/app/components/core/views/board-view/single-issue.tsx
+++ b/web/components/core/views/board-view/single-issue.tsx
@@ -350,7 +350,7 @@ export const SingleBoardIssue: React.FC = ({
/>
)}
{properties.labels && issue.labels.length > 0 && (
-
+
)}
{properties.assignee && (
= ({
labels: null,
priority: null,
state: null,
+ start_date: null,
target_date: null,
type: null,
})
@@ -513,7 +514,8 @@ export const IssuesView: React.FC = ({
dragDisabled={
selectedGroup === "created_by" ||
selectedGroup === "labels" ||
- selectedGroup === "state_detail.group"
+ selectedGroup === "state_detail.group" ||
+ selectedGroup === "assignees"
}
emptyState={{
title: cycleId
@@ -546,7 +548,7 @@ export const IssuesView: React.FC = ({
}}
handleOnDragEnd={handleOnDragEnd}
handleIssueAction={handleIssueAction}
- openIssuesListModal={openIssuesListModal ? openIssuesListModal : null}
+ openIssuesListModal={openIssuesListModal ?? null}
removeIssue={cycleId ? removeIssueFromCycle : moduleId ? removeIssueFromModule : null}
trashBox={trashBox}
setTrashBox={setTrashBox}
diff --git a/apps/app/components/core/views/list-view/all-lists.tsx b/web/components/core/views/list-view/all-lists.tsx
similarity index 93%
rename from apps/app/components/core/views/list-view/all-lists.tsx
rename to web/components/core/views/list-view/all-lists.tsx
index 64cbebdcd..84ef02962 100644
--- a/apps/app/components/core/views/list-view/all-lists.tsx
+++ b/web/components/core/views/list-view/all-lists.tsx
@@ -11,6 +11,7 @@ type Props = {
openIssuesListModal?: (() => void) | null;
removeIssue: ((bridgeId: string, issueId: string) => void) | null;
disableUserActions: boolean;
+ disableAddIssueOption?: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth;
viewProps: IIssueViewProps;
@@ -20,6 +21,7 @@ export const AllLists: React.FC = ({
addIssueToGroup,
handleIssueAction,
disableUserActions,
+ disableAddIssueOption = false,
openIssuesListModal,
removeIssue,
states,
@@ -49,6 +51,7 @@ export const AllLists: React.FC = ({
openIssuesListModal={openIssuesListModal}
removeIssue={removeIssue}
disableUserActions={disableUserActions}
+ disableAddIssueOption={disableAddIssueOption}
user={user}
userAuth={userAuth}
viewProps={viewProps}
diff --git a/apps/app/components/core/views/list-view/index.ts b/web/components/core/views/list-view/index.ts
similarity index 100%
rename from apps/app/components/core/views/list-view/index.ts
rename to web/components/core/views/list-view/index.ts
diff --git a/apps/app/components/core/views/list-view/single-issue.tsx b/web/components/core/views/list-view/single-issue.tsx
similarity index 94%
rename from apps/app/components/core/views/list-view/single-issue.tsx
rename to web/components/core/views/list-view/single-issue.tsx
index eafe74612..d89ef6927 100644
--- a/apps/app/components/core/views/list-view/single-issue.tsx
+++ b/web/components/core/views/list-view/single-issue.tsx
@@ -36,9 +36,21 @@ import { LayerDiagonalIcon } from "components/icons";
import { copyTextToClipboard } from "helpers/string.helper";
import { handleIssuesMutation } from "constants/issue";
// types
-import { ICurrentUserResponse, IIssue, IIssueViewProps, ISubIssueResponse, UserAuth } from "types";
+import {
+ ICurrentUserResponse,
+ IIssue,
+ IIssueViewProps,
+ ISubIssueResponse,
+ IUserProfileProjectSegregation,
+ UserAuth,
+} from "types";
// fetch-keys
-import { CYCLE_DETAILS, MODULE_DETAILS, SUB_ISSUES } from "constants/fetch-keys";
+import {
+ CYCLE_DETAILS,
+ MODULE_DETAILS,
+ SUB_ISSUES,
+ USER_PROFILE_PROJECT_SEGREGATION,
+} from "constants/fetch-keys";
type Props = {
type?: string;
@@ -74,7 +86,7 @@ export const SingleListIssue: React.FC = ({
const [contextMenuPosition, setContextMenuPosition] = useState(null);
const router = useRouter();
- const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
+ const { workspaceSlug, projectId, cycleId, moduleId, userId } = router.query;
const isArchivedIssues = router.pathname.includes("archived-issues");
const { setToastAlert } = useToast();
@@ -126,6 +138,11 @@ export const SingleListIssue: React.FC = ({
.then(() => {
mutateIssues();
+ if (userId)
+ mutate(
+ USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString())
+ );
+
if (cycleId) mutate(CYCLE_DETAILS(cycleId as string));
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
});
@@ -134,6 +151,7 @@ export const SingleListIssue: React.FC = ({
workspaceSlug,
cycleId,
moduleId,
+ userId,
groupTitle,
index,
selectedGroup,
@@ -261,7 +279,7 @@ export const SingleListIssue: React.FC = ({
isNotAllowed={isNotAllowed}
/>
)}
- {properties.labels && }
+ {properties.labels && }
{properties.assignee && (
void) | null;
removeIssue: ((bridgeId: string, issueId: string) => void) | null;
disableUserActions: boolean;
+ disableAddIssueOption?: boolean;
user: ICurrentUserResponse | undefined;
userAuth: UserAuth;
viewProps: IIssueViewProps;
@@ -52,6 +53,7 @@ export const SingleList: React.FC = ({
openIssuesListModal,
removeIssue,
disableUserActions,
+ disableAddIssueOption = false,
user,
userAuth,
viewProps,
@@ -94,9 +96,10 @@ export const SingleList: React.FC = ({
case "project":
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
break;
+ case "assignees":
case "created_by":
const member = members?.find((member) => member.member.id === groupTitle)?.member;
- title = member?.display_name ?? "";
+ title = member ? member.display_name : "None";
break;
}
@@ -137,9 +140,10 @@ export const SingleList: React.FC = ({
/>
);
break;
+ case "assignees":
case "created_by":
const member = members?.find((member) => member.member.id === groupTitle)?.member;
- icon = ;
+ icon = member ? : <>>;
break;
}
@@ -178,13 +182,15 @@ export const SingleList: React.FC = ({
{isArchivedIssues ? (
""
) : type === "issue" ? (
-
-
-
+ !disableAddIssueOption && (
+
+
+
+ )
) : disableUserActions ? (
""
) : (
diff --git a/apps/app/components/core/views/spreadsheet-view/index.ts b/web/components/core/views/spreadsheet-view/index.ts
similarity index 100%
rename from apps/app/components/core/views/spreadsheet-view/index.ts
rename to web/components/core/views/spreadsheet-view/index.ts
diff --git a/web/components/core/views/spreadsheet-view/single-issue.tsx b/web/components/core/views/spreadsheet-view/single-issue.tsx
new file mode 100644
index 000000000..731d7f921
--- /dev/null
+++ b/web/components/core/views/spreadsheet-view/single-issue.tsx
@@ -0,0 +1,380 @@
+import React, { useCallback, useState } from "react";
+
+import { useRouter } from "next/router";
+
+import { mutate } from "swr";
+
+// components
+import {
+ ViewAssigneeSelect,
+ ViewDueDateSelect,
+ ViewEstimateSelect,
+ ViewIssueLabel,
+ ViewPrioritySelect,
+ ViewStartDateSelect,
+ ViewStateSelect,
+} from "components/issues";
+import { Popover2 } from "@blueprintjs/popover2";
+// icons
+import { Icon } from "components/ui";
+import {
+ EllipsisHorizontalIcon,
+ LinkIcon,
+ PencilIcon,
+ TrashIcon,
+} from "@heroicons/react/24/outline";
+// hooks
+import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view";
+import useToast from "hooks/use-toast";
+// services
+import issuesService from "services/issues.service";
+// constant
+import {
+ CYCLE_DETAILS,
+ CYCLE_ISSUES_WITH_PARAMS,
+ MODULE_DETAILS,
+ MODULE_ISSUES_WITH_PARAMS,
+ PROJECT_ISSUES_LIST_WITH_PARAMS,
+ SUB_ISSUES,
+ VIEW_ISSUES,
+} from "constants/fetch-keys";
+// types
+import { ICurrentUserResponse, IIssue, ISubIssueResponse, Properties, UserAuth } from "types";
+// helper
+import { copyTextToClipboard } from "helpers/string.helper";
+import { renderLongDetailDateFormat } from "helpers/date-time.helper";
+
+type Props = {
+ issue: IIssue;
+ index: number;
+ expanded: boolean;
+ handleToggleExpand: (issueId: string) => void;
+ properties: Properties;
+ handleEditIssue: (issue: IIssue) => void;
+ handleDeleteIssue: (issue: IIssue) => void;
+ gridTemplateColumns: string;
+ disableUserActions: boolean;
+ user: ICurrentUserResponse | undefined;
+ userAuth: UserAuth;
+ nestingLevel: number;
+};
+
+export const SingleSpreadsheetIssue: React.FC = ({
+ issue,
+ index,
+ expanded,
+ handleToggleExpand,
+ properties,
+ handleEditIssue,
+ handleDeleteIssue,
+ gridTemplateColumns,
+ disableUserActions,
+ user,
+ userAuth,
+ nestingLevel,
+}) => {
+ const [isOpen, setIsOpen] = useState(false);
+
+ const router = useRouter();
+
+ const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
+
+ const { params } = useSpreadsheetIssuesView();
+
+ const { setToastAlert } = useToast();
+
+ const partialUpdateIssue = useCallback(
+ (formData: Partial, issue: IIssue) => {
+ if (!workspaceSlug || !projectId) return;
+
+ const fetchKey = cycleId
+ ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params)
+ : moduleId
+ ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params)
+ : viewId
+ ? VIEW_ISSUES(viewId.toString(), params)
+ : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params);
+
+ if (issue.parent)
+ mutate(
+ SUB_ISSUES(issue.parent.toString()),
+ (prevData) => {
+ if (!prevData) return prevData;
+
+ return {
+ ...prevData,
+ sub_issues: (prevData.sub_issues ?? []).map((i) => {
+ if (i.id === issue.id) {
+ return {
+ ...i,
+ ...formData,
+ };
+ }
+ return i;
+ }),
+ };
+ },
+ false
+ );
+ else
+ mutate(
+ fetchKey,
+ (prevData) =>
+ (prevData ?? []).map((p) => {
+ if (p.id === issue.id) {
+ return {
+ ...p,
+ ...formData,
+ };
+ }
+ return p;
+ }),
+ false
+ );
+
+ issuesService
+ .patchIssue(
+ workspaceSlug as string,
+ projectId as string,
+ issue.id as string,
+ formData,
+ user
+ )
+ .then(() => {
+ if (issue.parent) {
+ mutate(SUB_ISSUES(issue.parent as string));
+ } else {
+ mutate(fetchKey);
+
+ if (cycleId) mutate(CYCLE_DETAILS(cycleId as string));
+ if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
+ }
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ },
+ [workspaceSlug, projectId, cycleId, moduleId, viewId, params, user]
+ );
+
+ const openPeekOverview = () => {
+ const { query } = router;
+
+ router.push({
+ pathname: router.pathname,
+ query: { ...query, peekIssue: issue.id },
+ });
+ };
+
+ const handleCopyText = () => {
+ const originURL =
+ typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
+ copyTextToClipboard(
+ `${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`
+ ).then(() => {
+ setToastAlert({
+ type: "success",
+ title: "Link Copied!",
+ message: "Issue link copied to clipboard.",
+ });
+ });
+ };
+
+ const paddingLeft = `${nestingLevel * 68}px`;
+
+ const tooltipPosition = index === 0 ? "bottom" : "top";
+
+ const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
+
+ return (
+ <>
+
+
+
+
+ {properties.key && (
+
+ {issue.project_detail?.identifier}-{issue.sequence_id}
+
+ )}
+ {!isNotAllowed && !disableUserActions && (
+
+
setIsOpen(nextOpenState)}
+ content={
+
+
{
+ handleEditIssue(issue);
+ setIsOpen(false);
+ }}
+ >
+
+
+
+
{
+ handleDeleteIssue(issue);
+ setIsOpen(false);
+ }}
+ >
+
+
+ Delete issue
+
+
+
+
{
+ handleCopyText();
+ setIsOpen(false);
+ }}
+ >
+
+
+ Copy issue link
+
+
+
+ }
+ placement="bottom-start"
+ >
+
+
+
+ )}
+
+
+ {issue.sub_issues_count > 0 && (
+
+ handleToggleExpand(issue.id)}
+ >
+
+
+
+ )}
+
+
+
+ {issue.name}
+
+
+ {properties.state && (
+
+
+
+ )}
+ {properties.priority && (
+
+
+
+ )}
+ {properties.assignee && (
+
+
+
+ )}
+ {properties.labels && (
+
+
+
+ )}
+
+ {properties.start_date && (
+
+
+
+ )}
+
+ {properties.due_date && (
+
+
+
+ )}
+ {properties.estimate && (
+
+
+
+ )}
+ {properties.created_on && (
+
+ {renderLongDetailDateFormat(issue.created_at)}
+
+ )}
+ {properties.updated_on && (
+
+ {renderLongDetailDateFormat(issue.updated_at)}
+
+ )}
+
+ >
+ );
+};
diff --git a/apps/app/components/core/views/spreadsheet-view/spreadsheet-columns.tsx b/web/components/core/views/spreadsheet-view/spreadsheet-columns.tsx
similarity index 100%
rename from apps/app/components/core/views/spreadsheet-view/spreadsheet-columns.tsx
rename to web/components/core/views/spreadsheet-view/spreadsheet-columns.tsx
diff --git a/apps/app/components/core/views/spreadsheet-view/spreadsheet-issues.tsx b/web/components/core/views/spreadsheet-view/spreadsheet-issues.tsx
similarity index 100%
rename from apps/app/components/core/views/spreadsheet-view/spreadsheet-issues.tsx
rename to web/components/core/views/spreadsheet-view/spreadsheet-issues.tsx
diff --git a/web/components/core/views/spreadsheet-view/spreadsheet-view.tsx b/web/components/core/views/spreadsheet-view/spreadsheet-view.tsx
new file mode 100644
index 000000000..1076f30d0
--- /dev/null
+++ b/web/components/core/views/spreadsheet-view/spreadsheet-view.tsx
@@ -0,0 +1,147 @@
+import React, { useState } from "react";
+
+// next
+import { useRouter } from "next/router";
+
+// components
+import { SpreadsheetColumns, SpreadsheetIssues } from "components/core";
+import { CustomMenu, Spinner } from "components/ui";
+import { IssuePeekOverview } from "components/issues";
+// hooks
+import useIssuesProperties from "hooks/use-issue-properties";
+import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view";
+// types
+import { ICurrentUserResponse, IIssue, Properties, UserAuth } from "types";
+// constants
+import { SPREADSHEET_COLUMN } from "constants/spreadsheet";
+// icon
+import { PlusIcon } from "@heroicons/react/24/outline";
+
+type Props = {
+ handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
+ openIssuesListModal?: (() => void) | null;
+ disableUserActions: boolean;
+ user: ICurrentUserResponse | undefined;
+ userAuth: UserAuth;
+};
+
+export const SpreadsheetView: React.FC = ({
+ handleIssueAction,
+ openIssuesListModal,
+ disableUserActions,
+ user,
+ userAuth,
+}) => {
+ const [expandedIssues, setExpandedIssues] = useState([]);
+
+ const router = useRouter();
+ const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
+
+ const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
+
+ const { spreadsheetIssues, mutateIssues } = useSpreadsheetIssuesView();
+
+ const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
+
+ const columnData = SPREADSHEET_COLUMN.map((column) => ({
+ ...column,
+ isActive: properties
+ ? column.propertyName === "labels"
+ ? properties[column.propertyName as keyof Properties]
+ : column.propertyName === "title"
+ ? true
+ : properties[column.propertyName as keyof Properties]
+ : false,
+ }));
+
+ const gridTemplateColumns = columnData
+ .filter((column) => column.isActive)
+ .map((column) => column.colSize)
+ .join(" ");
+
+ return (
+ <>
+ mutateIssues()}
+ projectId={projectId?.toString() ?? ""}
+ workspaceSlug={workspaceSlug?.toString() ?? ""}
+ readOnly={disableUserActions}
+ />
+
+
+
+
+ {spreadsheetIssues ? (
+
+ {spreadsheetIssues.map((issue: IIssue, index) => (
+
+ ))}
+
+ {type === "issue" ? (
+
{
+ const e = new KeyboardEvent("keydown", { key: "c" });
+ document.dispatchEvent(e);
+ }}
+ >
+
+ Add Issue
+
+ ) : (
+ !disableUserActions && (
+
+
+ Add Issue
+
+ }
+ position="left"
+ optionsClassName="left-5 !w-36"
+ noBorder
+ >
+ {
+ const e = new KeyboardEvent("keydown", { key: "c" });
+ document.dispatchEvent(e);
+ }}
+ >
+ Create new
+
+ {openIssuesListModal && (
+
+ Add an existing issue
+
+ )}
+
+ )
+ )}
+
+
+ ) : (
+
+ )}
+
+ >
+ );
+};
diff --git a/apps/app/components/cycles/active-cycle-details.tsx b/web/components/cycles/active-cycle-details.tsx
similarity index 94%
rename from apps/app/components/cycles/active-cycle-details.tsx
rename to web/components/cycles/active-cycle-details.tsx
index bec200bd9..23fd68e75 100644
--- a/apps/app/components/cycles/active-cycle-details.tsx
+++ b/web/components/cycles/active-cycle-details.tsx
@@ -31,6 +31,8 @@ import {
CompletedStateIcon,
} from "components/icons";
import { StarIcon } from "@heroicons/react/24/outline";
+// components
+import { ViewIssueLabel } from "components/issues";
// helpers
import {
getDateRangeStatus,
@@ -441,7 +443,10 @@ export const ActiveCycleDetails: React.FC = () => {
issues.map((issue) => (
+ router.push(`/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`)
+ }
+ className="flex flex-wrap cursor-pointer rounded-md items-center justify-between gap-2 border border-custom-border-200 bg-custom-background-90 px-3 py-1.5"
>
@@ -474,27 +479,7 @@ export const ActiveCycleDetails: React.FC = () => {
>
{getPriorityIcon(issue.priority, "text-sm")}
- {issue.label_details.length > 0 ? (
-
- {issue.label_details.map((label) => (
-
-
- {label.name}
-
- ))}
-
- ) : (
- ""
- )}
+
{issue.assignees &&
issue.assignees.length > 0 &&
diff --git a/apps/app/components/cycles/active-cycle-stats.tsx b/web/components/cycles/active-cycle-stats.tsx
similarity index 100%
rename from apps/app/components/cycles/active-cycle-stats.tsx
rename to web/components/cycles/active-cycle-stats.tsx
diff --git a/apps/app/components/cycles/cycles-list/all-cycles-list.tsx b/web/components/cycles/cycles-list/all-cycles-list.tsx
similarity index 100%
rename from apps/app/components/cycles/cycles-list/all-cycles-list.tsx
rename to web/components/cycles/cycles-list/all-cycles-list.tsx
diff --git a/apps/app/components/cycles/cycles-list/completed-cycles-list.tsx b/web/components/cycles/cycles-list/completed-cycles-list.tsx
similarity index 100%
rename from apps/app/components/cycles/cycles-list/completed-cycles-list.tsx
rename to web/components/cycles/cycles-list/completed-cycles-list.tsx
diff --git a/apps/app/components/cycles/cycles-list/draft-cycles-list.tsx b/web/components/cycles/cycles-list/draft-cycles-list.tsx
similarity index 100%
rename from apps/app/components/cycles/cycles-list/draft-cycles-list.tsx
rename to web/components/cycles/cycles-list/draft-cycles-list.tsx
diff --git a/apps/app/components/cycles/cycles-list/index.ts b/web/components/cycles/cycles-list/index.ts
similarity index 100%
rename from apps/app/components/cycles/cycles-list/index.ts
rename to web/components/cycles/cycles-list/index.ts
diff --git a/apps/app/components/cycles/cycles-list/upcoming-cycles-list.tsx b/web/components/cycles/cycles-list/upcoming-cycles-list.tsx
similarity index 100%
rename from apps/app/components/cycles/cycles-list/upcoming-cycles-list.tsx
rename to web/components/cycles/cycles-list/upcoming-cycles-list.tsx
diff --git a/apps/app/components/cycles/cycles-view.tsx b/web/components/cycles/cycles-view.tsx
similarity index 99%
rename from apps/app/components/cycles/cycles-view.tsx
rename to web/components/cycles/cycles-view.tsx
index ede13b65e..6e07d896e 100644
--- a/apps/app/components/cycles/cycles-view.tsx
+++ b/web/components/cycles/cycles-view.tsx
@@ -190,7 +190,7 @@ export const CyclesView: React.FC
= ({ cycles, mutateCycles, viewType })
))}
) : viewType === "board" ? (
-
+
{cycles.map((cycle) => (
{
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+
+ const cycleStatus = getDateRangeStatus(data?.start_date, data?.end_date);
+
+ return (
+ router.push(`/${workspaceSlug}/projects/${data?.project}/cycles/${data?.id}`)}
+ >
+
+
+ {data?.name}
+
+ {renderShortDate(data?.start_date ?? "")} to {renderShortDate(data?.end_date ?? "")}
+
+
+ }
+ position="top-left"
+ >
+
+ {data?.name}
+
+
+
+ );
+};
+
+export const CycleGanttSidebarBlock = ({ data }: { data: ICycle }) => {
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+
+ const cycleStatus = getDateRangeStatus(data?.start_date, data?.end_date);
+
+ return (
+
router.push(`/${workspaceSlug}/projects/${data?.project}/cycles/${data?.id}`)}
+ >
+
+
{data?.name}
+
+ );
+};
diff --git a/apps/app/components/cycles/gantt-chart.tsx b/web/components/cycles/gantt-chart/cycle-issues-layout.tsx
similarity index 53%
rename from apps/app/components/cycles/gantt-chart.tsx
rename to web/components/cycles/gantt-chart/cycle-issues-layout.tsx
index fe276b50d..c18bc9346 100644
--- a/apps/app/components/cycles/gantt-chart.tsx
+++ b/web/components/cycles/gantt-chart/cycle-issues-layout.tsx
@@ -5,12 +5,10 @@ import useIssuesView from "hooks/use-issues-view";
import useUser from "hooks/use-user";
import useGanttChartCycleIssues from "hooks/gantt-chart/cycle-issues-view";
import { updateGanttIssue } from "components/gantt-chart/hooks/block-update";
+import useProjectDetails from "hooks/use-project-details";
// components
-import {
- GanttChartRoot,
- IssueGanttBlock,
- renderIssueBlocksStructure,
-} from "components/gantt-chart";
+import { GanttChartRoot, renderIssueBlocksStructure } from "components/gantt-chart";
+import { IssueGanttBlock, IssueGanttSidebarBlock } from "components/issues";
// types
import { IIssue } from "types";
@@ -21,6 +19,7 @@ export const CycleIssuesGanttChartView = () => {
const { orderBy } = useIssuesView();
const { user } = useUser();
+ const { projectDetails } = useProjectDetails();
const { ganttIssues, mutateGanttIssues } = useGanttChartCycleIssues(
workspaceSlug as string,
@@ -28,29 +27,25 @@ export const CycleIssuesGanttChartView = () => {
cycleId as string
);
- // rendering issues on gantt sidebar
- const GanttSidebarBlockView = ({ data }: any) => (
-
- );
+ const isAllowed = projectDetails?.member_role === 20 || projectDetails?.member_role === 15;
return (
-
+
updateGanttIssue(block, payload, mutateGanttIssues, user, workspaceSlug?.toString())
}
- sidebarBlockRender={(data: any) => }
- blockRender={(data: any) => }
- enableReorder={orderBy === "sort_order"}
+ SidebarBlockRender={IssueGanttSidebarBlock}
+ BlockRender={IssueGanttBlock}
+ enableBlockLeftResize={isAllowed}
+ enableBlockRightResize={isAllowed}
+ enableBlockMove={isAllowed}
+ enableReorder={orderBy === "sort_order" && isAllowed}
+ bottomSpacing
/>
);
diff --git a/apps/app/components/cycles/cycles-list-gantt-chart.tsx b/web/components/cycles/gantt-chart/cycles-list-layout.tsx
similarity index 75%
rename from apps/app/components/cycles/cycles-list-gantt-chart.tsx
rename to web/components/cycles/gantt-chart/cycles-list-layout.tsx
index 4ad0029d8..9614ea447 100644
--- a/apps/app/components/cycles/cycles-list-gantt-chart.tsx
+++ b/web/components/cycles/gantt-chart/cycles-list-layout.tsx
@@ -8,8 +8,10 @@ import { KeyedMutator } from "swr";
import cyclesService from "services/cycles.service";
// hooks
import useUser from "hooks/use-user";
+import useProjectDetails from "hooks/use-project-details";
// components
-import { CycleGanttBlock, GanttChartRoot, IBlockUpdateData } from "components/gantt-chart";
+import { GanttChartRoot, IBlockUpdateData } from "components/gantt-chart";
+import { CycleGanttBlock, CycleGanttSidebarBlock } from "components/cycles";
// types
import { ICycle } from "types";
@@ -23,17 +25,7 @@ export const CyclesListGanttChartView: FC
= ({ cycles, mutateCycles }) =>
const { workspaceSlug } = router.query;
const { user } = useUser();
-
- // rendering issues on gantt sidebar
- const GanttSidebarBlockView = ({ data }: any) => (
-
- );
+ const { projectDetails } = useProjectDetails();
const handleCycleUpdate = (cycle: ICycle, payload: IBlockUpdateData) => {
if (!workspaceSlug || !user) return;
@@ -81,6 +73,8 @@ export const CyclesListGanttChartView: FC = ({ cycles, mutateCycles }) =>
}))
: [];
+ const isAllowed = projectDetails?.member_role === 20 || projectDetails?.member_role === 15;
+
return (
= ({ cycles, mutateCycles }) =>
loaderTitle="Cycles"
blocks={cycles ? blockFormat(cycles) : null}
blockUpdateHandler={(block, payload) => handleCycleUpdate(block, payload)}
- sidebarBlockRender={(data: any) => }
- blockRender={(data: any) => }
- enableLeftDrag={false}
- enableRightDrag={false}
+ SidebarBlockRender={CycleGanttSidebarBlock}
+ BlockRender={CycleGanttBlock}
+ enableBlockLeftResize={false}
+ enableBlockRightResize={false}
+ enableBlockMove={false}
+ enableReorder={isAllowed}
/>
);
diff --git a/web/components/cycles/gantt-chart/index.ts b/web/components/cycles/gantt-chart/index.ts
new file mode 100644
index 000000000..e4850b2e2
--- /dev/null
+++ b/web/components/cycles/gantt-chart/index.ts
@@ -0,0 +1,3 @@
+export * from "./blocks";
+export * from "./cycle-issues-layout";
+export * from "./cycles-list-layout";
diff --git a/apps/app/components/cycles/index.ts b/web/components/cycles/index.ts
similarity index 91%
rename from apps/app/components/cycles/index.ts
rename to web/components/cycles/index.ts
index 40355d574..4b43b3a74 100644
--- a/apps/app/components/cycles/index.ts
+++ b/web/components/cycles/index.ts
@@ -1,11 +1,10 @@
export * from "./cycles-list";
export * from "./active-cycle-details";
export * from "./active-cycle-stats";
-export * from "./cycles-list-gantt-chart";
+export * from "./gantt-chart";
export * from "./cycles-view";
export * from "./delete-cycle-modal";
export * from "./form";
-export * from "./gantt-chart";
export * from "./modal";
export * from "./select";
export * from "./sidebar";
diff --git a/apps/app/components/cycles/modal.tsx b/web/components/cycles/modal.tsx
similarity index 100%
rename from apps/app/components/cycles/modal.tsx
rename to web/components/cycles/modal.tsx
diff --git a/apps/app/components/cycles/select.tsx b/web/components/cycles/select.tsx
similarity index 100%
rename from apps/app/components/cycles/select.tsx
rename to web/components/cycles/select.tsx
diff --git a/apps/app/components/cycles/sidebar.tsx b/web/components/cycles/sidebar.tsx
similarity index 100%
rename from apps/app/components/cycles/sidebar.tsx
rename to web/components/cycles/sidebar.tsx
diff --git a/apps/app/components/cycles/single-cycle-card.tsx b/web/components/cycles/single-cycle-card.tsx
similarity index 100%
rename from apps/app/components/cycles/single-cycle-card.tsx
rename to web/components/cycles/single-cycle-card.tsx
diff --git a/apps/app/components/cycles/single-cycle-list.tsx b/web/components/cycles/single-cycle-list.tsx
similarity index 99%
rename from apps/app/components/cycles/single-cycle-list.tsx
rename to web/components/cycles/single-cycle-list.tsx
index 7518568ed..ec01da9e7 100644
--- a/apps/app/components/cycles/single-cycle-list.tsx
+++ b/web/components/cycles/single-cycle-list.tsx
@@ -106,6 +106,7 @@ function RadialProgressBar({ progress }: progress) {
);
}
+
export const SingleCycleList: React.FC
= ({
cycle,
handleEditCycle,
diff --git a/apps/app/components/cycles/transfer-issues-modal.tsx b/web/components/cycles/transfer-issues-modal.tsx
similarity index 100%
rename from apps/app/components/cycles/transfer-issues-modal.tsx
rename to web/components/cycles/transfer-issues-modal.tsx
diff --git a/apps/app/components/cycles/transfer-issues.tsx b/web/components/cycles/transfer-issues.tsx
similarity index 100%
rename from apps/app/components/cycles/transfer-issues.tsx
rename to web/components/cycles/transfer-issues.tsx
diff --git a/apps/app/components/dnd/StrictModeDroppable.tsx b/web/components/dnd/StrictModeDroppable.tsx
similarity index 100%
rename from apps/app/components/dnd/StrictModeDroppable.tsx
rename to web/components/dnd/StrictModeDroppable.tsx
diff --git a/apps/app/components/emoji-icon-picker/emojis.json b/web/components/emoji-icon-picker/emojis.json
similarity index 100%
rename from apps/app/components/emoji-icon-picker/emojis.json
rename to web/components/emoji-icon-picker/emojis.json
diff --git a/apps/app/components/emoji-icon-picker/helpers.ts b/web/components/emoji-icon-picker/helpers.ts
similarity index 100%
rename from apps/app/components/emoji-icon-picker/helpers.ts
rename to web/components/emoji-icon-picker/helpers.ts
diff --git a/apps/app/components/emoji-icon-picker/icons.json b/web/components/emoji-icon-picker/icons.json
similarity index 100%
rename from apps/app/components/emoji-icon-picker/icons.json
rename to web/components/emoji-icon-picker/icons.json
diff --git a/apps/app/components/emoji-icon-picker/index.tsx b/web/components/emoji-icon-picker/index.tsx
similarity index 96%
rename from apps/app/components/emoji-icon-picker/index.tsx
rename to web/components/emoji-icon-picker/index.tsx
index ffe8b33d6..7af3bb74f 100644
--- a/apps/app/components/emoji-icon-picker/index.tsx
+++ b/web/components/emoji-icon-picker/index.tsx
@@ -23,7 +23,13 @@ const tabOptions = [
},
];
-const EmojiIconPicker: React.FC = ({ label, value, onChange, onIconColorChange }) => {
+const EmojiIconPicker: React.FC = ({
+ label,
+ value,
+ onChange,
+ onIconColorChange,
+ disabled = false,
+}) => {
const [isOpen, setIsOpen] = useState(false);
const [openColorPicker, setOpenColorPicker] = useState(false);
const [activeColor, setActiveColor] = useState("rgb(var(--color-text-200))");
@@ -40,7 +46,11 @@ const EmojiIconPicker: React.FC = ({ label, value, onChange, onIconColorC
return (
- setIsOpen((prev) => !prev)} className="outline-none">
+ setIsOpen((prev) => !prev)}
+ className="outline-none"
+ disabled={disabled}
+ >
{label}
void;
onIconColorChange?: (data: any) => void;
+ disabled?: boolean;
};
diff --git a/apps/app/components/estimates/create-update-estimate-modal.tsx b/web/components/estimates/create-update-estimate-modal.tsx
similarity index 100%
rename from apps/app/components/estimates/create-update-estimate-modal.tsx
rename to web/components/estimates/create-update-estimate-modal.tsx
diff --git a/apps/app/components/estimates/delete-estimate-modal.tsx b/web/components/estimates/delete-estimate-modal.tsx
similarity index 100%
rename from apps/app/components/estimates/delete-estimate-modal.tsx
rename to web/components/estimates/delete-estimate-modal.tsx
diff --git a/apps/app/components/estimates/index.tsx b/web/components/estimates/index.tsx
similarity index 100%
rename from apps/app/components/estimates/index.tsx
rename to web/components/estimates/index.tsx
diff --git a/apps/app/components/estimates/single-estimate.tsx b/web/components/estimates/single-estimate.tsx
similarity index 100%
rename from apps/app/components/estimates/single-estimate.tsx
rename to web/components/estimates/single-estimate.tsx
diff --git a/apps/app/components/exporter/export-modal.tsx b/web/components/exporter/export-modal.tsx
similarity index 100%
rename from apps/app/components/exporter/export-modal.tsx
rename to web/components/exporter/export-modal.tsx
diff --git a/apps/app/components/exporter/guide.tsx b/web/components/exporter/guide.tsx
similarity index 100%
rename from apps/app/components/exporter/guide.tsx
rename to web/components/exporter/guide.tsx
diff --git a/apps/app/components/exporter/index.tsx b/web/components/exporter/index.tsx
similarity index 100%
rename from apps/app/components/exporter/index.tsx
rename to web/components/exporter/index.tsx
diff --git a/apps/app/components/exporter/single-export.tsx b/web/components/exporter/single-export.tsx
similarity index 95%
rename from apps/app/components/exporter/single-export.tsx
rename to web/components/exporter/single-export.tsx
index 34eb1510a..c8ef2dc1a 100644
--- a/apps/app/components/exporter/single-export.tsx
+++ b/web/components/exporter/single-export.tsx
@@ -1,6 +1,4 @@
import React from "react";
-// next imports
-import Link from "next/link";
// ui
import { PrimaryButton } from "components/ui"; // icons
// helpers
@@ -65,11 +63,11 @@ export const SingleExport: React.FC = ({ service, refreshing }) => {
<>
{service.status == "completed" && (
)}
>
diff --git a/web/components/gantt-chart/blocks/blocks-display.tsx b/web/components/gantt-chart/blocks/blocks-display.tsx
new file mode 100644
index 000000000..f0e7279be
--- /dev/null
+++ b/web/components/gantt-chart/blocks/blocks-display.tsx
@@ -0,0 +1,100 @@
+import { FC } from "react";
+
+// hooks
+import { useChart } from "../hooks";
+// helpers
+import { ChartDraggable } from "../helpers/draggable";
+import { renderDateFormat } from "helpers/date-time.helper";
+// types
+import { IBlockUpdateData, IGanttBlock } from "../types";
+
+export const GanttChartBlocks: FC<{
+ itemsContainerWidth: number;
+ blocks: IGanttBlock[] | null;
+ BlockRender: React.FC;
+ blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
+ enableBlockLeftResize: boolean;
+ enableBlockRightResize: boolean;
+ enableBlockMove: boolean;
+}> = ({
+ itemsContainerWidth,
+ blocks,
+ BlockRender,
+ blockUpdateHandler,
+ enableBlockLeftResize,
+ enableBlockRightResize,
+ enableBlockMove,
+}) => {
+ const { activeBlock, dispatch } = useChart();
+
+ // update the active block on hover
+ const updateActiveBlock = (block: IGanttBlock | null) => {
+ dispatch({
+ type: "PARTIAL_UPDATE",
+ payload: {
+ activeBlock: block,
+ },
+ });
+ };
+
+ const handleChartBlockPosition = (
+ block: IGanttBlock,
+ totalBlockShifts: number,
+ dragDirection: "left" | "right" | "move"
+ ) => {
+ const originalStartDate = new Date(block.start_date);
+ const updatedStartDate = new Date(originalStartDate);
+
+ const originalTargetDate = new Date(block.target_date);
+ const updatedTargetDate = new Date(originalTargetDate);
+
+ // update the start date on left resize
+ if (dragDirection === "left")
+ updatedStartDate.setDate(originalStartDate.getDate() - totalBlockShifts);
+ // update the target date on right resize
+ else if (dragDirection === "right")
+ updatedTargetDate.setDate(originalTargetDate.getDate() + totalBlockShifts);
+ // update both the dates on x-axis move
+ else if (dragDirection === "move") {
+ updatedStartDate.setDate(originalStartDate.getDate() + totalBlockShifts);
+ updatedTargetDate.setDate(originalTargetDate.getDate() + totalBlockShifts);
+ }
+
+ // call the block update handler with the updated dates
+ blockUpdateHandler(block.data, {
+ start_date: renderDateFormat(updatedStartDate),
+ target_date: renderDateFormat(updatedTargetDate),
+ });
+ };
+
+ return (
+
+ {blocks &&
+ blocks.length > 0 &&
+ blocks.map(
+ (block) =>
+ block.start_date &&
+ block.target_date && (
+
updateActiveBlock(block)}
+ onMouseLeave={() => updateActiveBlock(null)}
+ >
+ handleChartBlockPosition(block, ...args)}
+ enableBlockLeftResize={enableBlockLeftResize}
+ enableBlockRightResize={enableBlockRightResize}
+ enableBlockMove={enableBlockMove}
+ />
+
+ )
+ )}
+
+ );
+};
diff --git a/apps/app/components/gantt-chart/blocks/index.ts b/web/components/gantt-chart/blocks/index.ts
similarity index 57%
rename from apps/app/components/gantt-chart/blocks/index.ts
rename to web/components/gantt-chart/blocks/index.ts
index 8773b2797..18ca5da9e 100644
--- a/apps/app/components/gantt-chart/blocks/index.ts
+++ b/web/components/gantt-chart/blocks/index.ts
@@ -1,2 +1 @@
-export * from "./block";
export * from "./blocks-display";
diff --git a/apps/app/components/gantt-chart/chart/bi-week.tsx b/web/components/gantt-chart/chart/bi-week.tsx
similarity index 100%
rename from apps/app/components/gantt-chart/chart/bi-week.tsx
rename to web/components/gantt-chart/chart/bi-week.tsx
diff --git a/apps/app/components/gantt-chart/chart/day.tsx b/web/components/gantt-chart/chart/day.tsx
similarity index 100%
rename from apps/app/components/gantt-chart/chart/day.tsx
rename to web/components/gantt-chart/chart/day.tsx
diff --git a/apps/app/components/gantt-chart/chart/hours.tsx b/web/components/gantt-chart/chart/hours.tsx
similarity index 100%
rename from apps/app/components/gantt-chart/chart/hours.tsx
rename to web/components/gantt-chart/chart/hours.tsx
diff --git a/apps/app/components/gantt-chart/chart/index.tsx b/web/components/gantt-chart/chart/index.tsx
similarity index 77%
rename from apps/app/components/gantt-chart/chart/index.tsx
rename to web/components/gantt-chart/chart/index.tsx
index 0cc8a14ee..aa79ae19c 100644
--- a/apps/app/components/gantt-chart/chart/index.tsx
+++ b/web/components/gantt-chart/chart/index.tsx
@@ -3,6 +3,7 @@ import { FC, useEffect, useState } from "react";
import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/20/solid";
// components
import { GanttChartBlocks } from "components/gantt-chart";
+import { GanttSidebar } from "../sidebar";
// import { HourChartView } from "./hours";
// import { DayChartView } from "./day";
// import { WeekChartView } from "./week";
@@ -25,7 +26,7 @@ import {
getMonthChartItemPositionWidthInMonth,
} from "../views";
// types
-import { ChartDataType, IBlockUpdateData, IGanttBlock } from "../types";
+import { ChartDataType, IBlockUpdateData, IGanttBlock, TGanttViews } from "../types";
// data
import { currentViewDataWithView } from "../data";
// context
@@ -33,15 +34,17 @@ import { useChart } from "../hooks";
type ChartViewRootProps = {
border: boolean;
- title: null | string;
+ title: string;
loaderTitle: string;
blocks: IGanttBlock[] | null;
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
- sidebarBlockRender: FC;
- blockRender: FC;
- enableLeftDrag: boolean;
- enableRightDrag: boolean;
+ SidebarBlockRender: React.FC;
+ BlockRender: React.FC;
+ enableBlockLeftResize: boolean;
+ enableBlockRightResize: boolean;
+ enableBlockMove: boolean;
enableReorder: boolean;
+ bottomSpacing: boolean;
};
export const ChartViewRoot: FC = ({
@@ -50,22 +53,24 @@ export const ChartViewRoot: FC = ({
blocks = null,
loaderTitle,
blockUpdateHandler,
- sidebarBlockRender,
- blockRender,
- enableLeftDrag,
- enableRightDrag,
+ SidebarBlockRender,
+ BlockRender,
+ enableBlockLeftResize,
+ enableBlockRightResize,
+ enableBlockMove,
enableReorder,
+ bottomSpacing,
}) => {
- const { currentView, currentViewData, renderView, dispatch, allViews } = useChart();
-
const [itemsContainerWidth, setItemsContainerWidth] = useState(0);
const [fullScreenMode, setFullScreenMode] = useState(false);
- const [blocksSidebarView, setBlocksSidebarView] = useState(false);
// blocks state management starts
const [chartBlocks, setChartBlocks] = useState(null);
- const renderBlockStructure = (view: any, blocks: IGanttBlock[]) =>
+ const { currentView, currentViewData, renderView, dispatch, allViews, updateScrollLeft } =
+ useChart();
+
+ const renderBlockStructure = (view: any, blocks: IGanttBlock[] | null) =>
blocks && blocks.length > 0
? blocks.map((block: any) => ({
...block,
@@ -74,16 +79,16 @@ export const ChartViewRoot: FC = ({
: [];
useEffect(() => {
- if (currentViewData && blocks && blocks.length > 0)
+ if (currentViewData && blocks)
setChartBlocks(() => renderBlockStructure(currentViewData, blocks));
}, [currentViewData, blocks]);
// blocks state management ends
- const handleChartView = (key: string) => updateCurrentViewRenderPayload(null, key);
+ const handleChartView = (key: TGanttViews) => updateCurrentViewRenderPayload(null, key);
- const updateCurrentViewRenderPayload = (side: null | "left" | "right", view: string) => {
- const selectedCurrentView = view;
+ const updateCurrentViewRenderPayload = (side: null | "left" | "right", view: TGanttViews) => {
+ const selectedCurrentView: TGanttViews = view;
const selectedCurrentViewData: ChartDataType | undefined =
selectedCurrentView && selectedCurrentView === currentViewData?.key
? currentViewData
@@ -155,6 +160,9 @@ export const ChartViewRoot: FC = ({
const updatingCurrentLeftScrollPosition = (width: number) => {
const scrollContainer = document.getElementById("scroll-container") as HTMLElement;
+
+ if (!scrollContainer) return;
+
scrollContainer.scrollLeft = width + scrollContainer?.scrollLeft;
setItemsContainerWidth(width + scrollContainer?.scrollLeft);
};
@@ -195,6 +203,8 @@ export const ChartViewRoot: FC = ({
const clientVisibleWidth: number = scrollContainer?.clientWidth;
const currentScrollPosition: number = scrollContainer?.scrollLeft;
+ updateScrollLeft(currentScrollPosition);
+
const approxRangeLeft: number =
scrollWidth >= clientVisibleWidth + 1000 ? 1000 : scrollWidth - clientVisibleWidth;
const approxRangeRight: number = scrollWidth - (approxRangeLeft + clientVisibleWidth);
@@ -205,16 +215,6 @@ export const ChartViewRoot: FC = ({
updateCurrentViewRenderPayload("left", currentView);
};
- useEffect(() => {
- const scrollContainer = document.getElementById("scroll-container") as HTMLElement;
-
- scrollContainer.addEventListener("scroll", onScroll);
-
- return () => {
- scrollContainer.removeEventListener("scroll", onScroll);
- };
- }, [renderView]);
-
return (
= ({
border ? `border border-custom-border-200` : ``
} flex h-full flex-col rounded-sm select-none bg-custom-background-100 shadow`}
>
- {/* chart title */}
- {/*
- {title && (
-
-
{title}
-
- Gantt View Beta
-
-
- )}
- {blocks === null ? (
-
Loading...
- ) : (
-
- {blocks.length} {loaderTitle}
-
- )}
-
*/}
-
{/* chart header */}
-
- {/*
setBlocksSidebarView(() => !blocksSidebarView)}
- >
- {blocksSidebarView ? (
-
- ) : (
-
- )}
-
*/}
-
+
{title && (
{title}
-
+ {/*
Gantt View Beta
-
+
*/}
)}
@@ -282,7 +252,7 @@ export const ChartViewRoot: FC
= ({
allViews.map((_chatView: any, _idx: any) => (
= ({
Today
@@ -316,26 +286,30 @@ export const ChartViewRoot: FC = ({
{/* content */}
-
+
+
- {/* blocks components */}
- {currentView && currentViewData && (
-
- )}
-
- {/* chart */}
{/* {currentView && currentView === "hours" && } */}
{/* {currentView && currentView === "day" && } */}
{/* {currentView && currentView === "week" && } */}
@@ -343,6 +317,19 @@ export const ChartViewRoot: FC = ({
{currentView && currentView === "month" && }
{/* {currentView && currentView === "quarter" && } */}
{/* {currentView && currentView === "year" && } */}
+
+ {/* blocks */}
+ {currentView && currentViewData && (
+
+ )}
diff --git a/apps/app/components/gantt-chart/chart/month.tsx b/web/components/gantt-chart/chart/month.tsx
similarity index 53%
rename from apps/app/components/gantt-chart/chart/month.tsx
rename to web/components/gantt-chart/chart/month.tsx
index b6c68b5d1..2a4a67daf 100644
--- a/apps/app/components/gantt-chart/chart/month.tsx
+++ b/web/components/gantt-chart/chart/month.tsx
@@ -17,9 +17,38 @@ export const MonthChartView: FC
= () => {
monthBlocks.length > 0 &&
monthBlocks.map((block, _idxRoot) => (
-
-
- {block?.title}
+
+
+
+
+ {block?.children &&
+ block?.children.length > 0 &&
+ block?.children.map((monthDay, _idx) => (
+
+
+
+ {monthDay.dayData.shortTitle[0]}
+ {" "}
+
+ {monthDay.day}
+
+
+
+ ))}
@@ -28,19 +57,10 @@ export const MonthChartView: FC
= () => {
block?.children.length > 0 &&
block?.children.map((monthDay, _idx) => (
-
= () => {
: ``
}`}
>
- {monthDay?.today && (
+ {/* {monthDay?.today && (
- )}
+ )} */}
))}
diff --git a/apps/app/components/gantt-chart/chart/quarter.tsx b/web/components/gantt-chart/chart/quarter.tsx
similarity index 100%
rename from apps/app/components/gantt-chart/chart/quarter.tsx
rename to web/components/gantt-chart/chart/quarter.tsx
diff --git a/apps/app/components/gantt-chart/chart/week.tsx b/web/components/gantt-chart/chart/week.tsx
similarity index 100%
rename from apps/app/components/gantt-chart/chart/week.tsx
rename to web/components/gantt-chart/chart/week.tsx
diff --git a/apps/app/components/gantt-chart/chart/year.tsx b/web/components/gantt-chart/chart/year.tsx
similarity index 100%
rename from apps/app/components/gantt-chart/chart/year.tsx
rename to web/components/gantt-chart/chart/year.tsx
diff --git a/apps/app/components/gantt-chart/contexts/index.tsx b/web/components/gantt-chart/contexts/index.tsx
similarity index 83%
rename from apps/app/components/gantt-chart/contexts/index.tsx
rename to web/components/gantt-chart/contexts/index.tsx
index 4f858cf33..05dfbe678 100644
--- a/apps/app/components/gantt-chart/contexts/index.tsx
+++ b/web/components/gantt-chart/contexts/index.tsx
@@ -32,16 +32,27 @@ export const ChartContextProvider: React.FC<{ children: React.ReactNode }> = ({
currentViewData: currentViewDataWithView(initialView),
renderView: [],
allViews: allViewsWithData,
+ activeBlock: null,
});
+ const [scrollLeft, setScrollLeft] = useState(0);
+
const handleDispatch = (action: ChartContextActionPayload): ChartContextData => {
const newState = chartReducer(state, action);
+
dispatch(() => newState);
+
return newState;
};
+ const updateScrollLeft = (scrollLeft: number) => {
+ setScrollLeft(scrollLeft);
+ };
+
return (
-
+
{children}
);
diff --git a/apps/app/components/gantt-chart/data/index.ts b/web/components/gantt-chart/data/index.ts
similarity index 97%
rename from apps/app/components/gantt-chart/data/index.ts
rename to web/components/gantt-chart/data/index.ts
index 4be799998..4e1921434 100644
--- a/apps/app/components/gantt-chart/data/index.ts
+++ b/web/components/gantt-chart/data/index.ts
@@ -108,8 +108,8 @@ export const allViewsWithData: ChartDataType[] = [
startDate: new Date(),
currentDate: new Date(),
endDate: new Date(),
- approxFilterRange: 8,
- width: 80, // it will preview monthly all dates with weekends highlighted with no limitations ex: title (1, 2, 3)
+ approxFilterRange: 6,
+ width: 55, // it will preview monthly all dates with weekends highlighted with no limitations ex: title (1, 2, 3)
},
},
// {
diff --git a/apps/app/components/gantt-chart/helpers/block-structure.tsx b/web/components/gantt-chart/helpers/block-structure.tsx
similarity index 100%
rename from apps/app/components/gantt-chart/helpers/block-structure.tsx
rename to web/components/gantt-chart/helpers/block-structure.tsx
diff --git a/web/components/gantt-chart/helpers/draggable.tsx b/web/components/gantt-chart/helpers/draggable.tsx
new file mode 100644
index 000000000..b665bf5d3
--- /dev/null
+++ b/web/components/gantt-chart/helpers/draggable.tsx
@@ -0,0 +1,322 @@
+import React, { useEffect, useRef, useState } from "react";
+
+// icons
+import { Icon } from "components/ui";
+// hooks
+import { useChart } from "../hooks";
+// types
+import { IGanttBlock } from "../types";
+
+type Props = {
+ block: IGanttBlock;
+ BlockRender: React.FC;
+ handleBlock: (totalBlockShifts: number, dragDirection: "left" | "right" | "move") => void;
+ enableBlockLeftResize: boolean;
+ enableBlockRightResize: boolean;
+ enableBlockMove: boolean;
+};
+
+export const ChartDraggable: React.FC = ({
+ block,
+ BlockRender,
+ handleBlock,
+ enableBlockLeftResize,
+ enableBlockRightResize,
+ enableBlockMove,
+}) => {
+ const [isLeftResizing, setIsLeftResizing] = useState(false);
+ const [isRightResizing, setIsRightResizing] = useState(false);
+ const [isMoving, setIsMoving] = useState(false);
+ const [posFromLeft, setPosFromLeft] = useState(null);
+
+ const resizableRef = useRef(null);
+
+ const { currentViewData, scrollLeft } = useChart();
+
+ // check if cursor reaches either end while resizing/dragging
+ const checkScrollEnd = (e: MouseEvent): number => {
+ const SCROLL_THRESHOLD = 70;
+
+ let delWidth = 0;
+
+ const ganttContainer = document.querySelector("#gantt-container") as HTMLElement;
+ const ganttSidebar = document.querySelector("#gantt-sidebar") as HTMLElement;
+
+ const scrollContainer = document.querySelector("#scroll-container") as HTMLElement;
+
+ if (!ganttContainer || !ganttSidebar || !scrollContainer) return 0;
+
+ const posFromLeft = e.clientX;
+ // manually scroll to left if reached the left end while dragging
+ if (
+ posFromLeft - (ganttContainer.getBoundingClientRect().left + ganttSidebar.clientWidth) <=
+ SCROLL_THRESHOLD
+ ) {
+ if (e.movementX > 0) return 0;
+
+ delWidth = -5;
+
+ scrollContainer.scrollBy(delWidth, 0);
+ } else delWidth = e.movementX;
+
+ // manually scroll to right if reached the right end while dragging
+ const posFromRight = ganttContainer.getBoundingClientRect().right - e.clientX;
+ if (posFromRight <= SCROLL_THRESHOLD) {
+ if (e.movementX < 0) return 0;
+
+ delWidth = 5;
+
+ scrollContainer.scrollBy(delWidth, 0);
+ } else delWidth = e.movementX;
+
+ return delWidth;
+ };
+
+ // handle block resize from the left end
+ const handleBlockLeftResize = (e: React.MouseEvent) => {
+ if (!currentViewData || !resizableRef.current || !block.position) return;
+
+ if (e.button !== 0) return;
+
+ const resizableDiv = resizableRef.current;
+
+ const columnWidth = currentViewData.data.width;
+
+ const blockInitialWidth =
+ resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10);
+
+ let initialWidth = resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10);
+ let initialMarginLeft = parseInt(resizableDiv.style.marginLeft);
+
+ const handleMouseMove = (e: MouseEvent) => {
+ let delWidth = 0;
+
+ delWidth = checkScrollEnd(e);
+
+ // calculate new width and update the initialMarginLeft using -=
+ const newWidth = Math.round((initialWidth -= delWidth) / columnWidth) * columnWidth;
+ // calculate new marginLeft and update the initial marginLeft to the newly calculated one
+ const newMarginLeft = initialMarginLeft - (newWidth - (block.position?.width ?? 0));
+ initialMarginLeft = newMarginLeft;
+
+ // block needs to be at least 1 column wide
+ if (newWidth < columnWidth) return;
+
+ resizableDiv.style.width = `${newWidth}px`;
+ resizableDiv.style.marginLeft = `${newMarginLeft}px`;
+
+ if (block.position) {
+ block.position.width = newWidth;
+ block.position.marginLeft = newMarginLeft;
+ }
+ };
+
+ // remove event listeners and call block handler with the updated start date
+ const handleMouseUp = () => {
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+
+ const totalBlockShifts = Math.ceil(
+ (resizableDiv.clientWidth - blockInitialWidth) / columnWidth
+ );
+
+ handleBlock(totalBlockShifts, "left");
+ };
+
+ document.addEventListener("mousemove", handleMouseMove);
+ document.addEventListener("mouseup", handleMouseUp);
+ };
+
+ // handle block resize from the right end
+ const handleBlockRightResize = (e: React.MouseEvent) => {
+ if (!currentViewData || !resizableRef.current || !block.position) return;
+
+ if (e.button !== 0) return;
+
+ const resizableDiv = resizableRef.current;
+
+ const columnWidth = currentViewData.data.width;
+
+ const blockInitialWidth =
+ resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10);
+
+ let initialWidth = resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10);
+
+ const handleMouseMove = (e: MouseEvent) => {
+ let delWidth = 0;
+
+ delWidth = checkScrollEnd(e);
+
+ // calculate new width and update the initialMarginLeft using +=
+ const newWidth = Math.round((initialWidth += delWidth) / columnWidth) * columnWidth;
+
+ // block needs to be at least 1 column wide
+ if (newWidth < columnWidth) return;
+
+ resizableDiv.style.width = `${Math.max(newWidth, 80)}px`;
+ if (block.position) block.position.width = Math.max(newWidth, 80);
+ };
+
+ // remove event listeners and call block handler with the updated target date
+ const handleMouseUp = () => {
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+
+ const totalBlockShifts = Math.ceil(
+ (resizableDiv.clientWidth - blockInitialWidth) / columnWidth
+ );
+
+ handleBlock(totalBlockShifts, "right");
+ };
+
+ document.addEventListener("mousemove", handleMouseMove);
+ document.addEventListener("mouseup", handleMouseUp);
+ };
+
+ // handle block x-axis move
+ const handleBlockMove = (e: React.MouseEvent) => {
+ if (!enableBlockMove || !currentViewData || !resizableRef.current || !block.position) return;
+
+ if (e.button !== 0) return;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ setIsMoving(true);
+
+ const resizableDiv = resizableRef.current;
+
+ const columnWidth = currentViewData.data.width;
+
+ const blockInitialMarginLeft = parseInt(resizableDiv.style.marginLeft);
+
+ let initialMarginLeft = parseInt(resizableDiv.style.marginLeft);
+
+ const handleMouseMove = (e: MouseEvent) => {
+ let delWidth = 0;
+
+ delWidth = checkScrollEnd(e);
+
+ // calculate new marginLeft and update the initial marginLeft using -=
+ const newMarginLeft = Math.round((initialMarginLeft += delWidth) / columnWidth) * columnWidth;
+
+ resizableDiv.style.marginLeft = `${newMarginLeft}px`;
+
+ if (block.position) block.position.marginLeft = newMarginLeft;
+ };
+
+ // remove event listeners and call block handler with the updated dates
+ const handleMouseUp = () => {
+ setIsMoving(false);
+
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+
+ const totalBlockShifts = Math.ceil(
+ (parseInt(resizableDiv.style.marginLeft) - blockInitialMarginLeft) / columnWidth
+ );
+
+ handleBlock(totalBlockShifts, "move");
+ };
+
+ document.addEventListener("mousemove", handleMouseMove);
+ document.addEventListener("mouseup", handleMouseUp);
+ };
+
+ // scroll to a hidden block
+ const handleScrollToBlock = () => {
+ const scrollContainer = document.querySelector("#scroll-container") as HTMLElement;
+
+ if (!scrollContainer || !block.position) return;
+
+ // update container's scroll position to the block's position
+ scrollContainer.scrollLeft = block.position.marginLeft - 4;
+ };
+
+ // update block position from viewport's left end on scroll
+ useEffect(() => {
+ const block = resizableRef.current;
+
+ if (!block) return;
+
+ setPosFromLeft(block.getBoundingClientRect().left);
+ }, [scrollLeft]);
+
+ // check if block is hidden on either side
+ const isBlockHiddenOnLeft =
+ block.position?.marginLeft &&
+ block.position?.width &&
+ scrollLeft > block.position.marginLeft + block.position.width;
+ const isBlockHiddenOnRight = posFromLeft && window && posFromLeft > window.innerWidth;
+
+ return (
+ <>
+ {/* move to left side hidden block button */}
+ {isBlockHiddenOnLeft && (
+
+
+
+ )}
+ {/* move to right side hidden block button */}
+ {isBlockHiddenOnRight && (
+
+
+
+ )}
+
+ {/* left resize drag handle */}
+ {enableBlockLeftResize && (
+ <>
+
setIsLeftResizing(true)}
+ onMouseLeave={() => setIsLeftResizing(false)}
+ className="absolute top-1/2 -left-2.5 -translate-y-1/2 z-[3] w-6 h-full rounded-md cursor-col-resize"
+ />
+
+ >
+ )}
+
+
+
+ {/* right resize drag handle */}
+ {enableBlockRightResize && (
+ <>
+
setIsRightResizing(true)}
+ onMouseLeave={() => setIsRightResizing(false)}
+ className="absolute top-1/2 -right-2.5 -translate-y-1/2 z-[2] w-6 h-full rounded-md cursor-col-resize"
+ />
+
+ >
+ )}
+
+ >
+ );
+};
diff --git a/apps/app/components/gantt-chart/helpers/index.ts b/web/components/gantt-chart/helpers/index.ts
similarity index 100%
rename from apps/app/components/gantt-chart/helpers/index.ts
rename to web/components/gantt-chart/helpers/index.ts
diff --git a/apps/app/components/gantt-chart/hooks/block-update.tsx b/web/components/gantt-chart/hooks/block-update.tsx
similarity index 100%
rename from apps/app/components/gantt-chart/hooks/block-update.tsx
rename to web/components/gantt-chart/hooks/block-update.tsx
diff --git a/apps/app/components/gantt-chart/hooks/index.tsx b/web/components/gantt-chart/hooks/index.tsx
similarity index 75%
rename from apps/app/components/gantt-chart/hooks/index.tsx
rename to web/components/gantt-chart/hooks/index.tsx
index a26b56f84..5fb9bee3f 100644
--- a/apps/app/components/gantt-chart/hooks/index.tsx
+++ b/web/components/gantt-chart/hooks/index.tsx
@@ -7,9 +7,7 @@ import { ChartContext } from "../contexts";
export const useChart = (): ChartContextReducer => {
const context = useContext(ChartContext);
- if (!context) {
- throw new Error("useChart must be used within a GanttChart");
- }
+ if (!context) throw new Error("useChart must be used within a GanttChart");
return context;
};
diff --git a/apps/app/components/gantt-chart/index.ts b/web/components/gantt-chart/index.ts
similarity index 100%
rename from apps/app/components/gantt-chart/index.ts
rename to web/components/gantt-chart/index.ts
diff --git a/apps/app/components/gantt-chart/root.tsx b/web/components/gantt-chart/root.tsx
similarity index 57%
rename from apps/app/components/gantt-chart/root.tsx
rename to web/components/gantt-chart/root.tsx
index 077e8a896..5acedd53e 100644
--- a/apps/app/components/gantt-chart/root.tsx
+++ b/web/components/gantt-chart/root.tsx
@@ -8,28 +8,32 @@ import { IBlockUpdateData, IGanttBlock } from "./types";
type GanttChartRootProps = {
border?: boolean;
- title: null | string;
+ title: string;
loaderTitle: string;
blocks: IGanttBlock[] | null;
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
- sidebarBlockRender: FC
;
- blockRender: FC;
- enableLeftDrag?: boolean;
- enableRightDrag?: boolean;
+ SidebarBlockRender: FC;
+ BlockRender: FC;
+ enableBlockLeftResize?: boolean;
+ enableBlockRightResize?: boolean;
+ enableBlockMove?: boolean;
enableReorder?: boolean;
+ bottomSpacing?: boolean;
};
export const GanttChartRoot: FC = ({
border = true,
- title = null,
+ title,
blocks,
loaderTitle = "blocks",
blockUpdateHandler,
- sidebarBlockRender,
- blockRender,
- enableLeftDrag = true,
- enableRightDrag = true,
+ SidebarBlockRender,
+ BlockRender,
+ enableBlockLeftResize = true,
+ enableBlockRightResize = true,
+ enableBlockMove = true,
enableReorder = true,
+ bottomSpacing = false,
}) => (
= ({
blocks={blocks}
loaderTitle={loaderTitle}
blockUpdateHandler={blockUpdateHandler}
- sidebarBlockRender={sidebarBlockRender}
- blockRender={blockRender}
- enableLeftDrag={enableLeftDrag}
- enableRightDrag={enableRightDrag}
+ SidebarBlockRender={SidebarBlockRender}
+ BlockRender={BlockRender}
+ enableBlockLeftResize={enableBlockLeftResize}
+ enableBlockRightResize={enableBlockRightResize}
+ enableBlockMove={enableBlockMove}
enableReorder={enableReorder}
+ bottomSpacing={bottomSpacing}
/>
);
diff --git a/web/components/gantt-chart/sidebar.tsx b/web/components/gantt-chart/sidebar.tsx
new file mode 100644
index 000000000..92e7a603d
--- /dev/null
+++ b/web/components/gantt-chart/sidebar.tsx
@@ -0,0 +1,156 @@
+// react-beautiful-dnd
+import { DragDropContext, Draggable, DropResult } from "react-beautiful-dnd";
+import StrictModeDroppable from "components/dnd/StrictModeDroppable";
+// hooks
+import { useChart } from "./hooks";
+// ui
+import { Loader } from "components/ui";
+// icons
+import { EllipsisVerticalIcon } from "@heroicons/react/24/outline";
+// types
+import { IBlockUpdateData, IGanttBlock } from "./types";
+
+type Props = {
+ title: string;
+ blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
+ blocks: IGanttBlock[] | null;
+ SidebarBlockRender: React.FC;
+ enableReorder: boolean;
+};
+
+export const GanttSidebar: React.FC = ({
+ title,
+ blockUpdateHandler,
+ blocks,
+ SidebarBlockRender,
+ enableReorder,
+}) => {
+ const { activeBlock, dispatch } = useChart();
+
+ // update the active block on hover
+ const updateActiveBlock = (block: IGanttBlock | null) => {
+ dispatch({
+ type: "PARTIAL_UPDATE",
+ payload: {
+ activeBlock: block,
+ },
+ });
+ };
+
+ const handleOrderChange = (result: DropResult) => {
+ if (!blocks) return;
+
+ const { source, destination } = result;
+
+ // return if dropped outside the list
+ if (!destination) return;
+
+ // return if dropped on the same index
+ if (source.index === destination.index) return;
+
+ let updatedSortOrder = blocks[source.index].sort_order;
+
+ // update the sort order to the lowest if dropped at the top
+ if (destination.index === 0) updatedSortOrder = blocks[0].sort_order - 1000;
+ // update the sort order to the highest if dropped at the bottom
+ else if (destination.index === blocks.length - 1)
+ updatedSortOrder = blocks[blocks.length - 1].sort_order + 1000;
+ // update the sort order to the average of the two adjacent blocks if dropped in between
+ else {
+ const destinationSortingOrder = blocks[destination.index].sort_order;
+ const relativeDestinationSortingOrder =
+ source.index < destination.index
+ ? blocks[destination.index + 1].sort_order
+ : blocks[destination.index - 1].sort_order;
+
+ updatedSortOrder = (destinationSortingOrder + relativeDestinationSortingOrder) / 2;
+ }
+
+ // extract the element from the source index and insert it at the destination index without updating the entire array
+ const removedElement = blocks.splice(source.index, 1)[0];
+ blocks.splice(destination.index, 0, removedElement);
+
+ // call the block update handler with the updated sort order, new and old index
+ blockUpdateHandler(removedElement.data, {
+ sort_order: {
+ destinationIndex: destination.index,
+ newSortOrder: updatedSortOrder,
+ sourceIndex: source.index,
+ },
+ });
+ };
+
+ return (
+
+
+ {(droppableProvided) => (
+
+ <>
+ {blocks ? (
+ blocks.length > 0 ? (
+ blocks.map((block, index) => (
+
+ {(provided, snapshot) => (
+ updateActiveBlock(block)}
+ onMouseLeave={() => updateActiveBlock(null)}
+ ref={provided.innerRef}
+ {...provided.draggableProps}
+ >
+
+
+ )}
+
+ ))
+ ) : (
+
+ No {title} found
+
+ )
+ ) : (
+
+
+
+
+
+
+ )}
+ {droppableProvided.placeholder}
+ >
+
+ )}
+
+
+ );
+};
diff --git a/apps/app/components/gantt-chart/types/index.ts b/web/components/gantt-chart/types/index.ts
similarity index 67%
rename from apps/app/components/gantt-chart/types/index.ts
rename to web/components/gantt-chart/types/index.ts
index 645fd9c87..9cab40f5c 100644
--- a/apps/app/components/gantt-chart/types/index.ts
+++ b/web/components/gantt-chart/types/index.ts
@@ -27,19 +27,33 @@ export interface IBlockUpdateData {
target_date?: string;
}
+export type TGanttViews = "hours" | "day" | "week" | "bi_week" | "month" | "quarter" | "year";
+
export interface ChartContextData {
allViews: allViewsType[];
- currentView: "hours" | "day" | "week" | "bi_week" | "month" | "quarter" | "year";
+ currentView: TGanttViews;
currentViewData: ChartDataType | undefined;
renderView: any;
+ activeBlock: IGanttBlock | null;
}
-export type ChartContextActionPayload = {
- type: "CURRENT_VIEW" | "CURRENT_VIEW_DATA" | "PARTIAL_UPDATE" | "RENDER_VIEW";
- payload: any;
-};
+export type ChartContextActionPayload =
+ | {
+ type: "CURRENT_VIEW";
+ payload: TGanttViews;
+ }
+ | {
+ type: "CURRENT_VIEW_DATA" | "RENDER_VIEW";
+ payload: ChartDataType | undefined;
+ }
+ | {
+ type: "PARTIAL_UPDATE";
+ payload: Partial;
+ };
export interface ChartContextReducer extends ChartContextData {
+ scrollLeft: number;
+ updateScrollLeft: (scrollLeft: number) => void;
dispatch: (action: ChartContextActionPayload) => void;
}
diff --git a/apps/app/components/gantt-chart/views/bi-week-view.ts b/web/components/gantt-chart/views/bi-week-view.ts
similarity index 100%
rename from apps/app/components/gantt-chart/views/bi-week-view.ts
rename to web/components/gantt-chart/views/bi-week-view.ts
diff --git a/apps/app/components/gantt-chart/views/day-view.ts b/web/components/gantt-chart/views/day-view.ts
similarity index 93%
rename from apps/app/components/gantt-chart/views/day-view.ts
rename to web/components/gantt-chart/views/day-view.ts
index 67f369361..246ecd8b8 100644
--- a/apps/app/components/gantt-chart/views/day-view.ts
+++ b/web/components/gantt-chart/views/day-view.ts
@@ -72,7 +72,12 @@ export const getAllDaysInMonth = (month: number, year: number) => {
dayData: weeks[date.getDay()],
weekNumber: getWeekNumberByDate(date),
title: `${weeks[date.getDay()].shortTitle} ${_day + 1}`,
- today: currentDate.getFullYear() === year && currentDate.getMonth() === month && currentDate.getDate() === (_day + 1) ? true : false,
+ today:
+ currentDate.getFullYear() === year &&
+ currentDate.getMonth() === month &&
+ currentDate.getDate() === _day + 1
+ ? true
+ : false,
});
});
@@ -180,7 +185,10 @@ export const generateMonthDataByYear = (
renderPayload.push(generateMonthDataByMonth(currentMonth, currentYear));
}
- const scrollWidth = ((renderPayload.map((monthData: any) => monthData.children.length)).reduce((partialSum: number, a: number) => partialSum + a, 0)) * monthPayload.data.width;
+ const scrollWidth =
+ renderPayload
+ .map((monthData: any) => monthData.children.length)
+ .reduce((partialSum: number, a: number) => partialSum + a, 0) * monthPayload.data.width;
return { state: renderState, payload: renderPayload, scrollWidth: scrollWidth };
-};
\ No newline at end of file
+};
diff --git a/apps/app/components/gantt-chart/views/helpers.ts b/web/components/gantt-chart/views/helpers.ts
similarity index 100%
rename from apps/app/components/gantt-chart/views/helpers.ts
rename to web/components/gantt-chart/views/helpers.ts
diff --git a/apps/app/components/gantt-chart/views/hours-view.ts b/web/components/gantt-chart/views/hours-view.ts
similarity index 93%
rename from apps/app/components/gantt-chart/views/hours-view.ts
rename to web/components/gantt-chart/views/hours-view.ts
index 67f369361..246ecd8b8 100644
--- a/apps/app/components/gantt-chart/views/hours-view.ts
+++ b/web/components/gantt-chart/views/hours-view.ts
@@ -72,7 +72,12 @@ export const getAllDaysInMonth = (month: number, year: number) => {
dayData: weeks[date.getDay()],
weekNumber: getWeekNumberByDate(date),
title: `${weeks[date.getDay()].shortTitle} ${_day + 1}`,
- today: currentDate.getFullYear() === year && currentDate.getMonth() === month && currentDate.getDate() === (_day + 1) ? true : false,
+ today:
+ currentDate.getFullYear() === year &&
+ currentDate.getMonth() === month &&
+ currentDate.getDate() === _day + 1
+ ? true
+ : false,
});
});
@@ -180,7 +185,10 @@ export const generateMonthDataByYear = (
renderPayload.push(generateMonthDataByMonth(currentMonth, currentYear));
}
- const scrollWidth = ((renderPayload.map((monthData: any) => monthData.children.length)).reduce((partialSum: number, a: number) => partialSum + a, 0)) * monthPayload.data.width;
+ const scrollWidth =
+ renderPayload
+ .map((monthData: any) => monthData.children.length)
+ .reduce((partialSum: number, a: number) => partialSum + a, 0) * monthPayload.data.width;
return { state: renderState, payload: renderPayload, scrollWidth: scrollWidth };
-};
\ No newline at end of file
+};
diff --git a/apps/app/components/gantt-chart/views/index.ts b/web/components/gantt-chart/views/index.ts
similarity index 100%
rename from apps/app/components/gantt-chart/views/index.ts
rename to web/components/gantt-chart/views/index.ts
diff --git a/apps/app/components/gantt-chart/views/month-view.ts b/web/components/gantt-chart/views/month-view.ts
similarity index 100%
rename from apps/app/components/gantt-chart/views/month-view.ts
rename to web/components/gantt-chart/views/month-view.ts
diff --git a/apps/app/components/gantt-chart/views/quater-view.ts b/web/components/gantt-chart/views/quater-view.ts
similarity index 100%
rename from apps/app/components/gantt-chart/views/quater-view.ts
rename to web/components/gantt-chart/views/quater-view.ts
diff --git a/apps/app/components/gantt-chart/views/week-view.ts b/web/components/gantt-chart/views/week-view.ts
similarity index 100%
rename from apps/app/components/gantt-chart/views/week-view.ts
rename to web/components/gantt-chart/views/week-view.ts
diff --git a/apps/app/components/gantt-chart/views/year-view.ts b/web/components/gantt-chart/views/year-view.ts
similarity index 100%
rename from apps/app/components/gantt-chart/views/year-view.ts
rename to web/components/gantt-chart/views/year-view.ts
diff --git a/apps/app/components/icons/alarm-clock-icon.tsx b/web/components/icons/alarm-clock-icon.tsx
similarity index 100%
rename from apps/app/components/icons/alarm-clock-icon.tsx
rename to web/components/icons/alarm-clock-icon.tsx
diff --git a/apps/app/components/icons/archive-icon.tsx b/web/components/icons/archive-icon.tsx
similarity index 100%
rename from apps/app/components/icons/archive-icon.tsx
rename to web/components/icons/archive-icon.tsx
diff --git a/apps/app/components/icons/arrow-right.tsx b/web/components/icons/arrow-right.tsx
similarity index 100%
rename from apps/app/components/icons/arrow-right.tsx
rename to web/components/icons/arrow-right.tsx
diff --git a/apps/app/components/icons/assignment-clipboard-icon.tsx b/web/components/icons/assignment-clipboard-icon.tsx
similarity index 100%
rename from apps/app/components/icons/assignment-clipboard-icon.tsx
rename to web/components/icons/assignment-clipboard-icon.tsx
diff --git a/apps/app/components/icons/attachment-icon.tsx b/web/components/icons/attachment-icon.tsx
similarity index 100%
rename from apps/app/components/icons/attachment-icon.tsx
rename to web/components/icons/attachment-icon.tsx
diff --git a/apps/app/components/icons/audio-file-icon.tsx b/web/components/icons/audio-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/audio-file-icon.tsx
rename to web/components/icons/audio-file-icon.tsx
index 6aff5d7a4..24ea55a23 100644
--- a/apps/app/components/icons/audio-file-icon.tsx
+++ b/web/components/icons/audio-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import AudioFileIcon from "public/attachment/audio-icon.png";
-export const AudioIcon: React.FC = ({ width, height }) => (
+export const AudioIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/backlog-state-icon.tsx b/web/components/icons/backlog-state-icon.tsx
similarity index 100%
rename from apps/app/components/icons/backlog-state-icon.tsx
rename to web/components/icons/backlog-state-icon.tsx
diff --git a/apps/app/components/icons/bell-icon.tsx b/web/components/icons/bell-icon.tsx
similarity index 100%
rename from apps/app/components/icons/bell-icon.tsx
rename to web/components/icons/bell-icon.tsx
diff --git a/web/components/icons/blocked-icon.tsx b/web/components/icons/blocked-icon.tsx
new file mode 100644
index 000000000..b712f7698
--- /dev/null
+++ b/web/components/icons/blocked-icon.tsx
@@ -0,0 +1,25 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const BlockedIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+
+);
diff --git a/web/components/icons/blocker-icon.tsx b/web/components/icons/blocker-icon.tsx
new file mode 100644
index 000000000..b92fadaea
--- /dev/null
+++ b/web/components/icons/blocker-icon.tsx
@@ -0,0 +1,25 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const BlockerIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+
+);
diff --git a/web/components/icons/bolt-icon.tsx b/web/components/icons/bolt-icon.tsx
new file mode 100644
index 000000000..477d4e04e
--- /dev/null
+++ b/web/components/icons/bolt-icon.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const BoltIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/calendar-after-icon.tsx b/web/components/icons/calendar-after-icon.tsx
similarity index 100%
rename from apps/app/components/icons/calendar-after-icon.tsx
rename to web/components/icons/calendar-after-icon.tsx
diff --git a/apps/app/components/icons/calendar-before-icon.tsx b/web/components/icons/calendar-before-icon.tsx
similarity index 100%
rename from apps/app/components/icons/calendar-before-icon.tsx
rename to web/components/icons/calendar-before-icon.tsx
diff --git a/apps/app/components/icons/calendar-month-icon.tsx b/web/components/icons/calendar-month-icon.tsx
similarity index 100%
rename from apps/app/components/icons/calendar-month-icon.tsx
rename to web/components/icons/calendar-month-icon.tsx
diff --git a/web/components/icons/cancel-icon.tsx b/web/components/icons/cancel-icon.tsx
new file mode 100644
index 000000000..a57425de1
--- /dev/null
+++ b/web/components/icons/cancel-icon.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const CancelIcon: React.FC = ({ width, height, className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/cancelled-state-icon.tsx b/web/components/icons/cancelled-state-icon.tsx
similarity index 100%
rename from apps/app/components/icons/cancelled-state-icon.tsx
rename to web/components/icons/cancelled-state-icon.tsx
diff --git a/apps/app/components/icons/check.tsx b/web/components/icons/check.tsx
similarity index 100%
rename from apps/app/components/icons/check.tsx
rename to web/components/icons/check.tsx
diff --git a/web/components/icons/clipboard-icon.tsx b/web/components/icons/clipboard-icon.tsx
new file mode 100644
index 000000000..a3feaf7af
--- /dev/null
+++ b/web/components/icons/clipboard-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const ClipboardIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/clock-icon.tsx b/web/components/icons/clock-icon.tsx
similarity index 100%
rename from apps/app/components/icons/clock-icon.tsx
rename to web/components/icons/clock-icon.tsx
diff --git a/apps/app/components/icons/cloud-upload.tsx b/web/components/icons/cloud-upload.tsx
similarity index 100%
rename from apps/app/components/icons/cloud-upload.tsx
rename to web/components/icons/cloud-upload.tsx
diff --git a/apps/app/components/icons/cmd-icon.tsx b/web/components/icons/cmd-icon.tsx
similarity index 100%
rename from apps/app/components/icons/cmd-icon.tsx
rename to web/components/icons/cmd-icon.tsx
diff --git a/apps/app/components/icons/cog.tsx b/web/components/icons/cog.tsx
similarity index 100%
rename from apps/app/components/icons/cog.tsx
rename to web/components/icons/cog.tsx
diff --git a/apps/app/components/icons/color-pallette-icon.tsx b/web/components/icons/color-pallette-icon.tsx
similarity index 100%
rename from apps/app/components/icons/color-pallette-icon.tsx
rename to web/components/icons/color-pallette-icon.tsx
diff --git a/apps/app/components/icons/color-picker-icon.tsx b/web/components/icons/color-picker-icon.tsx
similarity index 100%
rename from apps/app/components/icons/color-picker-icon.tsx
rename to web/components/icons/color-picker-icon.tsx
diff --git a/apps/app/components/icons/command-icon.tsx b/web/components/icons/command-icon.tsx
similarity index 100%
rename from apps/app/components/icons/command-icon.tsx
rename to web/components/icons/command-icon.tsx
diff --git a/web/components/icons/comment-icon.tsx b/web/components/icons/comment-icon.tsx
new file mode 100644
index 000000000..8619abd34
--- /dev/null
+++ b/web/components/icons/comment-icon.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const CommentIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/web/components/icons/completed-cycle-icon.tsx b/web/components/icons/completed-cycle-icon.tsx
new file mode 100644
index 000000000..77d30b24b
--- /dev/null
+++ b/web/components/icons/completed-cycle-icon.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const CompletedCycleIcon: React.FC = ({
+ width = "24",
+ height = "24",
+ className,
+ color = "black",
+}) => (
+
+
+
+);
diff --git a/apps/app/components/icons/completed-state-icon.tsx b/web/components/icons/completed-state-icon.tsx
similarity index 100%
rename from apps/app/components/icons/completed-state-icon.tsx
rename to web/components/icons/completed-state-icon.tsx
diff --git a/apps/app/components/icons/contrast-icon.tsx b/web/components/icons/contrast-icon.tsx
similarity index 100%
rename from apps/app/components/icons/contrast-icon.tsx
rename to web/components/icons/contrast-icon.tsx
diff --git a/apps/app/components/icons/css-file-icon.tsx b/web/components/icons/css-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/css-file-icon.tsx
rename to web/components/icons/css-file-icon.tsx
index 54b563d37..a753ead73 100644
--- a/apps/app/components/icons/css-file-icon.tsx
+++ b/web/components/icons/css-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import CssFileIcon from "public/attachment/css-icon.png";
-export const CssIcon: React.FC = ({ width, height }) => (
+export const CssIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/csv-file-icon.tsx b/web/components/icons/csv-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/csv-file-icon.tsx
rename to web/components/icons/csv-file-icon.tsx
index 63f01205e..d25aca262 100644
--- a/apps/app/components/icons/csv-file-icon.tsx
+++ b/web/components/icons/csv-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import CSVFileIcon from "public/attachment/csv-icon.png";
-export const CsvIcon: React.FC = ({ width , height }) => (
+export const CsvIcon: React.FC = ({ width, height }) => (
);
diff --git a/web/components/icons/current-cycle-icon.tsx b/web/components/icons/current-cycle-icon.tsx
new file mode 100644
index 000000000..57b376780
--- /dev/null
+++ b/web/components/icons/current-cycle-icon.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const CurrentCycleIcon: React.FC = ({
+ width = "24",
+ height = "24",
+ className,
+ color = "black",
+}) => (
+
+
+
+);
diff --git a/apps/app/components/icons/cycle-icon.tsx b/web/components/icons/cycle-icon.tsx
similarity index 100%
rename from apps/app/components/icons/cycle-icon.tsx
rename to web/components/icons/cycle-icon.tsx
diff --git a/apps/app/components/icons/default-file-icon.tsx b/web/components/icons/default-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/default-file-icon.tsx
rename to web/components/icons/default-file-icon.tsx
index 5323d8e07..3bc1948e3 100644
--- a/apps/app/components/icons/default-file-icon.tsx
+++ b/web/components/icons/default-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import DefaultFileIcon from "public/attachment/default-icon.png";
-export const DefaultIcon: React.FC = ({ width, height }) => (
+export const DefaultIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/discord-icon.tsx b/web/components/icons/discord-icon.tsx
similarity index 100%
rename from apps/app/components/icons/discord-icon.tsx
rename to web/components/icons/discord-icon.tsx
diff --git a/apps/app/components/icons/doc-file-icon.tsx b/web/components/icons/doc-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/doc-file-icon.tsx
rename to web/components/icons/doc-file-icon.tsx
index 173d40df1..a4367ef7c 100644
--- a/apps/app/components/icons/doc-file-icon.tsx
+++ b/web/components/icons/doc-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import DocFileIcon from "public/attachment/doc-icon.png";
-export const DocIcon: React.FC = ({ width , height }) => (
+export const DocIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/document-icon.tsx b/web/components/icons/document-icon.tsx
similarity index 82%
rename from apps/app/components/icons/document-icon.tsx
rename to web/components/icons/document-icon.tsx
index a9c599578..b84dd4c39 100644
--- a/apps/app/components/icons/document-icon.tsx
+++ b/web/components/icons/document-icon.tsx
@@ -2,17 +2,23 @@ import React from "react";
import type { Props } from "./types";
-export const DocumentIcon: React.FC = ({ width = "24", height = "24", className, color }) => (
-
+export const DocumentIcon: React.FC = ({
+ width = "24",
+ height = "24",
+ className,
+ color,
+}) => (
+
-
- );
+ d="M7.27051 14.792H12.7288C12.9094 14.792 13.0587 14.733 13.1768 14.6149C13.2948 14.4969 13.3538 14.3475 13.3538 14.167C13.3538 13.9864 13.2948 13.8371 13.1768 13.7191C13.0587 13.601 12.9094 13.542 12.7288 13.542H7.27051C7.08995 13.542 6.94065 13.601 6.82259 13.7191C6.70454 13.8371 6.64551 13.9864 6.64551 14.167C6.64551 14.3475 6.70454 14.4969 6.82259 14.6149C6.94065 14.733 7.08995 14.792 7.27051 14.792ZM7.27051 11.2503H12.7288C12.9094 11.2503 13.0587 11.1913 13.1768 11.0732C13.2948 10.9552 13.3538 10.8059 13.3538 10.6253C13.3538 10.4448 13.2948 10.2955 13.1768 10.1774C13.0587 10.0594 12.9094 10.0003 12.7288 10.0003H7.27051C7.08995 10.0003 6.94065 10.0594 6.82259 10.1774C6.70454 10.2955 6.64551 10.4448 6.64551 10.6253C6.64551 10.8059 6.70454 10.9552 6.82259 11.0732C6.94065 11.1913 7.08995 11.2503 7.27051 11.2503ZM4.58301 18.3337C4.24967 18.3337 3.95801 18.2087 3.70801 17.9587C3.45801 17.7087 3.33301 17.417 3.33301 17.0837V2.91699C3.33301 2.58366 3.45801 2.29199 3.70801 2.04199C3.95801 1.79199 4.24967 1.66699 4.58301 1.66699H11.583C11.7497 1.66699 11.9129 1.70171 12.0726 1.77116C12.2323 1.8406 12.3677 1.93088 12.4788 2.04199L16.2913 5.85449C16.4025 5.9656 16.4927 6.10102 16.5622 6.26074C16.6316 6.42046 16.6663 6.58366 16.6663 6.75033V17.0837C16.6663 17.417 16.5413 17.7087 16.2913 17.9587C16.0413 18.2087 15.7497 18.3337 15.4163 18.3337H4.58301ZM11.4788 6.16699V2.91699H4.58301V17.0837H15.4163V6.79199H12.1038C11.9233 6.79199 11.774 6.73296 11.6559 6.61491C11.5379 6.49685 11.4788 6.34755 11.4788 6.16699ZM4.58301 2.91699V6.79199V2.91699V17.0837V2.91699Z"
+ />
+
+);
diff --git a/web/components/icons/edit-icon.tsx b/web/components/icons/edit-icon.tsx
new file mode 100644
index 000000000..6b1ea2785
--- /dev/null
+++ b/web/components/icons/edit-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const EditIcon: React.FC = ({ width, height, className }) => (
+
+
+
+);
diff --git a/web/components/icons/ellipsis-horizontal-icon.tsx b/web/components/icons/ellipsis-horizontal-icon.tsx
new file mode 100644
index 000000000..26979f9a5
--- /dev/null
+++ b/web/components/icons/ellipsis-horizontal-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const EllipsisHorizontalIcon: React.FC = ({ width, height, className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/exclamation-icon.tsx b/web/components/icons/exclamation-icon.tsx
similarity index 100%
rename from apps/app/components/icons/exclamation-icon.tsx
rename to web/components/icons/exclamation-icon.tsx
diff --git a/apps/app/components/icons/external-link-icon.tsx b/web/components/icons/external-link-icon.tsx
similarity index 100%
rename from apps/app/components/icons/external-link-icon.tsx
rename to web/components/icons/external-link-icon.tsx
diff --git a/apps/app/components/icons/figma-file-icon.tsx b/web/components/icons/figma-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/figma-file-icon.tsx
rename to web/components/icons/figma-file-icon.tsx
index 7ff9f6ac0..fc7b74f73 100644
--- a/apps/app/components/icons/figma-file-icon.tsx
+++ b/web/components/icons/figma-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import FigmaFileIcon from "public/attachment/figma-icon.png";
-export const FigmaIcon: React.FC = ({ width , height }) => (
+export const FigmaIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/github-icon.tsx b/web/components/icons/github-icon.tsx
similarity index 100%
rename from apps/app/components/icons/github-icon.tsx
rename to web/components/icons/github-icon.tsx
diff --git a/apps/app/components/icons/grid-view-icons.tsx b/web/components/icons/grid-view-icons.tsx
similarity index 100%
rename from apps/app/components/icons/grid-view-icons.tsx
rename to web/components/icons/grid-view-icons.tsx
diff --git a/apps/app/components/icons/heartbeat-icon.tsx b/web/components/icons/heartbeat-icon.tsx
similarity index 100%
rename from apps/app/components/icons/heartbeat-icon.tsx
rename to web/components/icons/heartbeat-icon.tsx
diff --git a/apps/app/components/icons/html-file-icon.tsx b/web/components/icons/html-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/html-file-icon.tsx
rename to web/components/icons/html-file-icon.tsx
index 9de4080b0..4eddb323b 100644
--- a/apps/app/components/icons/html-file-icon.tsx
+++ b/web/components/icons/html-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import HtmlFileIcon from "public/attachment/html-icon.png";
-export const HtmlIcon: React.FC = ({ width, height }) => (
+export const HtmlIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/img-file-icon.tsx b/web/components/icons/img-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/img-file-icon.tsx
rename to web/components/icons/img-file-icon.tsx
index 1333957c1..0c58fa101 100644
--- a/apps/app/components/icons/img-file-icon.tsx
+++ b/web/components/icons/img-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import ImgFileIcon from "public/attachment/img-icon.png";
-export const ImgIcon: React.FC = ({ width , height }) => (
+export const ImgIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/import-layers.tsx b/web/components/icons/import-layers.tsx
similarity index 100%
rename from apps/app/components/icons/import-layers.tsx
rename to web/components/icons/import-layers.tsx
diff --git a/apps/app/components/icons/inbox-icon.tsx b/web/components/icons/inbox-icon.tsx
similarity index 100%
rename from apps/app/components/icons/inbox-icon.tsx
rename to web/components/icons/inbox-icon.tsx
diff --git a/apps/app/components/icons/index.ts b/web/components/icons/index.ts
similarity index 99%
rename from apps/app/components/icons/index.ts
rename to web/components/icons/index.ts
index 183b20c97..d3b311e40 100644
--- a/apps/app/components/icons/index.ts
+++ b/web/components/icons/index.ts
@@ -27,6 +27,7 @@ export * from "./started-state-icon";
export * from "./layer-diagonal-icon";
export * from "./lock-icon";
export * from "./menu-icon";
+export * from "./module";
export * from "./pencil-scribble-icon";
export * from "./plus-icon";
export * from "./person-running-icon";
diff --git a/apps/app/components/icons/jpg-file-icon.tsx b/web/components/icons/jpg-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/jpg-file-icon.tsx
rename to web/components/icons/jpg-file-icon.tsx
index e88f0e47f..26d3af373 100644
--- a/apps/app/components/icons/jpg-file-icon.tsx
+++ b/web/components/icons/jpg-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import JpgFileIcon from "public/attachment/jpg-icon.png";
-export const JpgIcon: React.FC = ({ width, height }) => (
+export const JpgIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/js-file-icon.tsx b/web/components/icons/js-file-icon.tsx
similarity index 97%
rename from apps/app/components/icons/js-file-icon.tsx
rename to web/components/icons/js-file-icon.tsx
index 9f879ba6b..67cfa05d4 100644
--- a/apps/app/components/icons/js-file-icon.tsx
+++ b/web/components/icons/js-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import JsFileIcon from "public/attachment/js-icon.png";
-export const JavaScriptIcon: React.FC = ({ width, height }) => (
+export const JavaScriptIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/layer-diagonal-icon.tsx b/web/components/icons/layer-diagonal-icon.tsx
similarity index 100%
rename from apps/app/components/icons/layer-diagonal-icon.tsx
rename to web/components/icons/layer-diagonal-icon.tsx
diff --git a/web/components/icons/lock-icon.tsx b/web/components/icons/lock-icon.tsx
new file mode 100644
index 000000000..2892011df
--- /dev/null
+++ b/web/components/icons/lock-icon.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const LockIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/web/components/icons/menu-icon.tsx b/web/components/icons/menu-icon.tsx
new file mode 100644
index 000000000..3b5e033d8
--- /dev/null
+++ b/web/components/icons/menu-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const MenuIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/web/components/icons/module/backlog.tsx b/web/components/icons/module/backlog.tsx
new file mode 100644
index 000000000..5685c7498
--- /dev/null
+++ b/web/components/icons/module/backlog.tsx
@@ -0,0 +1,57 @@
+import React from "react";
+
+type Props = {
+ width?: string;
+ height?: string;
+ className?: string;
+ color?: string;
+};
+
+export const ModuleBacklogIcon: React.FC = ({ width = "20", height = "20", className }) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/web/components/icons/module/cancelled.tsx b/web/components/icons/module/cancelled.tsx
new file mode 100644
index 000000000..9bfc02943
--- /dev/null
+++ b/web/components/icons/module/cancelled.tsx
@@ -0,0 +1,35 @@
+import React from "react";
+
+type Props = {
+ width?: string;
+ height?: string;
+ className?: string;
+ color?: string;
+};
+
+export const ModuleCancelledIcon: React.FC = ({
+ width = "20",
+ height = "20",
+ className,
+}) => (
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/web/components/icons/module/completed.tsx b/web/components/icons/module/completed.tsx
new file mode 100644
index 000000000..4c50ed3ad
--- /dev/null
+++ b/web/components/icons/module/completed.tsx
@@ -0,0 +1,28 @@
+import React from "react";
+
+type Props = {
+ width?: string;
+ height?: string;
+ className?: string;
+ color?: string;
+};
+
+export const ModuleCompletedIcon: React.FC = ({
+ width = "20",
+ height = "20",
+ className,
+}) => (
+
+
+
+);
diff --git a/web/components/icons/module/in-progress.tsx b/web/components/icons/module/in-progress.tsx
new file mode 100644
index 000000000..5892a94d6
--- /dev/null
+++ b/web/components/icons/module/in-progress.tsx
@@ -0,0 +1,71 @@
+import React from "react";
+
+type Props = {
+ width?: string;
+ height?: string;
+ className?: string;
+ color?: string;
+};
+
+export const ModuleInProgressIcon: React.FC = ({
+ width = "20",
+ height = "20",
+ className,
+}) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/web/components/icons/module/index.ts b/web/components/icons/module/index.ts
new file mode 100644
index 000000000..e82014b2f
--- /dev/null
+++ b/web/components/icons/module/index.ts
@@ -0,0 +1,7 @@
+export * from "./backlog";
+export * from "./cancelled";
+export * from "./completed";
+export * from "./in-progress";
+export * from "./module-status-icon";
+export * from "./paused";
+export * from "./planned";
diff --git a/web/components/icons/module/module-status-icon.tsx b/web/components/icons/module/module-status-icon.tsx
new file mode 100644
index 000000000..e80497773
--- /dev/null
+++ b/web/components/icons/module/module-status-icon.tsx
@@ -0,0 +1,37 @@
+// icons
+import {
+ ModuleBacklogIcon,
+ ModuleCancelledIcon,
+ ModuleCompletedIcon,
+ ModuleInProgressIcon,
+ ModulePausedIcon,
+ ModulePlannedIcon,
+} from "components/icons";
+// types
+import { TModuleStatus } from "types";
+
+type Props = {
+ status: TModuleStatus;
+ className?: string;
+ height?: string;
+ width?: string;
+};
+
+export const ModuleStatusIcon: React.FC = ({
+ status,
+ className,
+ height = "12px",
+ width = "12px",
+}) => {
+ if (status === "backlog")
+ return ;
+ else if (status === "cancelled")
+ return ;
+ else if (status === "completed")
+ return ;
+ else if (status === "in-progress")
+ return ;
+ else if (status === "paused")
+ return ;
+ else return ;
+};
diff --git a/web/components/icons/module/paused.tsx b/web/components/icons/module/paused.tsx
new file mode 100644
index 000000000..56ebcfd98
--- /dev/null
+++ b/web/components/icons/module/paused.tsx
@@ -0,0 +1,31 @@
+import React from "react";
+
+type Props = {
+ width?: string;
+ height?: string;
+ className?: string;
+ color?: string;
+};
+
+export const ModulePausedIcon: React.FC = ({ width = "20", height = "20", className }) => (
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/web/components/icons/module/planned.tsx b/web/components/icons/module/planned.tsx
new file mode 100644
index 000000000..97592057c
--- /dev/null
+++ b/web/components/icons/module/planned.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+
+type Props = {
+ width?: string;
+ height?: string;
+ className?: string;
+ color?: string;
+};
+
+export const ModulePlannedIcon: React.FC = ({ width = "20", height = "20", className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/pdf-file-icon.tsx b/web/components/icons/pdf-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/pdf-file-icon.tsx
rename to web/components/icons/pdf-file-icon.tsx
index 5467f0812..cb2014ee0 100644
--- a/apps/app/components/icons/pdf-file-icon.tsx
+++ b/web/components/icons/pdf-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import PDFFileIcon from "public/attachment/pdf-icon.png";
-export const PdfIcon: React.FC = ({ width , height }) => (
+export const PdfIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/pencil-scribble-icon.tsx b/web/components/icons/pencil-scribble-icon.tsx
similarity index 100%
rename from apps/app/components/icons/pencil-scribble-icon.tsx
rename to web/components/icons/pencil-scribble-icon.tsx
diff --git a/apps/app/components/icons/people-group-icon.tsx b/web/components/icons/people-group-icon.tsx
similarity index 100%
rename from apps/app/components/icons/people-group-icon.tsx
rename to web/components/icons/people-group-icon.tsx
diff --git a/apps/app/components/icons/person-running-icon.tsx b/web/components/icons/person-running-icon.tsx
similarity index 100%
rename from apps/app/components/icons/person-running-icon.tsx
rename to web/components/icons/person-running-icon.tsx
diff --git a/web/components/icons/plus-icon.tsx b/web/components/icons/plus-icon.tsx
new file mode 100644
index 000000000..25489a4fd
--- /dev/null
+++ b/web/components/icons/plus-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const PlusIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/png-file-icon.tsx b/web/components/icons/png-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/png-file-icon.tsx
rename to web/components/icons/png-file-icon.tsx
index 21b5dc116..fb64ed824 100644
--- a/apps/app/components/icons/png-file-icon.tsx
+++ b/web/components/icons/png-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import PngFileIcon from "public/attachment/png-icon.png";
-export const PngIcon: React.FC = ({ width, height }) => (
+export const PngIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/priority-icon.tsx b/web/components/icons/priority-icon.tsx
similarity index 100%
rename from apps/app/components/icons/priority-icon.tsx
rename to web/components/icons/priority-icon.tsx
diff --git a/web/components/icons/question-mark-circle-icon.tsx b/web/components/icons/question-mark-circle-icon.tsx
new file mode 100644
index 000000000..f4abd903f
--- /dev/null
+++ b/web/components/icons/question-mark-circle-icon.tsx
@@ -0,0 +1,20 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const QuestionMarkCircleIcon: React.FC = ({
+ width = "24",
+ height = "24",
+ className,
+}) => (
+
+
+
+);
diff --git a/apps/app/components/icons/setting-icon.tsx b/web/components/icons/setting-icon.tsx
similarity index 100%
rename from apps/app/components/icons/setting-icon.tsx
rename to web/components/icons/setting-icon.tsx
diff --git a/apps/app/components/icons/sheet-file-icon.tsx b/web/components/icons/sheet-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/sheet-file-icon.tsx
rename to web/components/icons/sheet-file-icon.tsx
index 9e57ce71c..dd4eee8ec 100644
--- a/apps/app/components/icons/sheet-file-icon.tsx
+++ b/web/components/icons/sheet-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import SheetFileIcon from "public/attachment/excel-icon.png";
-export const SheetIcon: React.FC = ({ width, height }) => (
+export const SheetIcon: React.FC = ({ width, height }) => (
);
diff --git a/web/components/icons/signal-cellular-icon.tsx b/web/components/icons/signal-cellular-icon.tsx
new file mode 100644
index 000000000..bb7d108fe
--- /dev/null
+++ b/web/components/icons/signal-cellular-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const SignalCellularIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/single-comment-icon.tsx b/web/components/icons/single-comment-icon.tsx
similarity index 100%
rename from apps/app/components/icons/single-comment-icon.tsx
rename to web/components/icons/single-comment-icon.tsx
diff --git a/apps/app/components/icons/sort-icon.tsx b/web/components/icons/sort-icon.tsx
similarity index 100%
rename from apps/app/components/icons/sort-icon.tsx
rename to web/components/icons/sort-icon.tsx
diff --git a/apps/app/components/icons/stacked-layers-horizontal-icon.tsx b/web/components/icons/stacked-layers-horizontal-icon.tsx
similarity index 100%
rename from apps/app/components/icons/stacked-layers-horizontal-icon.tsx
rename to web/components/icons/stacked-layers-horizontal-icon.tsx
diff --git a/apps/app/components/icons/stacked-layers-icon.tsx b/web/components/icons/stacked-layers-icon.tsx
similarity index 100%
rename from apps/app/components/icons/stacked-layers-icon.tsx
rename to web/components/icons/stacked-layers-icon.tsx
diff --git a/apps/app/components/icons/started-state-icon.tsx b/web/components/icons/started-state-icon.tsx
similarity index 100%
rename from apps/app/components/icons/started-state-icon.tsx
rename to web/components/icons/started-state-icon.tsx
diff --git a/apps/app/components/icons/state-group-icon.tsx b/web/components/icons/state-group-icon.tsx
similarity index 88%
rename from apps/app/components/icons/state-group-icon.tsx
rename to web/components/icons/state-group-icon.tsx
index b7da7136f..522e0b9dc 100644
--- a/apps/app/components/icons/state-group-icon.tsx
+++ b/web/components/icons/state-group-icon.tsx
@@ -21,6 +21,7 @@ export const getStateGroupIcon = (
width={width}
height={height}
color={color ?? STATE_GROUP_COLORS["backlog"]}
+ className="flex-shrink-0"
/>
);
case "unstarted":
@@ -29,6 +30,7 @@ export const getStateGroupIcon = (
width={width}
height={height}
color={color ?? STATE_GROUP_COLORS["unstarted"]}
+ className="flex-shrink-0"
/>
);
case "started":
@@ -37,6 +39,7 @@ export const getStateGroupIcon = (
width={width}
height={height}
color={color ?? STATE_GROUP_COLORS["started"]}
+ className="flex-shrink-0"
/>
);
case "completed":
@@ -45,6 +48,7 @@ export const getStateGroupIcon = (
width={width}
height={height}
color={color ?? STATE_GROUP_COLORS["completed"]}
+ className="flex-shrink-0"
/>
);
case "cancelled":
@@ -53,6 +57,7 @@ export const getStateGroupIcon = (
width={width}
height={height}
color={color ?? STATE_GROUP_COLORS["cancelled"]}
+ className="flex-shrink-0"
/>
);
default:
diff --git a/apps/app/components/icons/svg-file-icon.tsx b/web/components/icons/svg-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/svg-file-icon.tsx
rename to web/components/icons/svg-file-icon.tsx
index d04ae3167..043f41aeb 100644
--- a/apps/app/components/icons/svg-file-icon.tsx
+++ b/web/components/icons/svg-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import SvgFileIcon from "public/attachment/svg-icon.png";
-export const SvgIcon: React.FC = ({ width, height }) => (
+export const SvgIcon: React.FC = ({ width, height }) => (
);
diff --git a/web/components/icons/tag-icon.tsx b/web/components/icons/tag-icon.tsx
new file mode 100644
index 000000000..d907aabce
--- /dev/null
+++ b/web/components/icons/tag-icon.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const TagIcon: React.FC = ({
+ width = "24",
+ height = "24",
+ className,
+ color = "black",
+}) => (
+
+
+
+);
diff --git a/apps/app/components/icons/target-icon.tsx b/web/components/icons/target-icon.tsx
similarity index 100%
rename from apps/app/components/icons/target-icon.tsx
rename to web/components/icons/target-icon.tsx
diff --git a/apps/app/components/icons/tick-mark-icon.tsx b/web/components/icons/tick-mark-icon.tsx
similarity index 100%
rename from apps/app/components/icons/tick-mark-icon.tsx
rename to web/components/icons/tick-mark-icon.tsx
diff --git a/web/components/icons/transfer-icon.tsx b/web/components/icons/transfer-icon.tsx
new file mode 100644
index 000000000..dfb3f8c05
--- /dev/null
+++ b/web/components/icons/transfer-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const TransferIcon: React.FC = ({ width, height, className, color }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/triangle-exclamation-icon.tsx b/web/components/icons/triangle-exclamation-icon.tsx
similarity index 100%
rename from apps/app/components/icons/triangle-exclamation-icon.tsx
rename to web/components/icons/triangle-exclamation-icon.tsx
diff --git a/web/components/icons/tune-icon.tsx b/web/components/icons/tune-icon.tsx
new file mode 100644
index 000000000..baa2dcd72
--- /dev/null
+++ b/web/components/icons/tune-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const TuneIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/txt-file-icon.tsx b/web/components/icons/txt-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/txt-file-icon.tsx
rename to web/components/icons/txt-file-icon.tsx
index f0150a4cd..2fbfaee32 100644
--- a/apps/app/components/icons/txt-file-icon.tsx
+++ b/web/components/icons/txt-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import TxtFileIcon from "public/attachment/txt-icon.png";
-export const TxtIcon: React.FC = ({ width, height }) => (
+export const TxtIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/types.d.ts b/web/components/icons/types.d.ts
similarity index 100%
rename from apps/app/components/icons/types.d.ts
rename to web/components/icons/types.d.ts
diff --git a/apps/app/components/icons/unstarted-state-icon.tsx b/web/components/icons/unstarted-state-icon.tsx
similarity index 100%
rename from apps/app/components/icons/unstarted-state-icon.tsx
rename to web/components/icons/unstarted-state-icon.tsx
diff --git a/web/components/icons/upcoming-cycle-icon.tsx b/web/components/icons/upcoming-cycle-icon.tsx
new file mode 100644
index 000000000..e9bad7a42
--- /dev/null
+++ b/web/components/icons/upcoming-cycle-icon.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const UpcomingCycleIcon: React.FC = ({
+ width = "24",
+ height = "24",
+ className,
+ color = "black",
+}) => (
+
+
+
+);
diff --git a/apps/app/components/icons/user-group-icon.tsx b/web/components/icons/user-group-icon.tsx
similarity index 100%
rename from apps/app/components/icons/user-group-icon.tsx
rename to web/components/icons/user-group-icon.tsx
diff --git a/web/components/icons/user-icon-circle.tsx b/web/components/icons/user-icon-circle.tsx
new file mode 100644
index 000000000..ffc88be3b
--- /dev/null
+++ b/web/components/icons/user-icon-circle.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const UserCircleIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/web/components/icons/user-icon.tsx b/web/components/icons/user-icon.tsx
new file mode 100644
index 000000000..dedea1bae
--- /dev/null
+++ b/web/components/icons/user-icon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import type { Props } from "./types";
+
+export const UserIcon: React.FC = ({ width = "24", height = "24", className }) => (
+
+
+
+);
diff --git a/apps/app/components/icons/users.tsx b/web/components/icons/users.tsx
similarity index 100%
rename from apps/app/components/icons/users.tsx
rename to web/components/icons/users.tsx
diff --git a/apps/app/components/icons/video-file-icon.tsx b/web/components/icons/video-file-icon.tsx
similarity index 78%
rename from apps/app/components/icons/video-file-icon.tsx
rename to web/components/icons/video-file-icon.tsx
index 8deb7a80b..961aba1e6 100644
--- a/apps/app/components/icons/video-file-icon.tsx
+++ b/web/components/icons/video-file-icon.tsx
@@ -4,6 +4,6 @@ import Image from "next/image";
import type { Props } from "./types";
import VideoFileIcon from "public/attachment/video-icon.png";
-export const VideoIcon: React.FC = ({ width, height }) => (
+export const VideoIcon: React.FC = ({ width, height }) => (
);
diff --git a/apps/app/components/icons/view-list-icon.tsx b/web/components/icons/view-list-icon.tsx
similarity index 100%
rename from apps/app/components/icons/view-list-icon.tsx
rename to web/components/icons/view-list-icon.tsx
diff --git a/apps/app/components/icons/water-drop-icon.tsx b/web/components/icons/water-drop-icon.tsx
similarity index 100%
rename from apps/app/components/icons/water-drop-icon.tsx
rename to web/components/icons/water-drop-icon.tsx
diff --git a/apps/app/components/icons/x-mark-icon.tsx b/web/components/icons/x-mark-icon.tsx
similarity index 100%
rename from apps/app/components/icons/x-mark-icon.tsx
rename to web/components/icons/x-mark-icon.tsx
diff --git a/apps/app/components/inbox/accept-issue-modal.tsx b/web/components/inbox/accept-issue-modal.tsx
similarity index 100%
rename from apps/app/components/inbox/accept-issue-modal.tsx
rename to web/components/inbox/accept-issue-modal.tsx
diff --git a/apps/app/components/inbox/decline-issue-modal.tsx b/web/components/inbox/decline-issue-modal.tsx
similarity index 100%
rename from apps/app/components/inbox/decline-issue-modal.tsx
rename to web/components/inbox/decline-issue-modal.tsx
diff --git a/apps/app/components/inbox/delete-issue-modal.tsx b/web/components/inbox/delete-issue-modal.tsx
similarity index 100%
rename from apps/app/components/inbox/delete-issue-modal.tsx
rename to web/components/inbox/delete-issue-modal.tsx
diff --git a/apps/app/components/inbox/filters-dropdown.tsx b/web/components/inbox/filters-dropdown.tsx
similarity index 100%
rename from apps/app/components/inbox/filters-dropdown.tsx
rename to web/components/inbox/filters-dropdown.tsx
diff --git a/apps/app/components/inbox/filters-list.tsx b/web/components/inbox/filters-list.tsx
similarity index 100%
rename from apps/app/components/inbox/filters-list.tsx
rename to web/components/inbox/filters-list.tsx
diff --git a/apps/app/components/inbox/inbox-action-headers.tsx b/web/components/inbox/inbox-action-headers.tsx
similarity index 100%
rename from apps/app/components/inbox/inbox-action-headers.tsx
rename to web/components/inbox/inbox-action-headers.tsx
diff --git a/web/components/inbox/inbox-issue-activity.tsx b/web/components/inbox/inbox-issue-activity.tsx
new file mode 100644
index 000000000..efa237162
--- /dev/null
+++ b/web/components/inbox/inbox-issue-activity.tsx
@@ -0,0 +1,106 @@
+import { useRouter } from "next/router";
+
+import useSWR, { mutate } from "swr";
+
+// components
+import { AddComment, IssueActivitySection } from "components/issues";
+// services
+import issuesService from "services/issues.service";
+// hooks
+import useUser from "hooks/use-user";
+import useToast from "hooks/use-toast";
+// types
+import { IIssue, IIssueComment } from "types";
+// fetch-keys
+import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
+
+type Props = { issueDetails: IIssue };
+
+export const InboxIssueActivity: React.FC = ({ issueDetails }) => {
+ const router = useRouter();
+ const { workspaceSlug, projectId, inboxIssueId } = router.query;
+
+ const { setToastAlert } = useToast();
+
+ const { user } = useUser();
+
+ const { data: issueActivity, mutate: mutateIssueActivity } = useSWR(
+ workspaceSlug && projectId && inboxIssueId
+ ? PROJECT_ISSUES_ACTIVITY(inboxIssueId.toString())
+ : null,
+ workspaceSlug && projectId && inboxIssueId
+ ? () =>
+ issuesService.getIssueActivities(
+ workspaceSlug.toString(),
+ projectId.toString(),
+ inboxIssueId.toString()
+ )
+ : null
+ );
+
+ const handleCommentUpdate = async (comment: IIssueComment) => {
+ if (!workspaceSlug || !projectId || !inboxIssueId) return;
+
+ await issuesService
+ .patchIssueComment(
+ workspaceSlug as string,
+ projectId as string,
+ inboxIssueId as string,
+ comment.id,
+ comment,
+ user
+ )
+ .then(() => mutateIssueActivity());
+ };
+
+ const handleCommentDelete = async (commentId: string) => {
+ if (!workspaceSlug || !projectId || !inboxIssueId) return;
+
+ mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false);
+
+ await issuesService
+ .deleteIssueComment(
+ workspaceSlug as string,
+ projectId as string,
+ inboxIssueId as string,
+ commentId,
+ user
+ )
+ .then(() => mutateIssueActivity());
+ };
+
+ const handleAddComment = async (formData: IIssueComment) => {
+ if (!workspaceSlug || !issueDetails) return;
+
+ await issuesService
+ .createIssueComment(
+ workspaceSlug.toString(),
+ issueDetails.project,
+ issueDetails.id,
+ formData,
+ user
+ )
+ .then(() => {
+ mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id));
+ })
+ .catch(() =>
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Comment could not be posted. Please try again.",
+ })
+ );
+ };
+
+ return (
+
+
Comments/Activity
+
+
+
+ );
+};
diff --git a/apps/app/components/inbox/inbox-issue-card.tsx b/web/components/inbox/inbox-issue-card.tsx
similarity index 100%
rename from apps/app/components/inbox/inbox-issue-card.tsx
rename to web/components/inbox/inbox-issue-card.tsx
diff --git a/apps/app/components/inbox/inbox-main-content.tsx b/web/components/inbox/inbox-main-content.tsx
similarity index 95%
rename from apps/app/components/inbox/inbox-main-content.tsx
rename to web/components/inbox/inbox-main-content.tsx
index bd4f0ab01..6d4a4337c 100644
--- a/apps/app/components/inbox/inbox-main-content.tsx
+++ b/web/components/inbox/inbox-main-content.tsx
@@ -14,13 +14,8 @@ import inboxServices from "services/inbox.service";
import useInboxView from "hooks/use-inbox-view";
import useUserAuth from "hooks/use-user-auth";
// components
-import {
- AddComment,
- IssueActivitySection,
- IssueDescriptionForm,
- IssueDetailsSidebar,
- IssueReaction,
-} from "components/issues";
+import { IssueDescriptionForm, IssueDetailsSidebar, IssueReaction } from "components/issues";
+import { InboxIssueActivity } from "components/inbox";
// ui
import { Loader } from "components/ui";
// icons
@@ -42,7 +37,6 @@ import { INBOX_ISSUES, INBOX_ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "cons
const defaultValues = {
name: "",
- description: "",
description_html: "",
estimate_point: null,
assignees_list: [],
@@ -296,7 +290,6 @@ export const InboxMainContent: React.FC = () => {
workspaceSlug={workspaceSlug as string}
issue={{
name: issueDetails.name,
- description: issueDetails.description,
description_html: issueDetails.description_html,
}}
handleFormSubmit={submitChanges}
@@ -312,11 +305,7 @@ export const InboxMainContent: React.FC = () => {
issueId={issueDetails.id}
/>
-
-
Comments/Activity
-
-
-
+
diff --git a/apps/app/components/inbox/index.ts b/web/components/inbox/index.ts
similarity index 90%
rename from apps/app/components/inbox/index.ts
rename to web/components/inbox/index.ts
index 38cea0348..8301d2570 100644
--- a/apps/app/components/inbox/index.ts
+++ b/web/components/inbox/index.ts
@@ -4,6 +4,7 @@ export * from "./delete-issue-modal";
export * from "./filters-dropdown";
export * from "./filters-list";
export * from "./inbox-action-headers";
+export * from "./inbox-issue-activity";
export * from "./inbox-issue-card";
export * from "./inbox-main-content";
export * from "./issues-list-sidebar";
diff --git a/apps/app/components/inbox/issues-list-sidebar.tsx b/web/components/inbox/issues-list-sidebar.tsx
similarity index 100%
rename from apps/app/components/inbox/issues-list-sidebar.tsx
rename to web/components/inbox/issues-list-sidebar.tsx
diff --git a/apps/app/components/inbox/select-duplicate.tsx b/web/components/inbox/select-duplicate.tsx
similarity index 100%
rename from apps/app/components/inbox/select-duplicate.tsx
rename to web/components/inbox/select-duplicate.tsx
diff --git a/apps/app/components/integration/delete-import-modal.tsx b/web/components/integration/delete-import-modal.tsx
similarity index 100%
rename from apps/app/components/integration/delete-import-modal.tsx
rename to web/components/integration/delete-import-modal.tsx
diff --git a/apps/app/components/integration/github/auth.tsx b/web/components/integration/github/auth.tsx
similarity index 100%
rename from apps/app/components/integration/github/auth.tsx
rename to web/components/integration/github/auth.tsx
diff --git a/apps/app/components/integration/github/import-configure.tsx b/web/components/integration/github/import-configure.tsx
similarity index 100%
rename from apps/app/components/integration/github/import-configure.tsx
rename to web/components/integration/github/import-configure.tsx
diff --git a/apps/app/components/integration/github/import-confirm.tsx b/web/components/integration/github/import-confirm.tsx
similarity index 100%
rename from apps/app/components/integration/github/import-confirm.tsx
rename to web/components/integration/github/import-confirm.tsx
diff --git a/apps/app/components/integration/github/import-data.tsx b/web/components/integration/github/import-data.tsx
similarity index 100%
rename from apps/app/components/integration/github/import-data.tsx
rename to web/components/integration/github/import-data.tsx
diff --git a/apps/app/components/integration/github/import-users.tsx b/web/components/integration/github/import-users.tsx
similarity index 100%
rename from apps/app/components/integration/github/import-users.tsx
rename to web/components/integration/github/import-users.tsx
diff --git a/apps/app/components/integration/github/index.ts b/web/components/integration/github/index.ts
similarity index 100%
rename from apps/app/components/integration/github/index.ts
rename to web/components/integration/github/index.ts
diff --git a/apps/app/components/integration/github/repo-details.tsx b/web/components/integration/github/repo-details.tsx
similarity index 100%
rename from apps/app/components/integration/github/repo-details.tsx
rename to web/components/integration/github/repo-details.tsx
diff --git a/apps/app/components/integration/github/root.tsx b/web/components/integration/github/root.tsx
similarity index 100%
rename from apps/app/components/integration/github/root.tsx
rename to web/components/integration/github/root.tsx
diff --git a/apps/app/components/integration/github/select-repository.tsx b/web/components/integration/github/select-repository.tsx
similarity index 100%
rename from apps/app/components/integration/github/select-repository.tsx
rename to web/components/integration/github/select-repository.tsx
diff --git a/apps/app/components/integration/github/single-user-select.tsx b/web/components/integration/github/single-user-select.tsx
similarity index 100%
rename from apps/app/components/integration/github/single-user-select.tsx
rename to web/components/integration/github/single-user-select.tsx
diff --git a/apps/app/components/integration/guide.tsx b/web/components/integration/guide.tsx
similarity index 100%
rename from apps/app/components/integration/guide.tsx
rename to web/components/integration/guide.tsx
diff --git a/apps/app/components/integration/index.ts b/web/components/integration/index.ts
similarity index 100%
rename from apps/app/components/integration/index.ts
rename to web/components/integration/index.ts
diff --git a/apps/app/components/integration/jira/confirm-import.tsx b/web/components/integration/jira/confirm-import.tsx
similarity index 100%
rename from apps/app/components/integration/jira/confirm-import.tsx
rename to web/components/integration/jira/confirm-import.tsx
diff --git a/apps/app/components/integration/jira/give-details.tsx b/web/components/integration/jira/give-details.tsx
similarity index 100%
rename from apps/app/components/integration/jira/give-details.tsx
rename to web/components/integration/jira/give-details.tsx
diff --git a/apps/app/components/integration/jira/import-users.tsx b/web/components/integration/jira/import-users.tsx
similarity index 100%
rename from apps/app/components/integration/jira/import-users.tsx
rename to web/components/integration/jira/import-users.tsx
diff --git a/apps/app/components/integration/jira/index.ts b/web/components/integration/jira/index.ts
similarity index 100%
rename from apps/app/components/integration/jira/index.ts
rename to web/components/integration/jira/index.ts
diff --git a/apps/app/components/integration/jira/jira-project-detail.tsx b/web/components/integration/jira/jira-project-detail.tsx
similarity index 99%
rename from apps/app/components/integration/jira/jira-project-detail.tsx
rename to web/components/integration/jira/jira-project-detail.tsx
index 88803727c..f651ad89c 100644
--- a/apps/app/components/integration/jira/jira-project-detail.tsx
+++ b/web/components/integration/jira/jira-project-detail.tsx
@@ -20,7 +20,7 @@ import { IJiraImporterForm, IJiraMetadata } from "types";
// components
import { Spinner, ToggleSwitch } from "components/ui";
-import type { IJiraIntegrationData, TJiraIntegrationSteps } from "./";
+import type { IJiraIntegrationData, TJiraIntegrationSteps } from ".";
type Props = {
setCurrentStep: React.Dispatch
>;
diff --git a/apps/app/components/integration/jira/root.tsx b/web/components/integration/jira/root.tsx
similarity index 99%
rename from apps/app/components/integration/jira/root.tsx
rename to web/components/integration/jira/root.tsx
index b5c086431..451c23709 100644
--- a/apps/app/components/integration/jira/root.tsx
+++ b/web/components/integration/jira/root.tsx
@@ -31,7 +31,7 @@ import {
jiraFormDefaultValues,
TJiraIntegrationSteps,
IJiraIntegrationData,
-} from "./";
+} from ".";
import JiraLogo from "public/services/jira.png";
diff --git a/apps/app/components/integration/single-import.tsx b/web/components/integration/single-import.tsx
similarity index 100%
rename from apps/app/components/integration/single-import.tsx
rename to web/components/integration/single-import.tsx
diff --git a/apps/app/components/integration/single-integration-card.tsx b/web/components/integration/single-integration-card.tsx
similarity index 100%
rename from apps/app/components/integration/single-integration-card.tsx
rename to web/components/integration/single-integration-card.tsx
diff --git a/web/components/integration/slack/index.ts b/web/components/integration/slack/index.ts
new file mode 100644
index 000000000..4ea6cd1e4
--- /dev/null
+++ b/web/components/integration/slack/index.ts
@@ -0,0 +1 @@
+export * from "./select-channel";
diff --git a/apps/app/components/integration/slack/select-channel.tsx b/web/components/integration/slack/select-channel.tsx
similarity index 100%
rename from apps/app/components/integration/slack/select-channel.tsx
rename to web/components/integration/slack/select-channel.tsx
diff --git a/apps/app/components/issues/activity.tsx b/web/components/issues/activity.tsx
similarity index 75%
rename from apps/app/components/issues/activity.tsx
rename to web/components/issues/activity.tsx
index 8dd948e08..5a82907f2 100644
--- a/apps/app/components/issues/activity.tsx
+++ b/web/components/issues/activity.tsx
@@ -3,10 +3,6 @@ import React from "react";
import Link from "next/link";
import { useRouter } from "next/router";
-import useSWR from "swr";
-
-// services
-import issuesService from "services/issues.service";
// components
import { ActivityIcon, ActivityMessage } from "components/core";
import { CommentCard } from "components/issues/comment";
@@ -15,62 +11,23 @@ import { Icon, Loader } from "components/ui";
// helpers
import { timeAgo } from "helpers/date-time.helper";
// types
-import { ICurrentUserResponse, IIssueComment } from "types";
-// fetch-keys
-import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
+import { IIssueActivity, IIssueComment } from "types";
type Props = {
- issueId: string;
- user: ICurrentUserResponse | undefined;
+ activity: IIssueActivity[] | undefined;
+ handleCommentUpdate: (comment: IIssueComment) => Promise;
+ handleCommentDelete: (commentId: string) => Promise;
};
-export const IssueActivitySection: React.FC = ({ issueId, user }) => {
+export const IssueActivitySection: React.FC = ({
+ activity,
+ handleCommentUpdate,
+ handleCommentDelete,
+}) => {
const router = useRouter();
- const { workspaceSlug, projectId } = router.query;
+ const { workspaceSlug } = router.query;
- const { data: issueActivities, mutate: mutateIssueActivities } = useSWR(
- workspaceSlug && projectId ? PROJECT_ISSUES_ACTIVITY(issueId) : null,
- workspaceSlug && projectId
- ? () =>
- issuesService.getIssueActivities(workspaceSlug as string, projectId as string, issueId)
- : null
- );
-
- const handleCommentUpdate = async (comment: IIssueComment) => {
- if (!workspaceSlug || !projectId || !issueId) return;
-
- await issuesService
- .patchIssueComment(
- workspaceSlug as string,
- projectId as string,
- issueId as string,
- comment.id,
- comment,
- user
- )
- .then((res) => mutateIssueActivities());
- };
-
- const handleCommentDelete = async (commentId: string) => {
- if (!workspaceSlug || !projectId || !issueId) return;
-
- mutateIssueActivities(
- (prevData: any) => prevData?.filter((p: any) => p.id !== commentId),
- false
- );
-
- await issuesService
- .deleteIssueComment(
- workspaceSlug as string,
- projectId as string,
- issueId as string,
- commentId,
- user
- )
- .then(() => mutateIssueActivities());
- };
-
- if (!issueActivities) {
+ if (!activity)
return (
@@ -87,12 +44,11 @@ export const IssueActivitySection: React.FC
= ({ issueId, user }) => {
);
- }
return (
- {issueActivities.map((activityItem, index) => {
+ {activity.map((activityItem, index) => {
// determines what type of action is performed
const message = activityItem.field ? (
@@ -104,7 +60,7 @@ export const IssueActivitySection: React.FC = ({ issueId, user }) => {
return (
- {issueActivities.length > 1 && index !== issueActivities.length - 1 ? (
+ {activity.length > 1 && index !== activity.length - 1 ? (
= {
+ access: "INTERNAL",
+ comment_html: "",
+};
+
+type Props = {
+ disabled?: boolean;
+ onSubmit: (data: IIssueComment) => Promise;
+ showAccessSpecifier?: boolean;
+};
+
+const commentAccess = [
+ {
+ icon: "lock",
+ key: "INTERNAL",
+ label: "Private",
+ },
+ {
+ icon: "public",
+ key: "EXTERNAL",
+ label: "Public",
+ },
+];
+
+export const AddComment: React.FC = ({
+ disabled = false,
+ onSubmit,
+ showAccessSpecifier = false,
+}) => {
+ const editorRef = React.useRef(null);
+
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+
+ const {
+ control,
+ formState: { isSubmitting },
+ handleSubmit,
+ reset,
+ } = useForm({ defaultValues });
+
+ const handleAddComment = async (formData: IIssueComment) => {
+ if (!formData.comment_html || isSubmitting) return;
+
+ await onSubmit(formData).then(() => {
+ reset(defaultValues);
+ editorRef.current?.clearEditor();
+ });
+ };
+
+ return (
+
+ );
+};
diff --git a/apps/app/components/issues/comment/comment-card.tsx b/web/components/issues/comment/comment-card.tsx
similarity index 92%
rename from apps/app/components/issues/comment/comment-card.tsx
rename to web/components/issues/comment/comment-card.tsx
index 06ef891a9..089aa9db9 100644
--- a/apps/app/components/issues/comment/comment-card.tsx
+++ b/web/components/issues/comment/comment-card.tsx
@@ -9,17 +9,11 @@ import useUser from "hooks/use-user";
// ui
import { CustomMenu } from "components/ui";
import { CommentReaction } from "components/issues";
+import { TipTapEditor } from "components/tiptap";
// helpers
import { timeAgo } from "helpers/date-time.helper";
// types
import type { IIssueComment } from "types";
-import Tiptap, { ITiptapRichTextEditor } from "components/tiptap";
-
-const TiptapEditor = React.forwardRef(
- (props, ref) =>
-);
-
-TiptapEditor.displayName = "TiptapEditor";
type Props = {
workspaceSlug: string;
@@ -28,7 +22,12 @@ type Props = {
handleCommentDeletion: (comment: string) => void;
};
-export const CommentCard: React.FC = ({ comment, workspaceSlug, onSubmit, handleCommentDeletion }) => {
+export const CommentCard: React.FC = ({
+ comment,
+ workspaceSlug,
+ onSubmit,
+ handleCommentDeletion,
+}) => {
const { user } = useUser();
const editorRef = React.useRef(null);
@@ -109,7 +108,7 @@ export const CommentCard: React.FC = ({ comment, workspaceSlug, onSubmit,
onSubmit={handleSubmit(onEnter)}
>
- = ({ comment, workspaceSlug, onSubmit,
-
void;
data: IIssue | null;
user: ICurrentUserResponse | undefined;
+ onSubmit?: () => Promise;
};
-export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, user }) => {
+export const DeleteIssueModal: React.FC = ({
+ isOpen,
+ handleClose,
+ data,
+ user,
+ onSubmit,
+}) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter();
@@ -116,6 +123,8 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, u
else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(data.project, params));
}
+ if (onSubmit) onSubmit();
+
handleClose();
setToastAlert({
title: "Success",
@@ -129,6 +138,7 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, u
console.log(error);
setIsDeleteLoading(false);
});
+ if (onSubmit) await onSubmit();
};
const handleArchivedIssueDeletion = async () => {
diff --git a/apps/app/components/issues/description-form.tsx b/web/components/issues/description-form.tsx
similarity index 69%
rename from apps/app/components/issues/description-form.tsx
rename to web/components/issues/description-form.tsx
index 5561b1b99..54ea0a976 100644
--- a/apps/app/components/issues/description-form.tsx
+++ b/web/components/issues/description-form.tsx
@@ -4,24 +4,21 @@ import { FC, useCallback, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
// hooks
import useReloadConfirmations from "hooks/use-reload-confirmation";
+import { useDebouncedCallback } from "use-debounce";
// components
import { TextArea } from "components/ui";
-
+import { TipTapEditor } from "components/tiptap";
// types
import { IIssue } from "types";
-import Tiptap from "components/tiptap";
-import { useDebouncedCallback } from "use-debounce";
export interface IssueDescriptionFormValues {
name: string;
- description: any;
description_html: string;
}
export interface IssueDetailsProps {
issue: {
name: string;
- description: string;
description_html: string;
};
workspaceSlug: string;
@@ -43,7 +40,6 @@ export const IssueDescriptionForm: FC = ({
const {
handleSubmit,
watch,
- setValue,
reset,
register,
control,
@@ -51,7 +47,6 @@ export const IssueDescriptionForm: FC = ({
} = useForm({
defaultValues: {
name: "",
- description: "",
description_html: "",
},
});
@@ -62,7 +57,6 @@ export const IssueDescriptionForm: FC = ({
await handleFormSubmit({
name: formData.name ?? "",
- description: formData.description ?? "",
description_html: formData.description_html ?? "
",
});
},
@@ -80,7 +74,6 @@ export const IssueDescriptionForm: FC = ({
}
}, [isSubmitting, setShowAlert]);
-
// reset form values
useEffect(() => {
if (!issue) return;
@@ -99,27 +92,32 @@ export const IssueDescriptionForm: FC = ({
return (
setIsBlockerModalOpen(true)}
- disabled={isNotAllowed}
+ disabled={disabled}
>
Select issues
diff --git a/web/components/issues/sidebar-select/cycle.tsx b/web/components/issues/sidebar-select/cycle.tsx
new file mode 100644
index 000000000..8fbfcf707
--- /dev/null
+++ b/web/components/issues/sidebar-select/cycle.tsx
@@ -0,0 +1,118 @@
+import React from "react";
+
+import { useRouter } from "next/router";
+
+import useSWR, { mutate } from "swr";
+
+// services
+import issuesService from "services/issues.service";
+import cyclesService from "services/cycles.service";
+// ui
+import { Spinner, CustomSelect, Tooltip } from "components/ui";
+// helper
+import { truncateText } from "helpers/string.helper";
+// types
+import { ICycle, IIssue } from "types";
+// fetch-keys
+import { CYCLE_ISSUES, INCOMPLETE_CYCLES_LIST, ISSUE_DETAILS } from "constants/fetch-keys";
+
+type Props = {
+ issueDetail: IIssue | undefined;
+ handleCycleChange: (cycle: ICycle) => void;
+ disabled?: boolean;
+};
+
+export const SidebarCycleSelect: React.FC
= ({
+ issueDetail,
+ handleCycleChange,
+ disabled = false,
+}) => {
+ const router = useRouter();
+ const { workspaceSlug, projectId, issueId } = router.query;
+
+ const { data: incompleteCycles } = useSWR(
+ workspaceSlug && projectId ? INCOMPLETE_CYCLES_LIST(projectId as string) : null,
+ workspaceSlug && projectId
+ ? () =>
+ cyclesService.getCyclesWithParams(
+ workspaceSlug as string,
+ projectId as string,
+ "incomplete"
+ )
+ : null
+ );
+
+ const removeIssueFromCycle = (bridgeId: string, cycleId: string) => {
+ if (!workspaceSlug || !projectId) return;
+
+ issuesService
+ .removeIssueFromCycle(workspaceSlug as string, projectId as string, cycleId, bridgeId)
+ .then((res) => {
+ mutate(ISSUE_DETAILS(issueId as string));
+
+ mutate(CYCLE_ISSUES(cycleId));
+ })
+ .catch((e) => {
+ console.log(e);
+ });
+ };
+
+ const issueCycle = issueDetail?.issue_cycle;
+
+ return (
+
+
+
+
+ {issueCycle ? issueCycle.cycle_detail.name : "No cycle"}
+
+
+
+
+ }
+ value={issueCycle ? issueCycle.cycle_detail.id : null}
+ onChange={(value: any) => {
+ !value
+ ? removeIssueFromCycle(issueCycle?.id ?? "", issueCycle?.cycle ?? "")
+ : handleCycleChange(incompleteCycles?.find((c) => c.id === value) as ICycle);
+ }}
+ width="w-full"
+ position="right"
+ maxHeight="rg"
+ disabled={disabled}
+ >
+ {incompleteCycles ? (
+ incompleteCycles.length > 0 ? (
+ <>
+ {incompleteCycles.map((option) => (
+
+
+ {truncateText(option.name, 25)}
+
+
+ ))}
+ None
+ >
+ ) : (
+ No cycles found
+ )
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/web/components/issues/sidebar-select/estimate.tsx b/web/components/issues/sidebar-select/estimate.tsx
new file mode 100644
index 000000000..7ebdfe2b9
--- /dev/null
+++ b/web/components/issues/sidebar-select/estimate.tsx
@@ -0,0 +1,59 @@
+import React from "react";
+
+// hooks
+import useEstimateOption from "hooks/use-estimate-option";
+// ui
+import { CustomSelect } from "components/ui";
+// icons
+import { PlayIcon } from "@heroicons/react/24/outline";
+
+type Props = {
+ value: number | null;
+ onChange: (val: number | null) => void;
+ disabled?: boolean;
+};
+
+export const SidebarEstimateSelect: React.FC = ({ value, onChange, disabled = false }) => {
+ const { estimatePoints } = useEstimateOption();
+
+ return (
+
+
+ {estimatePoints?.find((e) => e.key === value)?.value ?? "No estimate"}
+
+ }
+ onChange={onChange}
+ disabled={disabled}
+ >
+
+ <>
+
+
+
+ None
+ >
+
+ {estimatePoints &&
+ estimatePoints.map((point) => (
+
+ <>
+
+
+
+ {point.value}
+ >
+
+ ))}
+
+ );
+};
diff --git a/apps/app/components/issues/sidebar-select/index.ts b/web/components/issues/sidebar-select/index.ts
similarity index 100%
rename from apps/app/components/issues/sidebar-select/index.ts
rename to web/components/issues/sidebar-select/index.ts
diff --git a/apps/app/components/issues/sidebar-select/label.tsx b/web/components/issues/sidebar-select/label.tsx
similarity index 100%
rename from apps/app/components/issues/sidebar-select/label.tsx
rename to web/components/issues/sidebar-select/label.tsx
diff --git a/web/components/issues/sidebar-select/module.tsx b/web/components/issues/sidebar-select/module.tsx
new file mode 100644
index 000000000..c9599bdf4
--- /dev/null
+++ b/web/components/issues/sidebar-select/module.tsx
@@ -0,0 +1,114 @@
+import React from "react";
+
+import { useRouter } from "next/router";
+
+import useSWR, { mutate } from "swr";
+
+// services
+import modulesService from "services/modules.service";
+// ui
+import { Spinner, CustomSelect, Tooltip } from "components/ui";
+// helper
+import { truncateText } from "helpers/string.helper";
+// types
+import { IIssue, IModule } from "types";
+// fetch-keys
+import { ISSUE_DETAILS, MODULE_ISSUES, MODULE_LIST } from "constants/fetch-keys";
+
+type Props = {
+ issueDetail: IIssue | undefined;
+ handleModuleChange: (module: IModule) => void;
+ disabled?: boolean;
+};
+
+export const SidebarModuleSelect: React.FC = ({
+ issueDetail,
+ handleModuleChange,
+ disabled = false,
+}) => {
+ const router = useRouter();
+ const { workspaceSlug, projectId, issueId } = router.query;
+
+ const { data: modules } = useSWR(
+ workspaceSlug && projectId ? MODULE_LIST(projectId as string) : null,
+ workspaceSlug && projectId
+ ? () => modulesService.getModules(workspaceSlug as string, projectId as string)
+ : null
+ );
+
+ const removeIssueFromModule = (bridgeId: string, moduleId: string) => {
+ if (!workspaceSlug || !projectId) return;
+
+ modulesService
+ .removeIssueFromModule(workspaceSlug as string, projectId as string, moduleId, bridgeId)
+ .then((res) => {
+ mutate(ISSUE_DETAILS(issueId as string));
+
+ mutate(MODULE_ISSUES(moduleId));
+ })
+ .catch((e) => {
+ console.log(e);
+ });
+ };
+
+ const issueModule = issueDetail?.issue_module;
+
+ return (
+
+ m.id === issueModule?.module)?.name ?? "No module"
+ }`}
+ >
+
+
+ {modules?.find((m) => m.id === issueModule?.module)?.name ?? "No module"}
+
+
+
+
+ }
+ value={issueModule ? issueModule.module_detail?.id : null}
+ onChange={(value: any) => {
+ !value
+ ? removeIssueFromModule(issueModule?.id ?? "", issueModule?.module ?? "")
+ : handleModuleChange(modules?.find((m) => m.id === value) as IModule);
+ }}
+ width="w-full"
+ position="right"
+ maxHeight="rg"
+ disabled={disabled}
+ >
+ {modules ? (
+ modules.length > 0 ? (
+ <>
+ {modules.map((option) => (
+
+
+ {truncateText(option.name, 25)}
+
+
+ ))}
+ None
+ >
+ ) : (
+ No modules found
+ )
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/web/components/issues/sidebar-select/parent.tsx b/web/components/issues/sidebar-select/parent.tsx
new file mode 100644
index 000000000..dd5d4f55b
--- /dev/null
+++ b/web/components/issues/sidebar-select/parent.tsx
@@ -0,0 +1,57 @@
+import React, { useState } from "react";
+
+import { useRouter } from "next/router";
+
+// components
+import { ParentIssuesListModal } from "components/issues";
+// types
+import { IIssue, ISearchIssueResponse, UserAuth } from "types";
+
+type Props = {
+ onChange: (value: string) => void;
+ issueDetails: IIssue | undefined;
+ disabled?: boolean;
+};
+
+export const SidebarParentSelect: React.FC = ({
+ onChange,
+ issueDetails,
+ disabled = false,
+}) => {
+ const [isParentModalOpen, setIsParentModalOpen] = useState(false);
+ const [selectedParentIssue, setSelectedParentIssue] = useState(null);
+
+ const router = useRouter();
+ const { projectId, issueId } = router.query;
+
+ return (
+ <>
+ setIsParentModalOpen(false)}
+ onChange={(issue) => {
+ onChange(issue.id);
+ setSelectedParentIssue(issue);
+ }}
+ issueId={issueId as string}
+ projectId={projectId as string}
+ />
+ setIsParentModalOpen(true)}
+ disabled={disabled}
+ >
+ {selectedParentIssue && issueDetails?.parent ? (
+ `${selectedParentIssue.project__identifier}-${selectedParentIssue.sequence_id}`
+ ) : !selectedParentIssue && issueDetails?.parent ? (
+ `${issueDetails.parent_detail?.project_detail.identifier}-${issueDetails.parent_detail?.sequence_id}`
+ ) : (
+ Select issue
+ )}
+
+ >
+ );
+};
diff --git a/web/components/issues/sidebar-select/priority.tsx b/web/components/issues/sidebar-select/priority.tsx
new file mode 100644
index 000000000..67ae5133d
--- /dev/null
+++ b/web/components/issues/sidebar-select/priority.tsx
@@ -0,0 +1,53 @@
+import React from "react";
+
+// ui
+import { CustomSelect } from "components/ui";
+// icons
+import { getPriorityIcon } from "components/icons/priority-icon";
+// constants
+import { PRIORITIES } from "constants/project";
+
+type Props = {
+ value: string | null;
+ onChange: (val: string) => void;
+ disabled?: boolean;
+};
+
+export const SidebarPrioritySelect: React.FC = ({ value, onChange, disabled = false }) => (
+
+
+ {getPriorityIcon(value ?? "None", "!text-sm")}
+
+ {value ?? "None"}
+
+ }
+ value={value}
+ onChange={onChange}
+ optionsClassName="w-min"
+ disabled={disabled}
+ >
+ {PRIORITIES.map((option) => (
+
+ <>
+ {getPriorityIcon(option, "text-sm")}
+ {option ?? "None"}
+ >
+
+ ))}
+
+);
diff --git a/web/components/issues/sidebar-select/state.tsx b/web/components/issues/sidebar-select/state.tsx
new file mode 100644
index 000000000..5084c61bd
--- /dev/null
+++ b/web/components/issues/sidebar-select/state.tsx
@@ -0,0 +1,87 @@
+import React from "react";
+
+import { useRouter } from "next/router";
+
+import useSWR from "swr";
+
+// services
+import stateService from "services/state.service";
+// ui
+import { Spinner, CustomSelect } from "components/ui";
+// icons
+import { getStateGroupIcon } from "components/icons";
+// helpers
+import { getStatesList } from "helpers/state.helper";
+import { addSpaceIfCamelCase } from "helpers/string.helper";
+// constants
+import { STATES_LIST } from "constants/fetch-keys";
+
+type Props = {
+ value: string;
+ onChange: (val: string) => void;
+ disabled?: boolean;
+};
+
+export const SidebarStateSelect: React.FC = ({ value, onChange, disabled = false }) => {
+ const router = useRouter();
+ const { workspaceSlug, projectId, inboxIssueId } = router.query;
+
+ const { data: stateGroups } = useSWR(
+ workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
+ workspaceSlug && projectId
+ ? () => stateService.getStates(workspaceSlug as string, projectId as string)
+ : null
+ );
+ const states = getStatesList(stateGroups);
+
+ const selectedState = states?.find((s) => s.id === value);
+
+ return (
+
+ {selectedState ? (
+
+ {getStateGroupIcon(
+ selectedState?.group ?? "backlog",
+ "14",
+ "14",
+ selectedState?.color ?? ""
+ )}
+ {addSpaceIfCamelCase(selectedState?.name ?? "")}
+
+ ) : inboxIssueId ? (
+
+ {getStateGroupIcon("backlog", "14", "14", "#ff7700")}
+ Triage
+
+ ) : (
+ "None"
+ )}
+
+ }
+ value={value}
+ onChange={onChange}
+ optionsClassName="w-min"
+ position="left"
+ disabled={disabled}
+ >
+ {states ? (
+ states.length > 0 ? (
+ states.map((state) => (
+
+ <>
+ {getStateGroupIcon(state.group, "16", "16", state.color)}
+ {state.name}
+ >
+
+ ))
+ ) : (
+ No states found
+ )
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/apps/app/components/issues/sidebar.tsx b/web/components/issues/sidebar.tsx
similarity index 69%
rename from apps/app/components/issues/sidebar.tsx
rename to web/components/issues/sidebar.tsx
index 6ae7eccb8..4bdd30137 100644
--- a/apps/app/components/issues/sidebar.tsx
+++ b/web/components/issues/sidebar.tsx
@@ -10,6 +10,7 @@ import { Controller, UseFormWatch } from "react-hook-form";
import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
import useUserIssueNotificationSubscription from "hooks/use-issue-notification-subscription";
+import useEstimateOption from "hooks/use-estimate-option";
// services
import issuesService from "services/issues.service";
import modulesService from "services/modules.service";
@@ -33,13 +34,25 @@ import {
// ui
import { CustomDatePicker, Icon } from "components/ui";
// icons
-import { LinkIcon, CalendarDaysIcon, TrashIcon, PlusIcon } from "@heroicons/react/24/outline";
+import {
+ LinkIcon,
+ CalendarDaysIcon,
+ TrashIcon,
+ PlusIcon,
+ Squares2X2Icon,
+ ChartBarIcon,
+ UserGroupIcon,
+ PlayIcon,
+ UserIcon,
+ RectangleGroupIcon,
+} from "@heroicons/react/24/outline";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
// types
import type { ICycle, IIssue, IIssueLink, linkDetails, IModule } from "types";
// fetch-keys
import { ISSUE_DETAILS } from "constants/fetch-keys";
+import { ContrastIcon } from "components/icons";
type Props = {
control: any;
@@ -84,6 +97,8 @@ export const IssueDetailsSidebar: React.FC = ({
const { user } = useUserAuth();
+ const { isEstimateActive } = useEstimateOption();
+
const { loading, handleSubscribe, handleUnsubscribe, subscribed } =
useUserIssueNotificationSubscription(workspaceSlug, projectId, issueId);
@@ -332,89 +347,126 @@ export const IssueDetailsSidebar: React.FC = ({
{showFirstSection && (
{(fieldsToShow.includes("all") || fieldsToShow.includes("state")) && (
-
(
- submitChanges({ state: val })}
- userAuth={memberRole}
- disabled={uneditable}
+
+
+
+ (
+ submitChanges({ state: val })}
+ disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
+ />
+ )}
/>
- )}
- />
+
+
)}
{(fieldsToShow.includes("all") || fieldsToShow.includes("assignee")) && (
- (
- submitChanges({ assignees_list: val })}
- userAuth={memberRole}
- disabled={uneditable}
+
+
+
+ (
+ submitChanges({ assignees_list: val })}
+ disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
+ />
+ )}
/>
- )}
- />
+
+
)}
{(fieldsToShow.includes("all") || fieldsToShow.includes("priority")) && (
- (
- submitChanges({ priority: val })}
- userAuth={memberRole}
- disabled={uneditable}
+
+
+
+ (
+ submitChanges({ priority: val })}
+ disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
+ />
+ )}
/>
- )}
- />
- )}
- {(fieldsToShow.includes("all") || fieldsToShow.includes("estimate")) && (
- (
- submitChanges({ estimate_point: val })}
- userAuth={memberRole}
- disabled={uneditable}
- />
- )}
- />
+
+
)}
+ {(fieldsToShow.includes("all") || fieldsToShow.includes("estimate")) &&
+ isEstimateActive && (
+
+
+
+ (
+
+ submitChanges({ estimate_point: val })
+ }
+ disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
+ />
+ )}
+ />
+
+
+ )}
)}
{showSecondSection && (
{(fieldsToShow.includes("all") || fieldsToShow.includes("parent")) && (
-
(
- {
- submitChanges({ parent: val });
- onChange(val);
- }}
- issueDetails={issueDetail}
- userAuth={memberRole}
- disabled={uneditable}
+
+
+
+ (
+ {
+ submitChanges({ parent: val });
+ onChange(val);
+ }}
+ issueDetails={issueDetail}
+ disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
+ />
+ )}
/>
- )}
- />
+
+
)}
{(fieldsToShow.includes("all") || fieldsToShow.includes("blocker")) && (
)}
{(fieldsToShow.includes("all") || fieldsToShow.includes("blocked")) && (
@@ -422,8 +474,7 @@ export const IssueDetailsSidebar: React.FC = ({
issueId={issueId as string}
submitChanges={submitChanges}
watch={watchIssue}
- userAuth={memberRole}
- disabled={uneditable}
+ disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
/>
)}
{(fieldsToShow.includes("all") || fieldsToShow.includes("startDate")) && (
@@ -445,8 +496,7 @@ export const IssueDetailsSidebar: React.FC = ({
start_date: val,
})
}
- className="bg-custom-background-100"
- wrapperClassName="w-full"
+ className="bg-custom-background-80 border-none"
maxDate={maxDate ?? undefined}
disabled={isNotAllowed || uneditable}
/>
@@ -474,8 +524,7 @@ export const IssueDetailsSidebar: React.FC = ({
target_date: val,
})
}
- className="bg-custom-background-100"
- wrapperClassName="w-full"
+ className="bg-custom-background-80 border-none"
minDate={minDate ?? undefined}
disabled={isNotAllowed || uneditable}
/>
@@ -489,20 +538,34 @@ export const IssueDetailsSidebar: React.FC = ({
{showThirdSection && (
{(fieldsToShow.includes("all") || fieldsToShow.includes("cycle")) && (
-
+
)}
{(fieldsToShow.includes("all") || fieldsToShow.includes("module")) && (
-
+
)}
)}
diff --git a/apps/app/components/issues/sub-issues-list.tsx b/web/components/issues/sub-issues-list.tsx
similarity index 100%
rename from apps/app/components/issues/sub-issues-list.tsx
rename to web/components/issues/sub-issues-list.tsx
diff --git a/apps/app/components/issues/view-select/assignee.tsx b/web/components/issues/view-select/assignee.tsx
similarity index 100%
rename from apps/app/components/issues/view-select/assignee.tsx
rename to web/components/issues/view-select/assignee.tsx
diff --git a/apps/app/components/issues/view-select/due-date.tsx b/web/components/issues/view-select/due-date.tsx
similarity index 100%
rename from apps/app/components/issues/view-select/due-date.tsx
rename to web/components/issues/view-select/due-date.tsx
diff --git a/apps/app/components/issues/view-select/estimate.tsx b/web/components/issues/view-select/estimate.tsx
similarity index 100%
rename from apps/app/components/issues/view-select/estimate.tsx
rename to web/components/issues/view-select/estimate.tsx
diff --git a/apps/app/components/issues/view-select/index.ts b/web/components/issues/view-select/index.ts
similarity index 100%
rename from apps/app/components/issues/view-select/index.ts
rename to web/components/issues/view-select/index.ts
diff --git a/apps/app/components/issues/view-select/label.tsx b/web/components/issues/view-select/label.tsx
similarity index 100%
rename from apps/app/components/issues/view-select/label.tsx
rename to web/components/issues/view-select/label.tsx
diff --git a/apps/app/components/issues/view-select/priority.tsx b/web/components/issues/view-select/priority.tsx
similarity index 100%
rename from apps/app/components/issues/view-select/priority.tsx
rename to web/components/issues/view-select/priority.tsx
diff --git a/apps/app/components/issues/view-select/start-date.tsx b/web/components/issues/view-select/start-date.tsx
similarity index 100%
rename from apps/app/components/issues/view-select/start-date.tsx
rename to web/components/issues/view-select/start-date.tsx
diff --git a/apps/app/components/issues/view-select/state.tsx b/web/components/issues/view-select/state.tsx
similarity index 100%
rename from apps/app/components/issues/view-select/state.tsx
rename to web/components/issues/view-select/state.tsx
diff --git a/apps/app/components/labels/create-label-modal.tsx b/web/components/labels/create-label-modal.tsx
similarity index 100%
rename from apps/app/components/labels/create-label-modal.tsx
rename to web/components/labels/create-label-modal.tsx
diff --git a/apps/app/components/labels/create-update-label-inline.tsx b/web/components/labels/create-update-label-inline.tsx
similarity index 100%
rename from apps/app/components/labels/create-update-label-inline.tsx
rename to web/components/labels/create-update-label-inline.tsx
diff --git a/apps/app/components/labels/delete-label-modal.tsx b/web/components/labels/delete-label-modal.tsx
similarity index 100%
rename from apps/app/components/labels/delete-label-modal.tsx
rename to web/components/labels/delete-label-modal.tsx
diff --git a/apps/app/components/labels/index.ts b/web/components/labels/index.ts
similarity index 100%
rename from apps/app/components/labels/index.ts
rename to web/components/labels/index.ts
diff --git a/apps/app/components/labels/labels-list-modal.tsx b/web/components/labels/labels-list-modal.tsx
similarity index 100%
rename from apps/app/components/labels/labels-list-modal.tsx
rename to web/components/labels/labels-list-modal.tsx
diff --git a/apps/app/components/labels/single-label-group.tsx b/web/components/labels/single-label-group.tsx
similarity index 100%
rename from apps/app/components/labels/single-label-group.tsx
rename to web/components/labels/single-label-group.tsx
diff --git a/apps/app/components/labels/single-label.tsx b/web/components/labels/single-label.tsx
similarity index 100%
rename from apps/app/components/labels/single-label.tsx
rename to web/components/labels/single-label.tsx
diff --git a/apps/app/components/modules/delete-module-modal.tsx b/web/components/modules/delete-module-modal.tsx
similarity index 100%
rename from apps/app/components/modules/delete-module-modal.tsx
rename to web/components/modules/delete-module-modal.tsx
diff --git a/apps/app/components/modules/form.tsx b/web/components/modules/form.tsx
similarity index 100%
rename from apps/app/components/modules/form.tsx
rename to web/components/modules/form.tsx
diff --git a/web/components/modules/gantt-chart/blocks.tsx b/web/components/modules/gantt-chart/blocks.tsx
new file mode 100644
index 000000000..c6400ad82
--- /dev/null
+++ b/web/components/modules/gantt-chart/blocks.tsx
@@ -0,0 +1,58 @@
+import { useRouter } from "next/router";
+
+// ui
+import { Tooltip } from "components/ui";
+// icons
+import { ModuleStatusIcon } from "components/icons";
+// helpers
+import { renderShortDate } from "helpers/date-time.helper";
+// types
+import { IModule } from "types";
+// constants
+import { MODULE_STATUS } from "constants/module";
+
+export const ModuleGanttBlock = ({ data }: { data: IModule }) => {
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+
+ return (
+ s.value === data?.status)?.color }}
+ onClick={() => router.push(`/${workspaceSlug}/projects/${data?.project}/modules/${data?.id}`)}
+ >
+
+
+ {data?.name}
+
+ {renderShortDate(data?.start_date ?? "")} to{" "}
+ {renderShortDate(data?.target_date ?? "")}
+
+
+ }
+ position="top-left"
+ >
+
+ {data?.name}
+
+
+
+ );
+};
+
+export const ModuleGanttSidebarBlock = ({ data }: { data: IModule }) => {
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+
+ return (
+ router.push(`/${workspaceSlug}/projects/${data?.project}/modules/${data.id}`)}
+ >
+
+
{data.name}
+
+ );
+};
diff --git a/web/components/modules/gantt-chart/index.ts b/web/components/modules/gantt-chart/index.ts
new file mode 100644
index 000000000..301b9f840
--- /dev/null
+++ b/web/components/modules/gantt-chart/index.ts
@@ -0,0 +1,3 @@
+export * from "./blocks";
+export * from "./module-issues-layout";
+export * from "./modules-list-layout";
diff --git a/apps/app/components/modules/gantt-chart.tsx b/web/components/modules/gantt-chart/module-issues-layout.tsx
similarity index 54%
rename from apps/app/components/modules/gantt-chart.tsx
rename to web/components/modules/gantt-chart/module-issues-layout.tsx
index 8ab8b6024..c350232e9 100644
--- a/apps/app/components/modules/gantt-chart.tsx
+++ b/web/components/modules/gantt-chart/module-issues-layout.tsx
@@ -7,12 +7,10 @@ import useIssuesView from "hooks/use-issues-view";
import useUser from "hooks/use-user";
import useGanttChartModuleIssues from "hooks/gantt-chart/module-issues-view";
import { updateGanttIssue } from "components/gantt-chart/hooks/block-update";
+import useProjectDetails from "hooks/use-project-details";
// components
-import {
- GanttChartRoot,
- IssueGanttBlock,
- renderIssueBlocksStructure,
-} from "components/gantt-chart";
+import { GanttChartRoot, renderIssueBlocksStructure } from "components/gantt-chart";
+import { IssueGanttBlock, IssueGanttSidebarBlock } from "components/issues";
// types
import { IIssue } from "types";
@@ -25,6 +23,7 @@ export const ModuleIssuesGanttChartView: FC = ({}) => {
const { orderBy } = useIssuesView();
const { user } = useUser();
+ const { projectDetails } = useProjectDetails();
const { ganttIssues, mutateGanttIssues } = useGanttChartModuleIssues(
workspaceSlug as string,
@@ -32,29 +31,25 @@ export const ModuleIssuesGanttChartView: FC = ({}) => {
moduleId as string
);
- // rendering issues on gantt sidebar
- const GanttSidebarBlockView = ({ data }: any) => (
-
- );
+ const isAllowed = projectDetails?.member_role === 20 || projectDetails?.member_role === 15;
return (
-
+
updateGanttIssue(block, payload, mutateGanttIssues, user, workspaceSlug?.toString())
}
- sidebarBlockRender={(data: any) => }
- blockRender={(data: any) => }
- enableReorder={orderBy === "sort_order"}
+ SidebarBlockRender={IssueGanttSidebarBlock}
+ BlockRender={IssueGanttBlock}
+ enableBlockLeftResize={isAllowed}
+ enableBlockRightResize={isAllowed}
+ enableBlockMove={isAllowed}
+ enableReorder={orderBy === "sort_order" && isAllowed}
+ bottomSpacing
/>
);
diff --git a/apps/app/components/modules/modules-list-gantt-chart.tsx b/web/components/modules/gantt-chart/modules-list-layout.tsx
similarity index 74%
rename from apps/app/components/modules/modules-list-gantt-chart.tsx
rename to web/components/modules/gantt-chart/modules-list-layout.tsx
index 7dc281fb3..08465ffa9 100644
--- a/apps/app/components/modules/modules-list-gantt-chart.tsx
+++ b/web/components/modules/gantt-chart/modules-list-layout.tsx
@@ -8,12 +8,12 @@ import { KeyedMutator } from "swr";
import modulesService from "services/modules.service";
// hooks
import useUser from "hooks/use-user";
+import useProjectDetails from "hooks/use-project-details";
// components
-import { GanttChartRoot, IBlockUpdateData, ModuleGanttBlock } from "components/gantt-chart";
+import { GanttChartRoot, IBlockUpdateData } from "components/gantt-chart";
+import { ModuleGanttBlock, ModuleGanttSidebarBlock } from "components/modules";
// types
import { IModule } from "types";
-// constants
-import { MODULE_STATUS } from "constants/module";
type Props = {
modules: IModule[];
@@ -25,19 +25,7 @@ export const ModulesListGanttChartView: FC
= ({ modules, mutateModules })
const { workspaceSlug } = router.query;
const { user } = useUser();
-
- // rendering issues on gantt sidebar
- const GanttSidebarBlockView = ({ data }: any) => (
-
-
s.value === data.status)?.color,
- }}
- />
-
{data?.name}
-
- );
+ const { projectDetails } = useProjectDetails();
const handleModuleUpdate = (module: IModule, payload: IBlockUpdateData) => {
if (!workspaceSlug || !user) return;
@@ -91,6 +79,8 @@ export const ModulesListGanttChartView: FC
= ({ modules, mutateModules })
}))
: [];
+ const isAllowed = projectDetails?.member_role === 20 || projectDetails?.member_role === 15;
+
return (
= ({ modules, mutateModules })
loaderTitle="Modules"
blocks={modules ? blockFormat(modules) : null}
blockUpdateHandler={(block, payload) => handleModuleUpdate(block, payload)}
- sidebarBlockRender={(data: any) => }
- blockRender={(data: any) => }
+ SidebarBlockRender={ModuleGanttSidebarBlock}
+ BlockRender={ModuleGanttBlock}
+ enableBlockLeftResize={isAllowed}
+ enableBlockRightResize={isAllowed}
+ enableBlockMove={isAllowed}
+ enableReorder={isAllowed}
/>
);
diff --git a/apps/app/components/modules/index.ts b/web/components/modules/index.ts
similarity index 84%
rename from apps/app/components/modules/index.ts
rename to web/components/modules/index.ts
index 5a5e2a4f1..2a7f54fb3 100644
--- a/apps/app/components/modules/index.ts
+++ b/web/components/modules/index.ts
@@ -4,6 +4,5 @@ export * from "./delete-module-modal";
export * from "./form";
export * from "./gantt-chart";
export * from "./modal";
-export * from "./modules-list-gantt-chart";
export * from "./sidebar";
export * from "./single-module-card";
diff --git a/apps/app/components/modules/modal.tsx b/web/components/modules/modal.tsx
similarity index 100%
rename from apps/app/components/modules/modal.tsx
rename to web/components/modules/modal.tsx
diff --git a/apps/app/components/modules/select/index.ts b/web/components/modules/select/index.ts
similarity index 100%
rename from apps/app/components/modules/select/index.ts
rename to web/components/modules/select/index.ts
diff --git a/apps/app/components/modules/select/lead.tsx b/web/components/modules/select/lead.tsx
similarity index 100%
rename from apps/app/components/modules/select/lead.tsx
rename to web/components/modules/select/lead.tsx
diff --git a/apps/app/components/modules/select/members.tsx b/web/components/modules/select/members.tsx
similarity index 100%
rename from apps/app/components/modules/select/members.tsx
rename to web/components/modules/select/members.tsx
diff --git a/apps/app/components/modules/select/status.tsx b/web/components/modules/select/status.tsx
similarity index 78%
rename from apps/app/components/modules/select/status.tsx
rename to web/components/modules/select/status.tsx
index 08192cd5d..8c16ca14c 100644
--- a/apps/app/components/modules/select/status.tsx
+++ b/web/components/modules/select/status.tsx
@@ -6,6 +6,7 @@ import { Controller, FieldError, Control } from "react-hook-form";
import { CustomSelect } from "components/ui";
// icons
import { Squares2X2Icon } from "@heroicons/react/24/outline";
+import { ModuleStatusIcon } from "components/icons";
// types
import type { IModule } from "types";
// constants
@@ -31,12 +32,7 @@ export const ModuleStatusSelect: React.FC = ({ control, error }) => (
}`}
>
{value ? (
- s.value === value)?.color,
- }}
- />
+
) : (
= ({ control, error }) => (
{MODULE_STATUS.map((status) => (
-
+
{status.label}
diff --git a/apps/app/components/modules/sidebar-select/index.ts b/web/components/modules/sidebar-select/index.ts
similarity index 100%
rename from apps/app/components/modules/sidebar-select/index.ts
rename to web/components/modules/sidebar-select/index.ts
diff --git a/apps/app/components/modules/sidebar-select/select-lead.tsx b/web/components/modules/sidebar-select/select-lead.tsx
similarity index 100%
rename from apps/app/components/modules/sidebar-select/select-lead.tsx
rename to web/components/modules/sidebar-select/select-lead.tsx
diff --git a/apps/app/components/modules/sidebar-select/select-members.tsx b/web/components/modules/sidebar-select/select-members.tsx
similarity index 100%
rename from apps/app/components/modules/sidebar-select/select-members.tsx
rename to web/components/modules/sidebar-select/select-members.tsx
diff --git a/apps/app/components/modules/sidebar-select/select-status.tsx b/web/components/modules/sidebar-select/select-status.tsx
similarity index 100%
rename from apps/app/components/modules/sidebar-select/select-status.tsx
rename to web/components/modules/sidebar-select/select-status.tsx
diff --git a/apps/app/components/modules/sidebar.tsx b/web/components/modules/sidebar.tsx
similarity index 99%
rename from apps/app/components/modules/sidebar.tsx
rename to web/components/modules/sidebar.tsx
index 0407b95aa..e815d1950 100644
--- a/apps/app/components/modules/sidebar.tsx
+++ b/web/components/modules/sidebar.tsx
@@ -48,7 +48,7 @@ const defaultValues: Partial = {
members_list: [],
start_date: null,
target_date: null,
- status: null,
+ status: "backlog",
};
type Props = {
diff --git a/apps/app/components/modules/single-module-card.tsx b/web/components/modules/single-module-card.tsx
similarity index 100%
rename from apps/app/components/modules/single-module-card.tsx
rename to web/components/modules/single-module-card.tsx
diff --git a/apps/app/components/notifications/index.ts b/web/components/notifications/index.ts
similarity index 100%
rename from apps/app/components/notifications/index.ts
rename to web/components/notifications/index.ts
diff --git a/apps/app/components/notifications/notification-card.tsx b/web/components/notifications/notification-card.tsx
similarity index 99%
rename from apps/app/components/notifications/notification-card.tsx
rename to web/components/notifications/notification-card.tsx
index 9bb0715a8..29fe579a8 100644
--- a/apps/app/components/notifications/notification-card.tsx
+++ b/web/components/notifications/notification-card.tsx
@@ -210,7 +210,7 @@ export const NotificationCard: React.FC = (props) => {
{
+ menuButtonOnClick={(e: { stopPropagation: () => void }) => {
e.stopPropagation();
}}
customButton={
diff --git a/apps/app/components/notifications/notification-header.tsx b/web/components/notifications/notification-header.tsx
similarity index 79%
rename from apps/app/components/notifications/notification-header.tsx
rename to web/components/notifications/notification-header.tsx
index e1003f636..0d181da98 100644
--- a/apps/app/components/notifications/notification-header.tsx
+++ b/web/components/notifications/notification-header.tsx
@@ -1,7 +1,7 @@
import React from "react";
// components
-import { Icon, Tooltip } from "components/ui";
+import { CustomMenu, Icon, Tooltip } from "components/ui";
// helpers
import { getNumberCount } from "helpers/string.helper";
@@ -21,6 +21,7 @@ type NotificationHeaderProps = {
setArchived: React.Dispatch>;
setReadNotification: React.Dispatch>;
setSelectedTab: React.Dispatch>;
+ markAllNotificationsAsRead: () => Promise;
};
export const NotificationHeader: React.FC = (props) => {
@@ -37,6 +38,7 @@ export const NotificationHeader: React.FC = (props) =>
setArchived,
setReadNotification,
setSelectedTab,
+ markAllNotificationsAsRead,
} = props;
const notificationTabs: Array<{
@@ -88,33 +90,51 @@ export const NotificationHeader: React.FC = (props) =>
-
-
+
+
+ }
+ >
+
+
+
+ Mark all as read
+
+
+ {
setArchived(false);
setReadNotification(false);
setSnoozed((prev) => !prev);
}}
>
-
-
-
-
-
+
+ Show snoozed
+
+
+ {
setSnoozed(false);
setReadNotification(false);
setArchived((prev) => !prev);
}}
>
-
+
+
+ Show archived
+
+
+
+
+ closePopover()}>
+
- closePopover()}>
-
-
diff --git a/apps/app/components/notifications/notification-popover.tsx b/web/components/notifications/notification-popover.tsx
similarity index 97%
rename from apps/app/components/notifications/notification-popover.tsx
rename to web/components/notifications/notification-popover.tsx
index 39e4d8764..f01fdafd1 100644
--- a/apps/app/components/notifications/notification-popover.tsx
+++ b/web/components/notifications/notification-popover.tsx
@@ -51,6 +51,7 @@ export const NotificationPopover = () => {
hasMore,
isRefreshing,
setFetchNotifications,
+ markAllNotificationsAsRead,
} = useUserNotification();
// theme context
@@ -112,7 +113,7 @@ export const NotificationPopover = () => {
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
-
+
{
setArchived={setArchived}
setReadNotification={setReadNotification}
setSelectedTab={setSelectedTab}
+ markAllNotificationsAsRead={markAllNotificationsAsRead}
/>
{notifications ? (
diff --git a/apps/app/components/notifications/select-snooze-till-modal.tsx b/web/components/notifications/select-snooze-till-modal.tsx
similarity index 100%
rename from apps/app/components/notifications/select-snooze-till-modal.tsx
rename to web/components/notifications/select-snooze-till-modal.tsx
diff --git a/apps/app/components/onboarding/index.ts b/web/components/onboarding/index.ts
similarity index 100%
rename from apps/app/components/onboarding/index.ts
rename to web/components/onboarding/index.ts
diff --git a/apps/app/components/onboarding/invite-members.tsx b/web/components/onboarding/invite-members.tsx
similarity index 100%
rename from apps/app/components/onboarding/invite-members.tsx
rename to web/components/onboarding/invite-members.tsx
diff --git a/apps/app/components/onboarding/join-workspaces.tsx b/web/components/onboarding/join-workspaces.tsx
similarity index 100%
rename from apps/app/components/onboarding/join-workspaces.tsx
rename to web/components/onboarding/join-workspaces.tsx
diff --git a/apps/app/components/onboarding/tour/index.ts b/web/components/onboarding/tour/index.ts
similarity index 100%
rename from apps/app/components/onboarding/tour/index.ts
rename to web/components/onboarding/tour/index.ts
diff --git a/apps/app/components/onboarding/tour/root.tsx b/web/components/onboarding/tour/root.tsx
similarity index 100%
rename from apps/app/components/onboarding/tour/root.tsx
rename to web/components/onboarding/tour/root.tsx
diff --git a/apps/app/components/onboarding/tour/sidebar.tsx b/web/components/onboarding/tour/sidebar.tsx
similarity index 100%
rename from apps/app/components/onboarding/tour/sidebar.tsx
rename to web/components/onboarding/tour/sidebar.tsx
diff --git a/apps/app/components/onboarding/user-details.tsx b/web/components/onboarding/user-details.tsx
similarity index 100%
rename from apps/app/components/onboarding/user-details.tsx
rename to web/components/onboarding/user-details.tsx
diff --git a/apps/app/components/onboarding/workspace.tsx b/web/components/onboarding/workspace.tsx
similarity index 100%
rename from apps/app/components/onboarding/workspace.tsx
rename to web/components/onboarding/workspace.tsx
diff --git a/apps/app/components/pages/create-block.tsx b/web/components/pages/create-block.tsx
similarity index 100%
rename from apps/app/components/pages/create-block.tsx
rename to web/components/pages/create-block.tsx
diff --git a/apps/app/components/pages/create-update-block-inline.tsx b/web/components/pages/create-update-block-inline.tsx
similarity index 94%
rename from apps/app/components/pages/create-update-block-inline.tsx
rename to web/components/pages/create-update-block-inline.tsx
index 3e0f604a3..cee9fe8e3 100644
--- a/apps/app/components/pages/create-update-block-inline.tsx
+++ b/web/components/pages/create-update-block-inline.tsx
@@ -1,12 +1,7 @@
import React, { useCallback, useEffect, useState } from "react";
-
import { useRouter } from "next/router";
-
import { mutate } from "swr";
-
import { SparklesIcon } from "@heroicons/react/24/outline";
-
-// react-hook-form
import { Controller, useForm } from "react-hook-form";
// services
import pagesService from "services/pages.service";
@@ -16,13 +11,12 @@ import aiService from "services/ai.service";
import useToast from "hooks/use-toast";
// components
import { GptAssistantModal } from "components/core";
-// ui
+import { TipTapEditor } from "components/tiptap";
import { PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// types
import { ICurrentUserResponse, IPageBlock } from "types";
// fetch-keys
import { PAGE_BLOCKS_LIST } from "constants/fetch-keys";
-import Tiptap, { ITiptapRichTextEditor } from "components/tiptap";
type Props = {
handleClose: () => void;
@@ -39,12 +33,6 @@ const defaultValues = {
description_html: null,
};
-const TiptapEditor = React.forwardRef(
- (props, ref) =>
-);
-
-TiptapEditor.displayName = "TiptapEditor";
-
export const CreateUpdateBlockInline: React.FC = ({
handleClose,
data,
@@ -231,9 +219,9 @@ export const CreateUpdateBlockInline: React.FC = ({
description:
!data.description || data.description === ""
? {
- type: "doc",
- content: [{ type: "paragraph" }],
- }
+ type: "doc",
+ content: [{ type: "paragraph" }],
+ }
: data.description,
description_html: data.description_html ?? "
",
});
@@ -291,7 +279,7 @@ export const CreateUpdateBlockInline: React.FC = ({
render={({ field: { value, onChange } }) => {
if (!data)
return (
- "}
@@ -311,7 +299,7 @@ export const CreateUpdateBlockInline: React.FC = ({
);
return (
- = ({
@@ -367,8 +356,8 @@ export const CreateUpdateBlockInline: React.FC = ({
? "Updating..."
: "Update block"
: isSubmitting
- ? "Adding..."
- : "Add block"}
+ ? "Adding..."
+ : "Add block"}
diff --git a/apps/app/components/pages/create-update-page-modal.tsx b/web/components/pages/create-update-page-modal.tsx
similarity index 100%
rename from apps/app/components/pages/create-update-page-modal.tsx
rename to web/components/pages/create-update-page-modal.tsx
diff --git a/apps/app/components/pages/delete-page-modal.tsx b/web/components/pages/delete-page-modal.tsx
similarity index 100%
rename from apps/app/components/pages/delete-page-modal.tsx
rename to web/components/pages/delete-page-modal.tsx
diff --git a/apps/app/components/pages/index.ts b/web/components/pages/index.ts
similarity index 100%
rename from apps/app/components/pages/index.ts
rename to web/components/pages/index.ts
diff --git a/apps/app/components/pages/page-form.tsx b/web/components/pages/page-form.tsx
similarity index 100%
rename from apps/app/components/pages/page-form.tsx
rename to web/components/pages/page-form.tsx
diff --git a/apps/app/components/pages/pages-list/all-pages-list.tsx b/web/components/pages/pages-list/all-pages-list.tsx
similarity index 100%
rename from apps/app/components/pages/pages-list/all-pages-list.tsx
rename to web/components/pages/pages-list/all-pages-list.tsx
diff --git a/apps/app/components/pages/pages-list/favorite-pages-list.tsx b/web/components/pages/pages-list/favorite-pages-list.tsx
similarity index 100%
rename from apps/app/components/pages/pages-list/favorite-pages-list.tsx
rename to web/components/pages/pages-list/favorite-pages-list.tsx
diff --git a/apps/app/components/pages/pages-list/index.ts b/web/components/pages/pages-list/index.ts
similarity index 100%
rename from apps/app/components/pages/pages-list/index.ts
rename to web/components/pages/pages-list/index.ts
diff --git a/apps/app/components/pages/pages-list/my-pages-list.tsx b/web/components/pages/pages-list/my-pages-list.tsx
similarity index 100%
rename from apps/app/components/pages/pages-list/my-pages-list.tsx
rename to web/components/pages/pages-list/my-pages-list.tsx
diff --git a/apps/app/components/pages/pages-list/other-pages-list.tsx b/web/components/pages/pages-list/other-pages-list.tsx
similarity index 100%
rename from apps/app/components/pages/pages-list/other-pages-list.tsx
rename to web/components/pages/pages-list/other-pages-list.tsx
diff --git a/apps/app/components/pages/pages-list/recent-pages-list.tsx b/web/components/pages/pages-list/recent-pages-list.tsx
similarity index 100%
rename from apps/app/components/pages/pages-list/recent-pages-list.tsx
rename to web/components/pages/pages-list/recent-pages-list.tsx
diff --git a/apps/app/components/pages/pages-list/types.ts b/web/components/pages/pages-list/types.ts
similarity index 100%
rename from apps/app/components/pages/pages-list/types.ts
rename to web/components/pages/pages-list/types.ts
diff --git a/apps/app/components/pages/pages-view.tsx b/web/components/pages/pages-view.tsx
similarity index 100%
rename from apps/app/components/pages/pages-view.tsx
rename to web/components/pages/pages-view.tsx
diff --git a/apps/app/components/pages/single-page-block.tsx b/web/components/pages/single-page-block.tsx
similarity index 92%
rename from apps/app/components/pages/single-page-block.tsx
rename to web/components/pages/single-page-block.tsx
index 0c192990a..e4c1d94ac 100644
--- a/apps/app/components/pages/single-page-block.tsx
+++ b/web/components/pages/single-page-block.tsx
@@ -19,6 +19,7 @@ import useOutsideClickDetector from "hooks/use-outside-click-detector";
// components
import { GptAssistantModal } from "components/core";
import { CreateUpdateBlockInline } from "components/pages";
+import { TipTapEditor } from "components/tiptap";
// ui
import { CustomMenu, TextArea } from "components/ui";
// icons
@@ -38,7 +39,6 @@ import { copyTextToClipboard } from "helpers/string.helper";
import { ICurrentUserResponse, IIssue, IPageBlock, IProject } from "types";
// fetch-keys
import { PAGE_BLOCKS_LIST } from "constants/fetch-keys";
-import Tiptap, { ITiptapRichTextEditor } from "components/tiptap";
type Props = {
block: IPageBlock;
@@ -48,13 +48,6 @@ type Props = {
user: ICurrentUserResponse | undefined;
};
-const TiptapEditor = React.forwardRef<
- ITiptapRichTextEditor,
- ITiptapRichTextEditor
->((props, ref) => );
-
-TiptapEditor.displayName = "TiptapEditor";
-
export const SinglePageBlock: React.FC = ({
block,
projectDetails,
@@ -328,8 +321,9 @@ export const SinglePageBlock: React.FC = ({
) : (
@@ -343,8 +337,9 @@ export const SinglePageBlock: React.FC
= ({
{block.issue && block.sync && (
@@ -358,8 +353,9 @@ export const SinglePageBlock: React.FC
= ({
)}
@@ -455,18 +451,19 @@ export const SinglePageBlock: React.FC = ({
{showBlockDetails
? block.description_html.length > 7 && (
-
- ) : block.description_stripped.length > 0 && (
-
- {block.description_stripped}
-
- )}
+
+ )
+ : block.description_stripped.length > 0 && (
+
+ {block.description_stripped}
+
+ )}
{
onSelect={(option) => {
const key = option.key as keyof typeof filters;
- if (key === "target_date") {
- const valueExists = checkIfArraysHaveSameElements(
- filters?.target_date ?? [],
- option.value
- );
+ if (key === "start_date" || key === "target_date") {
+ const valueExists = checkIfArraysHaveSameElements(filters?.[key] ?? [], option.value);
setFilters({
- target_date: valueExists ? null : option.value,
+ [key]: valueExists ? null : option.value,
});
} else {
const valueExists = filters[key]?.includes(option.value);
@@ -152,7 +149,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
: "text-custom-sidebar-text-200"
}`}
>
- View
+ Display
@@ -186,7 +183,11 @@ export const ProfileIssuesViewOptions: React.FC = () => {
>
{GROUP_BY_OPTIONS.map((option) => {
if (issueView === "kanban" && option.key === null) return null;
- if (option.key === "state" || option.key === "created_by")
+ if (
+ option.key === "state" ||
+ option.key === "created_by" ||
+ option.key === "assignees"
+ )
return null;
return (
diff --git a/apps/app/components/profile/profile-issues-view.tsx b/web/components/profile/profile-issues-view.tsx
similarity index 95%
rename from apps/app/components/profile/profile-issues-view.tsx
rename to web/components/profile/profile-issues-view.tsx
index 44120a61c..353b55ae2 100644
--- a/apps/app/components/profile/profile-issues-view.tsx
+++ b/web/components/profile/profile-issues-view.tsx
@@ -223,6 +223,15 @@ export const ProfileIssuesView = () => {
Object.keys(filtersToDisplay).length > 0 &&
nullFilters.length !== Object.keys(filtersToDisplay).length;
+ const isSubscribedIssuesRoute = router.pathname.includes("subscribed");
+ const isMySubscribedIssues =
+ (filters.subscriber &&
+ filters.subscriber.length > 0 &&
+ router.pathname.includes("my-issues")) ??
+ false;
+
+ const disableAddIssueOption = isSubscribedIssuesRoute || isMySubscribedIssues;
+
return (
<>
{
isOpen={deleteIssueModal}
data={issueToDelete}
user={user}
+ onSubmit={async () => {
+ mutateProfileIssues();
+ }}
/>
{areFiltersApplied && (
<>
@@ -263,6 +275,7 @@ export const ProfileIssuesView = () => {
labels: null,
priority: null,
state_group: null,
+ start_date: null,
target_date: null,
type: null,
})
@@ -288,6 +301,7 @@ export const ProfileIssuesView = () => {
handleIssueAction={handleIssueAction}
openIssuesListModal={null}
removeIssue={null}
+ disableAddIssueOption={disableAddIssueOption}
trashBox={trashBox}
setTrashBox={setTrashBox}
viewProps={{
diff --git a/apps/app/components/profile/sidebar.tsx b/web/components/profile/sidebar.tsx
similarity index 87%
rename from apps/app/components/profile/sidebar.tsx
rename to web/components/profile/sidebar.tsx
index d49058c67..59cc5528b 100644
--- a/apps/app/components/profile/sidebar.tsx
+++ b/web/components/profile/sidebar.tsx
@@ -3,8 +3,6 @@ import Link from "next/link";
import useSWR from "swr";
-// next-themes
-import { useTheme } from "next-themes";
// headless ui
import { Disclosure, Transition } from "@headlessui/react";
// services
@@ -16,7 +14,7 @@ import { Icon, Loader, Tooltip } from "components/ui";
// icons
import { EditOutlined } from "@mui/icons-material";
// helpers
-import { render12HourFormatTime, renderLongDetailDateFormat } from "helpers/date-time.helper";
+import { renderLongDetailDateFormat } from "helpers/date-time.helper";
import { renderEmoji } from "helpers/emoji.helper";
// fetch-keys
import { USER_PROFILE_PROJECT_SEGREGATION } from "constants/fetch-keys";
@@ -25,8 +23,6 @@ export const ProfileSidebar = () => {
const router = useRouter();
const { workspaceSlug, userId } = router.query;
- const { theme } = useTheme();
-
const { user } = useUser();
const { data: userProjectsData } = useSWR(
@@ -39,6 +35,16 @@ export const ProfileSidebar = () => {
: null
);
+ // Create a date object for the current time in the specified timezone
+ const currentTime = new Date();
+ const formatter = new Intl.DateTimeFormat("en-US", {
+ timeZone: userProjectsData?.user_data.user_timezone,
+ hour12: false, // Use 24-hour format
+ hour: "2-digit",
+ minute: "2-digit",
+ });
+ const timeString = formatter.format(currentTime);
+
const userDetails = [
{
label: "Joined on",
@@ -48,7 +54,7 @@ export const ProfileSidebar = () => {
label: "Timezone",
value: (
- {render12HourFormatTime(new Date())}{" "}
+ {timeString}{" "}
{userProjectsData?.user_data.user_timezone}
),
@@ -56,15 +62,7 @@ export const ProfileSidebar = () => {
];
return (
-
+
{userProjectsData ? (
<>
@@ -127,12 +125,11 @@ export const ProfileSidebar = () => {
project.assigned_issues +
project.pending_issues +
project.completed_issues;
- const totalAssignedIssues = totalIssues - project.created_issues;
const completedIssuePercentage =
- totalAssignedIssues === 0
+ project.assigned_issues === 0
? 0
- : Math.round((project.completed_issues / totalAssignedIssues) * 100);
+ : Math.round((project.completed_issues / project.assigned_issues) * 100);
return (
{
-
-
- {completedIssuePercentage}%
-
-
+ {project.assigned_issues > 0 && (
+
+
+ {completedIssuePercentage}%
+
+
+ )}
diff --git a/web/components/project/confirm-project-leave-modal.tsx b/web/components/project/confirm-project-leave-modal.tsx
new file mode 100644
index 000000000..7d6582869
--- /dev/null
+++ b/web/components/project/confirm-project-leave-modal.tsx
@@ -0,0 +1,211 @@
+import React from "react";
+// next imports
+import { useRouter } from "next/router";
+// react-hook-form
+import { Controller, useForm } from "react-hook-form";
+// headless ui
+import { Dialog, Transition } from "@headlessui/react";
+// icons
+import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
+// ui
+import { DangerButton, Input, SecondaryButton } from "components/ui";
+// fetch-keys
+import { PROJECTS_LIST } from "constants/fetch-keys";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// mobx store
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+// hooks
+import useToast from "hooks/use-toast";
+import useUser from "hooks/use-user";
+import useProjects from "hooks/use-projects";
+// types
+import { IProject } from "types";
+
+type FormData = {
+ projectName: string;
+ confirmLeave: string;
+};
+
+const defaultValues: FormData = {
+ projectName: "",
+ confirmLeave: "",
+};
+
+export const ConfirmProjectLeaveModal: React.FC = observer(() => {
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+
+ const store: RootStore = useMobxStore();
+ const { project } = store;
+
+ const { user } = useUser();
+ const { mutateProjects } = useProjects();
+
+ const { setToastAlert } = useToast();
+
+ const {
+ control,
+ formState: { isSubmitting },
+ handleSubmit,
+ reset,
+ watch,
+ } = useForm({ defaultValues });
+
+ const handleClose = () => {
+ project.handleProjectLeaveModal(null);
+
+ reset({ ...defaultValues });
+ };
+
+ const onSubmit = async (data: any) => {
+ if (data) {
+ if (data.projectName === project?.projectLeaveDetails?.name) {
+ if (data.confirmLeave === "Leave Project") {
+ return project
+ .leaveProject(
+ project.projectLeaveDetails.workspaceSlug.toString(),
+ project.projectLeaveDetails.id.toString(),
+ user
+ )
+ .then((res) => {
+ mutateProjects();
+ handleClose();
+ router.push(`/${workspaceSlug}/projects`);
+ })
+ .catch((err) => {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Something went wrong please try again later.",
+ });
+ });
+ } else {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Please confirm leaving the project by typing the 'Leave Project'.",
+ });
+ }
+ } else {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Please enter the project name as shown in the description.",
+ });
+ }
+ } else {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Please fill all fields.",
+ });
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Leave Project
+
+
+
+
+
+ Are you sure you want to leave the project -
+ {` "${project?.projectLeaveDetails?.name}" `}
+ ? All of the issues associated with you will become inaccessible.
+
+
+
+
+
+ Enter the project name{" "}
+
+ {project?.projectLeaveDetails?.name}
+ {" "}
+ to continue:
+
+
(
+
+ )}
+ />
+
+
+
+
+ To confirm, type{" "}
+ Leave Project below:
+
+
(
+
+ )}
+ />
+
+
+ Cancel
+
+ {isSubmitting ? "Leaving..." : "Leave Project"}
+
+
+
+
+
+
+
+
+
+ );
+});
diff --git a/apps/app/components/project/confirm-project-member-remove.tsx b/web/components/project/confirm-project-member-remove.tsx
similarity index 100%
rename from apps/app/components/project/confirm-project-member-remove.tsx
rename to web/components/project/confirm-project-member-remove.tsx
diff --git a/apps/app/components/project/create-project-modal.tsx b/web/components/project/create-project-modal.tsx
similarity index 100%
rename from apps/app/components/project/create-project-modal.tsx
rename to web/components/project/create-project-modal.tsx
diff --git a/apps/app/components/project/delete-project-modal.tsx b/web/components/project/delete-project-modal.tsx
similarity index 97%
rename from apps/app/components/project/delete-project-modal.tsx
rename to web/components/project/delete-project-modal.tsx
index 5b271d99d..d6f7ba0f0 100644
--- a/apps/app/components/project/delete-project-modal.tsx
+++ b/web/components/project/delete-project-modal.tsx
@@ -42,7 +42,7 @@ export const DeleteProjectModal: React.FC
= ({
user,
}) => {
const router = useRouter();
- const { workspaceSlug } = router.query;
+ const { workspaceSlug, projectId } = router.query;
const { setToastAlert } = useToast();
@@ -81,6 +81,8 @@ export const DeleteProjectModal: React.FC = ({
);
if (onSuccess) onSuccess();
+
+ if (projectId && projectId === data.id) router.push(`/${workspaceSlug}/projects`);
})
.catch(() =>
setToastAlert({
diff --git a/apps/app/components/project/index.ts b/web/components/project/index.ts
similarity index 74%
rename from apps/app/components/project/index.ts
rename to web/components/project/index.ts
index e5ece3955..494a04294 100644
--- a/apps/app/components/project/index.ts
+++ b/web/components/project/index.ts
@@ -1,7 +1,8 @@
export * from "./create-project-modal";
export * from "./delete-project-modal";
export * from "./sidebar-list";
-export * from "./settings-header"
+export * from "./settings-header";
export * from "./single-integration-card";
export * from "./single-project-card";
export * from "./single-sidebar-project";
+export * from "./confirm-project-leave-modal";
diff --git a/apps/app/components/project/join-project-modal.tsx b/web/components/project/join-project-modal.tsx
similarity index 100%
rename from apps/app/components/project/join-project-modal.tsx
rename to web/components/project/join-project-modal.tsx
diff --git a/web/components/project/publish-project/modal.tsx b/web/components/project/publish-project/modal.tsx
new file mode 100644
index 000000000..173a5242c
--- /dev/null
+++ b/web/components/project/publish-project/modal.tsx
@@ -0,0 +1,528 @@
+import React, { useEffect, useState } from "react";
+// next imports
+import { useRouter } from "next/router";
+// react-hook-form
+import { Controller, useForm } from "react-hook-form";
+// headless ui
+import { Dialog, Transition } from "@headlessui/react";
+// ui components
+import {
+ ToggleSwitch,
+ PrimaryButton,
+ SecondaryButton,
+ Icon,
+ DangerButton,
+ Loader,
+} from "components/ui";
+import { CustomPopover } from "./popover";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// mobx store
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+import { IProjectPublishSettings, TProjectPublishViews } from "store/project-publish";
+// hooks
+import useToast from "hooks/use-toast";
+import useProjectDetails from "hooks/use-project-details";
+import useUser from "hooks/use-user";
+
+type Props = {
+ // user: ICurrentUserResponse | undefined;
+};
+
+type FormData = {
+ id: string | null;
+ comments: boolean;
+ reactions: boolean;
+ votes: boolean;
+ inbox: string | null;
+ views: TProjectPublishViews[];
+};
+
+const defaultValues: FormData = {
+ id: null,
+ comments: false,
+ reactions: false,
+ votes: false,
+ inbox: null,
+ views: ["list", "kanban"],
+};
+
+const viewOptions: {
+ key: TProjectPublishViews;
+ label: string;
+}[] = [
+ { key: "list", label: "List" },
+ { key: "kanban", label: "Kanban" },
+ // { key: "calendar", label: "Calendar" },
+ // { key: "gantt", label: "Gantt" },
+ // { key: "spreadsheet", label: "Spreadsheet" },
+];
+
+export const PublishProjectModal: React.FC = observer(() => {
+ const [isUnpublishing, setIsUnpublishing] = useState(false);
+ const [isUpdateRequired, setIsUpdateRequired] = useState(false);
+
+ const plane_deploy_url = process.env.NEXT_PUBLIC_DEPLOY_URL ?? "http://localhost:4000";
+
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+
+ const store: RootStore = useMobxStore();
+ const { projectPublish } = store;
+
+ const { user } = useUser();
+
+ const { mutateProjectDetails } = useProjectDetails();
+
+ const { setToastAlert } = useToast();
+
+ const {
+ control,
+ formState: { isSubmitting },
+ getValues,
+ handleSubmit,
+ reset,
+ watch,
+ } = useForm({
+ defaultValues,
+ });
+
+ const handleClose = () => {
+ projectPublish.handleProjectModal(null);
+
+ setIsUpdateRequired(false);
+ reset({ ...defaultValues });
+ };
+
+ // prefill form with the saved settings if the project is already published
+ useEffect(() => {
+ if (
+ projectPublish.projectPublishSettings &&
+ projectPublish.projectPublishSettings !== "not-initialized"
+ ) {
+ let userBoards: TProjectPublishViews[] = [];
+
+ if (projectPublish.projectPublishSettings?.views) {
+ const savedViews = projectPublish.projectPublishSettings?.views;
+
+ if (!savedViews) return;
+
+ if (savedViews.list) userBoards.push("list");
+ if (savedViews.kanban) userBoards.push("kanban");
+ if (savedViews.calendar) userBoards.push("calendar");
+ if (savedViews.gantt) userBoards.push("gantt");
+ if (savedViews.spreadsheet) userBoards.push("spreadsheet");
+
+ userBoards = userBoards && userBoards.length > 0 ? userBoards : ["list"];
+ }
+
+ const updatedData = {
+ id: projectPublish.projectPublishSettings?.id || null,
+ comments: projectPublish.projectPublishSettings?.comments || false,
+ reactions: projectPublish.projectPublishSettings?.reactions || false,
+ votes: projectPublish.projectPublishSettings?.votes || false,
+ inbox: projectPublish.projectPublishSettings?.inbox || null,
+ views: userBoards,
+ };
+
+ reset({ ...updatedData });
+ }
+ }, [reset, projectPublish.projectPublishSettings]);
+
+ // fetch publish settings
+ useEffect(() => {
+ if (!workspaceSlug) return;
+
+ if (
+ projectPublish.projectPublishModal &&
+ projectPublish.project_id !== null &&
+ projectPublish?.projectPublishSettings === "not-initialized"
+ ) {
+ projectPublish.getProjectSettingsAsync(
+ workspaceSlug.toString(),
+ projectPublish.project_id,
+ null
+ );
+ }
+ }, [workspaceSlug, projectPublish, projectPublish.projectPublishModal]);
+
+ const handlePublishProject = async (payload: IProjectPublishSettings) => {
+ if (!workspaceSlug || !user) return;
+
+ const projectId = projectPublish.project_id;
+
+ return projectPublish
+ .publishProject(workspaceSlug.toString(), projectId?.toString() ?? "", payload, user)
+ .then((res) => {
+ mutateProjectDetails();
+ handleClose();
+ if (projectId) window.open(`${plane_deploy_url}/${workspaceSlug}/${projectId}`, "_blank");
+ return res;
+ })
+ .catch((err) => err);
+ };
+
+ const handleUpdatePublishSettings = async (payload: IProjectPublishSettings) => {
+ if (!workspaceSlug || !user) return;
+
+ await projectPublish
+ .updateProjectSettingsAsync(
+ workspaceSlug.toString(),
+ projectPublish.project_id?.toString() ?? "",
+ payload.id ?? "",
+ payload,
+ user
+ )
+ .then((res) => {
+ mutateProjectDetails();
+
+ setToastAlert({
+ type: "success",
+ title: "Success!",
+ message: "Publish settings updated successfully!",
+ });
+
+ handleClose();
+ return res;
+ })
+ .catch((error) => {
+ console.log("error", error);
+ return error;
+ });
+ };
+
+ const handleUnpublishProject = async (publishId: string) => {
+ if (!workspaceSlug || !publishId) return;
+
+ setIsUnpublishing(true);
+
+ projectPublish
+ .unPublishProject(
+ workspaceSlug.toString(),
+ projectPublish.project_id as string,
+ publishId,
+ null
+ )
+ .then((res) => {
+ mutateProjectDetails();
+
+ handleClose();
+ return res;
+ })
+ .catch((err) => err)
+ .finally(() => setIsUnpublishing(false));
+ };
+
+ const CopyLinkToClipboard = ({ copy_link }: { copy_link: string }) => {
+ const [status, setStatus] = useState(false);
+
+ const copyText = () => {
+ navigator.clipboard.writeText(copy_link);
+ setStatus(true);
+ setTimeout(() => {
+ setStatus(false);
+ }, 1000);
+ };
+
+ return (
+ copyText()}
+ >
+ {status ? "Copied" : "Copy Link"}
+
+ );
+ };
+
+ const handleFormSubmit = async (formData: FormData) => {
+ if (!formData.views || formData.views.length === 0) {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Please select at least one view layout to publish the project.",
+ });
+ return;
+ }
+
+ const payload = {
+ comments: formData.comments,
+ reactions: formData.reactions,
+ votes: formData.votes,
+ inbox: formData.inbox,
+ views: {
+ list: formData.views.includes("list"),
+ kanban: formData.views.includes("kanban"),
+ calendar: formData.views.includes("calendar"),
+ gantt: formData.views.includes("gantt"),
+ spreadsheet: formData.views.includes("spreadsheet"),
+ },
+ };
+
+ if (watch("id")) await handleUpdatePublishSettings({ id: watch("id") ?? "", ...payload });
+ else await handlePublishProject(payload);
+ };
+
+ // check if an update is required or not
+ const checkIfUpdateIsRequired = () => {
+ if (
+ !projectPublish.projectPublishSettings ||
+ projectPublish.projectPublishSettings === "not-initialized"
+ )
+ return;
+
+ const currentSettings = projectPublish.projectPublishSettings as IProjectPublishSettings;
+ const newSettings = getValues();
+
+ if (
+ currentSettings.comments !== newSettings.comments ||
+ currentSettings.reactions !== newSettings.reactions ||
+ currentSettings.votes !== newSettings.votes
+ ) {
+ setIsUpdateRequired(true);
+ return;
+ }
+
+ let viewCheckFlag = 0;
+ viewOptions.forEach((option) => {
+ if (currentSettings.views[option.key] !== newSettings.views.includes(option.key))
+ viewCheckFlag++;
+ });
+
+ if (viewCheckFlag !== 0) {
+ setIsUpdateRequired(true);
+ return;
+ }
+
+ setIsUpdateRequired(false);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {/* heading */}
+
+
Publish
+ {projectPublish.projectPublishSettings !== "not-initialized" && (
+ handleUnpublishProject(watch("id") ?? "")}
+ className="!px-2 !py-1.5"
+ loading={isUnpublishing}
+ >
+ {isUnpublishing ? "Unpublishing..." : "Unpublish"}
+
+ )}
+
+
+ {/* content */}
+ {projectPublish.fetchSettingsLoader ? (
+
+
+
+
+
+
+ ) : (
+
+ {watch("id") && (
+ <>
+
+
+ {`${plane_deploy_url}/${workspaceSlug}/${projectPublish.project_id}`}
+
+
+
+
+
+
+
+
+
+
This project is live on web
+
+ >
+ )}
+
+
+
+
Views
+
(
+ 0
+ ? viewOptions
+ .filter((v) => value.includes(v.key))
+ .map((v) => v.label)
+ .join(", ")
+ : ``
+ }
+ placeholder="Select views"
+ >
+ <>
+ {viewOptions.map((option) => (
+ {
+ const _views =
+ value.length > 0
+ ? value.includes(option.key)
+ ? value.filter((_o: string) => _o !== option.key)
+ : [...value, option.key]
+ : [option.key];
+
+ if (_views.length === 0) return;
+
+ onChange(_views);
+ checkIfUpdateIsRequired();
+ }}
+ >
+
{option.label}
+
+ {value.length > 0 && value.includes(option.key) && (
+
+ )}
+
+
+ ))}
+ >
+
+ )}
+ />
+
+
+
Allow comments
+
(
+ {
+ onChange(val);
+ checkIfUpdateIsRequired();
+ }}
+ size="sm"
+ />
+ )}
+ />
+
+
+
Allow reactions
+
(
+ {
+ onChange(val);
+ checkIfUpdateIsRequired();
+ }}
+ size="sm"
+ />
+ )}
+ />
+
+
+
Allow voting
+
(
+ {
+ onChange(val);
+ checkIfUpdateIsRequired();
+ }}
+ size="sm"
+ />
+ )}
+ />
+
+
+ {/*
+
Allow issue proposals
+
(
+
+ )}
+ />
+ */}
+
+
+ )}
+
+ {/* modal handlers */}
+
+
+
+
Anyone with the link can access
+
+ {!projectPublish.fetchSettingsLoader && (
+
+
Cancel
+ {watch("id") ? (
+ <>
+ {isUpdateRequired && (
+
+ {isSubmitting ? "Updating..." : "Update settings"}
+
+ )}
+ >
+ ) : (
+
+ {isSubmitting ? "Publishing..." : "Publish"}
+
+ )}
+
+ )}
+
+
+
+
+
+
+
+
+ );
+});
diff --git a/apps/app/components/project/publish-project/popover.tsx b/web/components/project/publish-project/popover.tsx
similarity index 55%
rename from apps/app/components/project/publish-project/popover.tsx
rename to web/components/project/publish-project/popover.tsx
index 623675b9f..5ab2d6432 100644
--- a/apps/app/components/project/publish-project/popover.tsx
+++ b/web/components/project/publish-project/popover.tsx
@@ -1,6 +1,9 @@
import React, { Fragment } from "react";
+
// headless ui
import { Popover, Transition } from "@headlessui/react";
+// icons
+import { Icon } from "components/ui";
export const CustomPopover = ({
children,
@@ -16,18 +19,14 @@ export const CustomPopover = ({
{({ open }) => (
<>
-
- {label ? label : placeholder ? placeholder : "Select"}
-
-
+
{label ?? placeholder}
+
{!open ? (
- expand_more
+
) : (
- expand_less
+
)}
@@ -41,8 +40,8 @@ export const CustomPopover = ({
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
-
-
+
+
{children}
diff --git a/apps/app/components/project/send-project-invitation-modal.tsx b/web/components/project/send-project-invitation-modal.tsx
similarity index 95%
rename from apps/app/components/project/send-project-invitation-modal.tsx
rename to web/components/project/send-project-invitation-modal.tsx
index d37ad627f..b8f383f05 100644
--- a/apps/app/components/project/send-project-invitation-modal.tsx
+++ b/web/components/project/send-project-invitation-modal.tsx
@@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import { useRouter } from "next/router";
-import useSWR, { mutate } from "swr";
+import useSWR from "swr";
import { useForm, Controller, useFieldArray } from "react-hook-form";
@@ -28,7 +28,7 @@ import useToast from "hooks/use-toast";
// types
import { ICurrentUserResponse } from "types";
// fetch-keys
-import { PROJECT_MEMBERS, WORKSPACE_MEMBERS } from "constants/fetch-keys";
+import { WORKSPACE_MEMBERS } from "constants/fetch-keys";
// constants
import { ROLE } from "constants/workspace";
@@ -37,6 +37,7 @@ type Props = {
setIsOpen: React.Dispatch
>;
members: any[];
user: ICurrentUserResponse | undefined;
+ onSuccess: () => void;
};
type member = {
@@ -57,7 +58,9 @@ const defaultValues: FormValues = {
],
};
-const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, members, user }) => {
+const SendProjectInvitationModal: React.FC = (props) => {
+ const { isOpen, setIsOpen, members, user, onSuccess } = props;
+
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@@ -82,7 +85,8 @@ const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, member
});
const uninvitedPeople = people?.filter((person) => {
- const isInvited = members?.find((member) => member.display_name === person.member.display_name);
+ const isInvited = members?.find((member) => member.memberId === person.member.id);
+
return !isInvited;
});
@@ -98,13 +102,13 @@ const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, member
type: "success",
message: "Member added successfully",
});
+ onSuccess();
})
.catch((error) => {
console.log(error);
})
.finally(() => {
reset(defaultValues);
- mutate(PROJECT_MEMBERS(projectId.toString()));
});
};
@@ -140,7 +144,7 @@ const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, member
content: (
- {person.member.display_name}
+ {person.member.display_name} ({person.member.first_name + " " + person.member.last_name})
),
}));
@@ -215,7 +219,7 @@ const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, member
}
) : (
- Select co-worker’s email
+ Select co-worker
)}
diff --git a/apps/app/components/project/settings-header.tsx b/web/components/project/settings-header.tsx
similarity index 100%
rename from apps/app/components/project/settings-header.tsx
rename to web/components/project/settings-header.tsx
diff --git a/apps/app/components/project/settings/single-label.tsx b/web/components/project/settings/single-label.tsx
similarity index 100%
rename from apps/app/components/project/settings/single-label.tsx
rename to web/components/project/settings/single-label.tsx
diff --git a/apps/app/components/project/sidebar-list.tsx b/web/components/project/sidebar-list.tsx
similarity index 93%
rename from apps/app/components/project/sidebar-list.tsx
rename to web/components/project/sidebar-list.tsx
index 9e37426de..a46a97f04 100644
--- a/apps/app/components/project/sidebar-list.tsx
+++ b/web/components/project/sidebar-list.tsx
@@ -31,9 +31,11 @@ import { useMobxStore } from "lib/mobx/store-provider";
export const ProjectSidebarList: FC = () => {
const store: any = useMobxStore();
+ const [isFavoriteProjectCreate, setIsFavoriteProjectCreate] = useState(false);
const [isProjectModalOpen, setIsProjectModalOpen] = useState(false);
const [deleteProjectModal, setDeleteProjectModal] = useState(false);
const [projectToDelete, setProjectToDelete] = useState(null);
+ const [projectToLeaveId, setProjectToLeaveId] = useState(null);
// router
const [isScrolled, setIsScrolled] = useState(false);
@@ -151,7 +153,7 @@ export const ProjectSidebarList: FC = () => {
{
setIsProjectModalOpen(true)}
+ onClick={() => {
+ setIsFavoriteProjectCreate(true);
+ setIsProjectModalOpen(true);
+ }}
>
@@ -213,6 +218,7 @@ export const ProjectSidebarList: FC = () => {
snapshot={snapshot}
handleDeleteProject={() => handleDeleteProject(project)}
handleCopyText={() => handleCopyText(project.id)}
+ handleProjectLeave={() => setProjectToLeaveId(project.id)}
shortContextMenu
/>
@@ -252,7 +258,10 @@ export const ProjectSidebarList: FC = () => {
setIsProjectModalOpen(true)}
+ onClick={() => {
+ setIsFavoriteProjectCreate(false);
+ setIsProjectModalOpen(true);
+ }}
>
@@ -278,6 +287,7 @@ export const ProjectSidebarList: FC = () => {
provided={provided}
snapshot={snapshot}
handleDeleteProject={() => handleDeleteProject(project)}
+ handleProjectLeave={() => setProjectToLeaveId(project.id)}
handleCopyText={() => handleCopyText(project.id)}
/>
diff --git a/apps/app/components/project/single-integration-card.tsx b/web/components/project/single-integration-card.tsx
similarity index 100%
rename from apps/app/components/project/single-integration-card.tsx
rename to web/components/project/single-integration-card.tsx
diff --git a/apps/app/components/project/single-project-card.tsx b/web/components/project/single-project-card.tsx
similarity index 100%
rename from apps/app/components/project/single-project-card.tsx
rename to web/components/project/single-project-card.tsx
diff --git a/web/components/project/single-sidebar-project.tsx b/web/components/project/single-sidebar-project.tsx
new file mode 100644
index 000000000..ebc8bc974
--- /dev/null
+++ b/web/components/project/single-sidebar-project.tsx
@@ -0,0 +1,373 @@
+import Link from "next/link";
+import { useRouter } from "next/router";
+
+import { mutate } from "swr";
+
+// react-beautiful-dnd
+import { DraggableProvided, DraggableStateSnapshot } from "react-beautiful-dnd";
+// headless ui
+import { Disclosure, Transition } from "@headlessui/react";
+// services
+import projectService from "services/project.service";
+// hooks
+import useToast from "hooks/use-toast";
+// ui
+import { CustomMenu, Icon, Tooltip } from "components/ui";
+// icons
+import { EllipsisVerticalIcon, LinkIcon, StarIcon, TrashIcon } from "@heroicons/react/24/outline";
+import {
+ ArchiveOutlined,
+ ArticleOutlined,
+ ContrastOutlined,
+ DatasetOutlined,
+ ExpandMoreOutlined,
+ FilterNoneOutlined,
+ PhotoFilterOutlined,
+ SettingsOutlined,
+} from "@mui/icons-material";
+// helpers
+import { renderEmoji } from "helpers/emoji.helper";
+// types
+import { IProject } from "types";
+// fetch-keys
+import { PROJECTS_LIST } from "constants/fetch-keys";
+// mobx react lite
+import { observer } from "mobx-react-lite";
+// mobx store
+import { useMobxStore } from "lib/mobx/store-provider";
+import { RootStore } from "store/root";
+
+type Props = {
+ project: IProject;
+ sidebarCollapse: boolean;
+ provided?: DraggableProvided;
+ snapshot?: DraggableStateSnapshot;
+ handleDeleteProject: () => void;
+ handleCopyText: () => void;
+ handleProjectLeave: () => void;
+ shortContextMenu?: boolean;
+};
+
+const navigation = (workspaceSlug: string, projectId: string) => [
+ {
+ name: "Issues",
+ href: `/${workspaceSlug}/projects/${projectId}/issues`,
+ Icon: FilterNoneOutlined,
+ },
+ {
+ name: "Cycles",
+ href: `/${workspaceSlug}/projects/${projectId}/cycles`,
+ Icon: ContrastOutlined,
+ },
+ {
+ name: "Modules",
+ href: `/${workspaceSlug}/projects/${projectId}/modules`,
+ Icon: DatasetOutlined,
+ },
+ {
+ name: "Views",
+ href: `/${workspaceSlug}/projects/${projectId}/views`,
+ Icon: PhotoFilterOutlined,
+ },
+ {
+ name: "Pages",
+ href: `/${workspaceSlug}/projects/${projectId}/pages`,
+ Icon: ArticleOutlined,
+ },
+ {
+ name: "Settings",
+ href: `/${workspaceSlug}/projects/${projectId}/settings`,
+ Icon: SettingsOutlined,
+ },
+];
+
+export const SingleSidebarProject: React.FC = observer((props) => {
+ const {
+ project,
+ sidebarCollapse,
+ provided,
+ snapshot,
+ handleDeleteProject,
+ handleCopyText,
+ handleProjectLeave,
+ shortContextMenu = false,
+ } = props;
+
+ const store: RootStore = useMobxStore();
+ const { projectPublish, project: projectStore } = store;
+
+ const router = useRouter();
+ const { workspaceSlug, projectId } = router.query;
+
+ const { setToastAlert } = useToast();
+
+ const isAdmin = project.member_role === 20;
+
+ const isViewerOrGuest = project.member_role === 10 || project.member_role === 5;
+
+ const handleAddToFavorites = () => {
+ if (!workspaceSlug) return;
+
+ mutate(
+ PROJECTS_LIST(workspaceSlug as string, { is_favorite: "all" }),
+ (prevData) =>
+ (prevData ?? []).map((p) => (p.id === project.id ? { ...p, is_favorite: true } : p)),
+ false
+ );
+
+ projectService
+ .addProjectToFavorites(workspaceSlug as string, {
+ project: project.id,
+ })
+ .catch(() =>
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Couldn't remove the project from favorites. Please try again.",
+ })
+ );
+ };
+
+ const handleRemoveFromFavorites = () => {
+ if (!workspaceSlug) return;
+
+ mutate(
+ PROJECTS_LIST(workspaceSlug as string, { is_favorite: "all" }),
+ (prevData) =>
+ (prevData ?? []).map((p) => (p.id === project.id ? { ...p, is_favorite: false } : p)),
+ false
+ );
+
+ projectService.removeProjectFromFavorites(workspaceSlug as string, project.id).catch(() =>
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Couldn't remove the project from favorites. Please try again.",
+ })
+ );
+ };
+
+ return (
+
+ {({ open }) => (
+ <>
+
+ {provided && (
+
+
+
+
+
+
+ )}
+
+
+
+ {project.emoji ? (
+
+ {renderEmoji(project.emoji)}
+
+ ) : project.icon_prop ? (
+
+ {renderEmoji(project.icon_prop)}
+
+ ) : (
+
+ {project?.name.charAt(0)}
+
+ )}
+
+ {!sidebarCollapse && (
+
+ {project.name}
+
+ )}
+
+ {!sidebarCollapse && (
+
+ )}
+
+
+
+ {!sidebarCollapse && (
+
+ {!shortContextMenu && isAdmin && (
+
+
+
+ Delete project
+
+
+ )}
+ {!project.is_favorite && (
+
+
+
+ Add to favorites
+
+
+ )}
+ {project.is_favorite && (
+
+
+
+ Remove from favorites
+
+
+ )}
+
+
+
+ Copy project link
+
+
+
+ {/* publish project settings */}
+ {isAdmin && (
+ projectPublish.handleProjectModal(project?.id)}
+ >
+
+
+
+
+
{project.is_deployed ? "Publish settings" : "Publish"}
+
+
+ )}
+
+ {project.archive_in > 0 && (
+
+ router.push(`/${workspaceSlug}/projects/${project?.id}/archived-issues/`)
+ }
+ >
+
+
+ )}
+ router.push(`/${workspaceSlug}/projects/${project?.id}/settings`)}
+ >
+
+
+ Settings
+
+
+
+ {/* leave project */}
+ {isViewerOrGuest && (
+
+ projectStore.handleProjectLeaveModal({
+ id: project?.id,
+ name: project?.name,
+ workspaceSlug: workspaceSlug as string,
+ })
+ }
+ >
+
+
+ Leave Project
+
+
+ )}
+
+ )}
+
+
+
+
+ {navigation(workspaceSlug as string, project?.id).map((item) => {
+ if (
+ (item.name === "Cycles" && !project.cycle_view) ||
+ (item.name === "Modules" && !project.module_view) ||
+ (item.name === "Views" && !project.issue_views_view) ||
+ (item.name === "Pages" && !project.page_view)
+ )
+ return;
+
+ return (
+
+
+
+
+
+ {!sidebarCollapse && item.name}
+
+
+
+
+ );
+ })}
+
+
+ >
+ )}
+
+ );
+});
diff --git a/apps/app/components/search-listbox/index.tsx b/web/components/search-listbox/index.tsx
similarity index 100%
rename from apps/app/components/search-listbox/index.tsx
rename to web/components/search-listbox/index.tsx
diff --git a/apps/app/components/search-listbox/types.d.ts b/web/components/search-listbox/types.d.ts
similarity index 100%
rename from apps/app/components/search-listbox/types.d.ts
rename to web/components/search-listbox/types.d.ts
diff --git a/apps/app/components/states/create-state-modal.tsx b/web/components/states/create-state-modal.tsx
similarity index 100%
rename from apps/app/components/states/create-state-modal.tsx
rename to web/components/states/create-state-modal.tsx
diff --git a/apps/app/components/states/create-update-state-inline.tsx b/web/components/states/create-update-state-inline.tsx
similarity index 100%
rename from apps/app/components/states/create-update-state-inline.tsx
rename to web/components/states/create-update-state-inline.tsx
diff --git a/apps/app/components/states/delete-state-modal.tsx b/web/components/states/delete-state-modal.tsx
similarity index 100%
rename from apps/app/components/states/delete-state-modal.tsx
rename to web/components/states/delete-state-modal.tsx
diff --git a/apps/app/components/states/index.ts b/web/components/states/index.ts
similarity index 100%
rename from apps/app/components/states/index.ts
rename to web/components/states/index.ts
diff --git a/apps/app/components/states/single-state.tsx b/web/components/states/single-state.tsx
similarity index 100%
rename from apps/app/components/states/single-state.tsx
rename to web/components/states/single-state.tsx
diff --git a/web/components/tiptap/bubble-menu/index.tsx b/web/components/tiptap/bubble-menu/index.tsx
new file mode 100644
index 000000000..217317ea1
--- /dev/null
+++ b/web/components/tiptap/bubble-menu/index.tsx
@@ -0,0 +1,121 @@
+import { BubbleMenu, BubbleMenuProps } from "@tiptap/react";
+import { FC, useState } from "react";
+import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react";
+
+import { NodeSelector } from "./node-selector";
+import { LinkSelector } from "./link-selector";
+import { cn } from "../utils";
+
+export interface BubbleMenuItem {
+ name: string;
+ isActive: () => boolean;
+ command: () => void;
+ icon: typeof BoldIcon;
+}
+
+type EditorBubbleMenuProps = Omit;
+
+export const EditorBubbleMenu: FC = (props: any) => {
+ const items: BubbleMenuItem[] = [
+ {
+ name: "bold",
+ isActive: () => props.editor?.isActive("bold"),
+ command: () => props.editor?.chain().focus().toggleBold().run(),
+ icon: BoldIcon,
+ },
+ {
+ name: "italic",
+ isActive: () => props.editor?.isActive("italic"),
+ command: () => props.editor?.chain().focus().toggleItalic().run(),
+ icon: ItalicIcon,
+ },
+ {
+ name: "underline",
+ isActive: () => props.editor?.isActive("underline"),
+ command: () => props.editor?.chain().focus().toggleUnderline().run(),
+ icon: UnderlineIcon,
+ },
+ {
+ name: "strike",
+ isActive: () => props.editor?.isActive("strike"),
+ command: () => props.editor?.chain().focus().toggleStrike().run(),
+ icon: StrikethroughIcon,
+ },
+ {
+ name: "code",
+ isActive: () => props.editor?.isActive("code"),
+ command: () => props.editor?.chain().focus().toggleCode().run(),
+ icon: CodeIcon,
+ },
+ ];
+
+ const bubbleMenuProps: EditorBubbleMenuProps = {
+ ...props,
+ shouldShow: ({ editor }) => {
+ if (!editor.isEditable) {
+ return false;
+ }
+ if (editor.isActive("image")) {
+ return false;
+ }
+ return editor.view.state.selection.content().size > 0;
+ },
+ tippyOptions: {
+ moveTransition: "transform 0.15s ease-out",
+ onHidden: () => {
+ setIsNodeSelectorOpen(false);
+ setIsLinkSelectorOpen(false);
+ },
+ },
+ };
+
+ const [isNodeSelectorOpen, setIsNodeSelectorOpen] = useState(false);
+ const [isLinkSelectorOpen, setIsLinkSelectorOpen] = useState(false);
+
+ return (
+
+ {!props.editor.isActive("table") && (
+ {
+ setIsNodeSelectorOpen(!isNodeSelectorOpen);
+ setIsLinkSelectorOpen(false);
+ }}
+ />
+ )}
+ {
+ setIsLinkSelectorOpen(!isLinkSelectorOpen);
+ setIsNodeSelectorOpen(false);
+ }}
+ />
+
+ {items.map((item, index) => (
+
+
+
+ ))}
+
+
+ );
+};
diff --git a/web/components/tiptap/bubble-menu/link-selector.tsx b/web/components/tiptap/bubble-menu/link-selector.tsx
new file mode 100644
index 000000000..559521db6
--- /dev/null
+++ b/web/components/tiptap/bubble-menu/link-selector.tsx
@@ -0,0 +1,92 @@
+import { Editor } from "@tiptap/core";
+import { Check, Trash } from "lucide-react";
+import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react";
+import { cn } from "../utils";
+import isValidHttpUrl from "./utils/link-validator";
+interface LinkSelectorProps {
+ editor: Editor;
+ isOpen: boolean;
+ setIsOpen: Dispatch>;
+}
+
+export const LinkSelector: FC = ({ editor, isOpen, setIsOpen }) => {
+ const inputRef = useRef(null);
+
+ const onLinkSubmit = useCallback(() => {
+ const input = inputRef.current;
+ const url = input?.value;
+ if (url && isValidHttpUrl(url)) {
+ editor.chain().focus().setLink({ href: url }).run();
+ setIsOpen(false);
+ }
+ }, [editor, inputRef, setIsOpen]);
+
+ useEffect(() => {
+ inputRef.current && inputRef.current?.focus();
+ });
+
+ return (
+
+
{
+ setIsOpen(!isOpen);
+ }}
+ >
+ ↗
+
+ Link
+
+
+ {isOpen && (
+
{
+ if (e.key === "Enter") {
+ e.preventDefault();
+ onLinkSubmit();
+ }
+ }}
+ >
+
+ {editor.getAttributes("link").href ? (
+ {
+ editor.chain().focus().unsetLink().run();
+ setIsOpen(false);
+ }}
+ >
+
+
+ ) : (
+ {
+ onLinkSubmit();
+ }}
+ >
+
+
+ )}
+
+ )}
+
+ );
+};
diff --git a/apps/app/components/tiptap/bubble-menu/node-selector.tsx b/web/components/tiptap/bubble-menu/node-selector.tsx
similarity index 98%
rename from apps/app/components/tiptap/bubble-menu/node-selector.tsx
rename to web/components/tiptap/bubble-menu/node-selector.tsx
index f6f1f18dc..34d40ec06 100644
--- a/apps/app/components/tiptap/bubble-menu/node-selector.tsx
+++ b/web/components/tiptap/bubble-menu/node-selector.tsx
@@ -13,7 +13,7 @@ import {
} from "lucide-react";
import { Dispatch, FC, SetStateAction } from "react";
-import { BubbleMenuItem } from "../bubble-menu";
+import { BubbleMenuItem } from ".";
import { cn } from "../utils";
interface NodeSelectorProps {
diff --git a/web/components/tiptap/bubble-menu/utils/link-validator.tsx b/web/components/tiptap/bubble-menu/utils/link-validator.tsx
new file mode 100644
index 000000000..9af366c02
--- /dev/null
+++ b/web/components/tiptap/bubble-menu/utils/link-validator.tsx
@@ -0,0 +1,11 @@
+export default function isValidHttpUrl(string: string): boolean {
+ let url;
+
+ try {
+ url = new URL(string);
+ } catch (_) {
+ return false;
+ }
+
+ return url.protocol === "http:" || url.protocol === "https:";
+}
diff --git a/web/components/tiptap/extensions/image-resize.tsx b/web/components/tiptap/extensions/image-resize.tsx
new file mode 100644
index 000000000..448b8811c
--- /dev/null
+++ b/web/components/tiptap/extensions/image-resize.tsx
@@ -0,0 +1,44 @@
+import { Editor } from "@tiptap/react";
+import Moveable from "react-moveable";
+
+export const ImageResizer = ({ editor }: { editor: Editor }) => {
+ const updateMediaSize = () => {
+ const imageInfo = document.querySelector(".ProseMirror-selectednode") as HTMLImageElement;
+ if (imageInfo) {
+ const selection = editor.state.selection;
+ editor.commands.setImage({
+ src: imageInfo.src,
+ width: Number(imageInfo.style.width.replace("px", "")),
+ height: Number(imageInfo.style.height.replace("px", "")),
+ } as any);
+ editor.commands.setNodeSelection(selection.from);
+ }
+ };
+
+ return (
+ <>
+ {
+ delta[0] && (target!.style.width = `${width}px`);
+ delta[1] && (target!.style.height = `${height}px`);
+ }}
+ onResizeEnd={() => {
+ updateMediaSize();
+ }}
+ scalable={true}
+ renderDirections={["w", "e"]}
+ onScale={({ target, transform }: any) => {
+ target!.style.transform = transform;
+ }}
+ />
+ >
+ );
+};
diff --git a/web/components/tiptap/extensions/index.tsx b/web/components/tiptap/extensions/index.tsx
new file mode 100644
index 000000000..ea5d421a6
--- /dev/null
+++ b/web/components/tiptap/extensions/index.tsx
@@ -0,0 +1,153 @@
+import StarterKit from "@tiptap/starter-kit";
+import HorizontalRule from "@tiptap/extension-horizontal-rule";
+import TiptapLink from "@tiptap/extension-link";
+import Placeholder from "@tiptap/extension-placeholder";
+import TiptapUnderline from "@tiptap/extension-underline";
+import TextStyle from "@tiptap/extension-text-style";
+import { Color } from "@tiptap/extension-color";
+import TaskItem from "@tiptap/extension-task-item";
+import TaskList from "@tiptap/extension-task-list";
+import { Markdown } from "tiptap-markdown";
+import Highlight from "@tiptap/extension-highlight";
+import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
+import { lowlight } from "lowlight/lib/core";
+import SlashCommand from "../slash-command";
+import { InputRule } from "@tiptap/core";
+import Gapcursor from "@tiptap/extension-gapcursor";
+
+import ts from "highlight.js/lib/languages/typescript";
+
+import "highlight.js/styles/github-dark.css";
+import UniqueID from "@tiptap-pro/extension-unique-id";
+import UpdatedImage from "./updated-image";
+import isValidHttpUrl from "../bubble-menu/utils/link-validator";
+import { CustomTableCell } from "./table/table-cell";
+import { Table } from "./table/table";
+import { TableHeader } from "./table/table-header";
+import { TableRow } from "@tiptap/extension-table-row";
+
+lowlight.registerLanguage("ts", ts);
+
+export const TiptapExtensions = (
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+) => [
+ StarterKit.configure({
+ bulletList: {
+ HTMLAttributes: {
+ class: "list-disc list-outside leading-3 -mt-2",
+ },
+ },
+ orderedList: {
+ HTMLAttributes: {
+ class: "list-decimal list-outside leading-3 -mt-2",
+ },
+ },
+ listItem: {
+ HTMLAttributes: {
+ class: "leading-normal -mb-2",
+ },
+ },
+ blockquote: {
+ HTMLAttributes: {
+ class: "border-l-4 border-custom-border-300",
+ },
+ },
+ code: {
+ HTMLAttributes: {
+ class:
+ "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000",
+ spellcheck: "false",
+ },
+ },
+ codeBlock: false,
+ horizontalRule: false,
+ dropcursor: {
+ color: "rgba(var(--color-text-100))",
+ width: 2,
+ },
+ gapcursor: false,
+ }),
+ CodeBlockLowlight.configure({
+ lowlight,
+ }),
+ HorizontalRule.extend({
+ addInputRules() {
+ return [
+ new InputRule({
+ find: /^(?:---|—-|___\s|\*\*\*\s)$/,
+ handler: ({ state, range, commands }) => {
+ commands.splitBlock();
+
+ const attributes = {};
+ const { tr } = state;
+ const start = range.from;
+ const end = range.to;
+ // @ts-ignore
+ tr.replaceWith(start - 1, end, this.type.create(attributes));
+ },
+ }),
+ ];
+ },
+ }).configure({
+ HTMLAttributes: {
+ class: "mb-6 border-t border-custom-border-300",
+ },
+ }),
+ Gapcursor,
+ TiptapLink.configure({
+ protocols: ["http", "https"],
+ validate: (url) => isValidHttpUrl(url),
+ HTMLAttributes: {
+ class:
+ "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
+ },
+ }),
+ UpdatedImage.configure({
+ HTMLAttributes: {
+ class: "rounded-lg border border-custom-border-300",
+ },
+ }),
+ Placeholder.configure({
+ placeholder: ({ node }) => {
+ if (node.type.name === "heading") {
+ return `Heading ${node.attrs.level}`;
+ }
+ if (node.type.name === "image" || node.type.name === "table") {
+ return "";
+ }
+
+ return "Press '/' for commands...";
+ },
+ includeChildren: true,
+ }),
+ UniqueID.configure({
+ types: ["image"],
+ }),
+ SlashCommand(workspaceSlug, setIsSubmitting),
+ TiptapUnderline,
+ TextStyle,
+ Color,
+ Highlight.configure({
+ multicolor: true,
+ }),
+ TaskList.configure({
+ HTMLAttributes: {
+ class: "not-prose pl-2",
+ },
+ }),
+ TaskItem.configure({
+ HTMLAttributes: {
+ class: "flex items-start my-4",
+ },
+ nested: true,
+ }),
+ Markdown.configure({
+ html: true,
+ transformCopiedText: true,
+ }),
+ Table,
+ TableHeader,
+ CustomTableCell,
+ TableRow,
+];
diff --git a/web/components/tiptap/extensions/table/table-cell.ts b/web/components/tiptap/extensions/table/table-cell.ts
new file mode 100644
index 000000000..643cb8c64
--- /dev/null
+++ b/web/components/tiptap/extensions/table/table-cell.ts
@@ -0,0 +1,32 @@
+import { TableCell } from "@tiptap/extension-table-cell";
+
+export const CustomTableCell = TableCell.extend({
+ addAttributes() {
+ return {
+ ...this.parent?.(),
+ isHeader: {
+ default: false,
+ parseHTML: (element) => {
+ isHeader: element.tagName === "TD";
+ },
+ renderHTML: (attributes) => {
+ tag: attributes.isHeader ? "th" : "td";
+ },
+ },
+ };
+ },
+ renderHTML({ HTMLAttributes }) {
+ if (HTMLAttributes.isHeader) {
+ return [
+ "th",
+ {
+ ...HTMLAttributes,
+ class: `relative ${HTMLAttributes.class}`,
+ },
+ ["span", { class: "absolute top-0 right-0" }],
+ 0,
+ ];
+ }
+ return ["td", HTMLAttributes, 0];
+ },
+});
diff --git a/web/components/tiptap/extensions/table/table-header.ts b/web/components/tiptap/extensions/table/table-header.ts
new file mode 100644
index 000000000..f23aa93ef
--- /dev/null
+++ b/web/components/tiptap/extensions/table/table-header.ts
@@ -0,0 +1,7 @@
+import { TableHeader as BaseTableHeader } from "@tiptap/extension-table-header";
+
+const TableHeader = BaseTableHeader.extend({
+ content: "paragraph",
+});
+
+export { TableHeader };
diff --git a/web/components/tiptap/extensions/table/table.ts b/web/components/tiptap/extensions/table/table.ts
new file mode 100644
index 000000000..9b727bb51
--- /dev/null
+++ b/web/components/tiptap/extensions/table/table.ts
@@ -0,0 +1,9 @@
+import { Table as BaseTable } from "@tiptap/extension-table";
+
+const Table = BaseTable.configure({
+ resizable: true,
+ cellMinWidth: 100,
+ allowTableNodeSelection: true,
+});
+
+export { Table };
diff --git a/web/components/tiptap/extensions/updated-image.tsx b/web/components/tiptap/extensions/updated-image.tsx
new file mode 100644
index 000000000..b62050953
--- /dev/null
+++ b/web/components/tiptap/extensions/updated-image.tsx
@@ -0,0 +1,22 @@
+import Image from "@tiptap/extension-image";
+import TrackImageDeletionPlugin from "../plugins/delete-image";
+import UploadImagesPlugin from "../plugins/upload-image";
+
+const UpdatedImage = Image.extend({
+ addProseMirrorPlugins() {
+ return [UploadImagesPlugin(), TrackImageDeletionPlugin()];
+ },
+ addAttributes() {
+ return {
+ ...this.parent?.(),
+ width: {
+ default: "35%",
+ },
+ height: {
+ default: null,
+ },
+ };
+ },
+});
+
+export default UpdatedImage;
diff --git a/apps/app/components/tiptap/index.tsx b/web/components/tiptap/index.tsx
similarity index 77%
rename from apps/app/components/tiptap/index.tsx
rename to web/components/tiptap/index.tsx
index 418449c08..82304bfb0 100644
--- a/apps/app/components/tiptap/index.tsx
+++ b/web/components/tiptap/index.tsx
@@ -3,10 +3,11 @@ import { useDebouncedCallback } from "use-debounce";
import { EditorBubbleMenu } from "./bubble-menu";
import { TiptapExtensions } from "./extensions";
import { TiptapEditorProps } from "./props";
-import { useImperativeHandle, useRef } from "react";
+import { useImperativeHandle, useRef, forwardRef } from "react";
import { ImageResizer } from "./extensions/image-resize";
+import { TableMenu } from "./table-menu";
-export interface ITiptapRichTextEditor {
+export interface ITipTapRichTextEditor {
value: string;
noBorder?: boolean;
borderOnFocus?: boolean;
@@ -21,7 +22,7 @@ export interface ITiptapRichTextEditor {
debouncedUpdatesEnabled?: boolean;
}
-const Tiptap = (props: ITiptapRichTextEditor) => {
+const Tiptap = (props: ITipTapRichTextEditor) => {
const {
onChange,
debouncedUpdatesEnabled,
@@ -73,9 +74,10 @@ const Tiptap = (props: ITiptapRichTextEditor) => {
}, 500);
}, 1000);
- const editorClassNames = `relative w-full max-w-screen-lg sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md
- ${noBorder ? "" : "border border-custom-border-200"} ${borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0"
- } ${customClassName}`;
+ const editorClassNames = `relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md
+ ${noBorder ? "" : "border border-custom-border-200"} ${
+ borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0"
+ } ${customClassName}`;
if (!editor) return null;
editorRef.current = editor;
@@ -91,10 +93,17 @@ const Tiptap = (props: ITiptapRichTextEditor) => {
{editor && }
+
{editor?.isActive("image") &&
}
);
};
-export default Tiptap;
+const TipTapEditor = forwardRef((props, ref) => (
+
+));
+
+TipTapEditor.displayName = "TipTapEditor";
+
+export { TipTapEditor };
diff --git a/web/components/tiptap/plugins/delete-image.tsx b/web/components/tiptap/plugins/delete-image.tsx
new file mode 100644
index 000000000..568e4b748
--- /dev/null
+++ b/web/components/tiptap/plugins/delete-image.tsx
@@ -0,0 +1,56 @@
+import { Plugin, PluginKey } from "@tiptap/pm/state";
+import { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import fileService from "services/file.service";
+
+const deleteKey = new PluginKey("delete-image");
+
+const TrackImageDeletionPlugin = () =>
+ new Plugin({
+ key: deleteKey,
+ appendTransaction: (transactions, oldState, newState) => {
+ transactions.forEach((transaction) => {
+ if (!transaction.docChanged) return;
+
+ const removedImages: ProseMirrorNode[] = [];
+
+ oldState.doc.descendants((oldNode, oldPos) => {
+ if (oldNode.type.name !== "image") return;
+
+ if (oldPos < 0 || oldPos > newState.doc.content.size) return;
+ if (!newState.doc.resolve(oldPos).parent) return;
+ const newNode = newState.doc.nodeAt(oldPos);
+
+ // Check if the node has been deleted or replaced
+ if (!newNode || newNode.type.name !== "image") {
+ // Check if the node still exists elsewhere in the document
+ let nodeExists = false;
+ newState.doc.descendants((node) => {
+ if (node.attrs.id === oldNode.attrs.id) {
+ nodeExists = true;
+ }
+ });
+ if (!nodeExists) {
+ removedImages.push(oldNode as ProseMirrorNode);
+ }
+ }
+ });
+
+ removedImages.forEach((node) => {
+ const src = node.attrs.src;
+ onNodeDeleted(src);
+ });
+ });
+
+ return null;
+ },
+ });
+
+export default TrackImageDeletionPlugin;
+
+async function onNodeDeleted(src: string) {
+ const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1);
+ const resStatus = await fileService.deleteImage(assetUrlWithWorkspaceId);
+ if (resStatus === 204) {
+ console.log("Image deleted successfully");
+ }
+}
diff --git a/apps/app/components/tiptap/plugins/upload-image.tsx b/web/components/tiptap/plugins/upload-image.tsx
similarity index 88%
rename from apps/app/components/tiptap/plugins/upload-image.tsx
rename to web/components/tiptap/plugins/upload-image.tsx
index 0657bc82b..499a00455 100644
--- a/apps/app/components/tiptap/plugins/upload-image.tsx
+++ b/web/components/tiptap/plugins/upload-image.tsx
@@ -22,10 +22,7 @@ const UploadImagesPlugin = () =>
const placeholder = document.createElement("div");
placeholder.setAttribute("class", "img-placeholder");
const image = document.createElement("img");
- image.setAttribute(
- "class",
- "opacity-10 rounded-lg border border-custom-border-300",
- );
+ image.setAttribute("class", "opacity-10 rounded-lg border border-custom-border-300");
image.src = src;
placeholder.appendChild(image);
const deco = Decoration.widget(pos + 1, placeholder, {
@@ -57,11 +54,15 @@ function findPlaceholder(state: EditorState, id: {}) {
return found.length ? found[0].from : null;
}
-export async function startImageUpload(file: File, view: EditorView, pos: number, workspaceSlug: string, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void) {
+export async function startImageUpload(
+ file: File,
+ view: EditorView,
+ pos: number,
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+) {
if (!file.type.includes("image/")) {
return;
- } else if (file.size / 1024 / 1024 > 20) {
- return;
}
const id = {};
@@ -85,7 +86,7 @@ export async function startImageUpload(file: File, view: EditorView, pos: number
if (!workspaceSlug) {
return;
}
- setIsSubmitting?.("submitting")
+ setIsSubmitting?.("submitting");
const src = await UploadImageHandler(file, workspaceSlug);
const { schema } = view.state;
pos = findPlaceholder(view.state, id);
diff --git a/web/components/tiptap/props.tsx b/web/components/tiptap/props.tsx
new file mode 100644
index 000000000..8233e3ab4
--- /dev/null
+++ b/web/components/tiptap/props.tsx
@@ -0,0 +1,69 @@
+import { EditorProps } from "@tiptap/pm/view";
+import { startImageUpload } from "./plugins/upload-image";
+import { findTableAncestor } from "./table-menu";
+
+export function TiptapEditorProps(
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+): EditorProps {
+ return {
+ attributes: {
+ class: `prose prose-brand max-w-full prose-headings:font-display font-default focus:outline-none`,
+ },
+ handleDOMEvents: {
+ keydown: (_view, event) => {
+ // prevent default event listeners from firing when slash command is active
+ if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) {
+ const slashCommand = document.querySelector("#slash-command");
+ if (slashCommand) {
+ return true;
+ }
+ }
+ },
+ },
+ handlePaste: (view, event) => {
+ if (typeof window !== "undefined") {
+ const selection: any = window?.getSelection();
+ if (selection.rangeCount !== 0) {
+ const range = selection.getRangeAt(0);
+ if (findTableAncestor(range.startContainer)) {
+ return;
+ }
+ }
+ }
+ if (event.clipboardData && event.clipboardData.files && event.clipboardData.files[0]) {
+ event.preventDefault();
+ const file = event.clipboardData.files[0];
+ const pos = view.state.selection.from;
+ startImageUpload(file, view, pos, workspaceSlug, setIsSubmitting);
+ return true;
+ }
+ return false;
+ },
+ handleDrop: (view, event, _slice, moved) => {
+ if (typeof window !== "undefined") {
+ const selection: any = window?.getSelection();
+ if (selection.rangeCount !== 0) {
+ const range = selection.getRangeAt(0);
+ if (findTableAncestor(range.startContainer)) {
+ return;
+ }
+ }
+ }
+ if (!moved && event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]) {
+ event.preventDefault();
+ const file = event.dataTransfer.files[0];
+ const coordinates = view.posAtCoords({
+ left: event.clientX,
+ top: event.clientY,
+ });
+ // here we deduct 1 from the pos or else the image will create an extra node
+ if (coordinates) {
+ startImageUpload(file, view, coordinates.pos - 1, workspaceSlug, setIsSubmitting);
+ }
+ return true;
+ }
+ return false;
+ },
+ };
+}
diff --git a/web/components/tiptap/slash-command/index.tsx b/web/components/tiptap/slash-command/index.tsx
new file mode 100644
index 000000000..46bf5ea5a
--- /dev/null
+++ b/web/components/tiptap/slash-command/index.tsx
@@ -0,0 +1,365 @@
+import React, { useState, useEffect, useCallback, ReactNode, useRef, useLayoutEffect } from "react";
+import { Editor, Range, Extension } from "@tiptap/core";
+import Suggestion from "@tiptap/suggestion";
+import { ReactRenderer } from "@tiptap/react";
+import tippy from "tippy.js";
+import {
+ Heading1,
+ Heading2,
+ Heading3,
+ List,
+ ListOrdered,
+ Text,
+ TextQuote,
+ Code,
+ MinusSquare,
+ CheckSquare,
+ ImageIcon,
+ Table,
+} from "lucide-react";
+import { startImageUpload } from "../plugins/upload-image";
+import { cn } from "../utils";
+
+interface CommandItemProps {
+ title: string;
+ description: string;
+ icon: ReactNode;
+}
+
+interface CommandProps {
+ editor: Editor;
+ range: Range;
+}
+
+const Command = Extension.create({
+ name: "slash-command",
+ addOptions() {
+ return {
+ suggestion: {
+ char: "/",
+ command: ({ editor, range, props }: { editor: Editor; range: Range; props: any }) => {
+ props.command({ editor, range });
+ },
+ },
+ };
+ },
+ addProseMirrorPlugins() {
+ return [
+ Suggestion({
+ editor: this.editor,
+ allow({ editor }) {
+ return !editor.isActive("table");
+ },
+ ...this.options.suggestion,
+ }),
+ ];
+ },
+});
+
+const getSuggestionItems =
+ (
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+ ) =>
+ ({ query }: { query: string }) =>
+ [
+ {
+ title: "Text",
+ description: "Just start typing with plain text.",
+ searchTerms: ["p", "paragraph"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
+ },
+ },
+ {
+ title: "Heading 1",
+ description: "Big section heading.",
+ searchTerms: ["title", "big", "large"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
+ },
+ },
+ {
+ title: "Heading 2",
+ description: "Medium section heading.",
+ searchTerms: ["subtitle", "medium"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
+ },
+ },
+ {
+ title: "Heading 3",
+ description: "Small section heading.",
+ searchTerms: ["subtitle", "small"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
+ },
+ },
+ {
+ title: "To-do List",
+ description: "Track tasks with a to-do list.",
+ searchTerms: ["todo", "task", "list", "check", "checkbox"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).toggleTaskList().run();
+ },
+ },
+ {
+ title: "Bullet List",
+ description: "Create a simple bullet list.",
+ searchTerms: ["unordered", "point"],
+ icon:
,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).toggleBulletList().run();
+ },
+ },
+ {
+ title: "Divider",
+ description: "Visually divide blocks",
+ searchTerms: ["line", "divider", "horizontal", "rule", "separate"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).setHorizontalRule().run();
+ },
+ },
+ {
+ title: "Table",
+ description: "Create a Table",
+ searchTerms: ["table", "cell", "db", "data", "tabular"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor
+ .chain()
+ .focus()
+ .deleteRange(range)
+ .insertTable({ rows: 3, cols: 3, withHeaderRow: true })
+ .run();
+ },
+ },
+ {
+ title: "Numbered List",
+ description: "Create a list with numbering.",
+ searchTerms: ["ordered"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).toggleOrderedList().run();
+ },
+ },
+ {
+ title: "Quote",
+ description: "Capture a quote.",
+ searchTerms: ["blockquote"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) =>
+ editor
+ .chain()
+ .focus()
+ .deleteRange(range)
+ .toggleNode("paragraph", "paragraph")
+ .toggleBlockquote()
+ .run(),
+ },
+ {
+ title: "Code",
+ description: "Capture a code snippet.",
+ searchTerms: ["codeblock"],
+ icon:
,
+ command: ({ editor, range }: CommandProps) =>
+ editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
+ },
+ {
+ title: "Image",
+ description: "Upload an image from your computer.",
+ searchTerms: ["photo", "picture", "media"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).run();
+ // upload image
+ const input = document.createElement("input");
+ input.type = "file";
+ input.accept = "image/*";
+ input.onchange = async () => {
+ if (input.files?.length) {
+ const file = input.files[0];
+ const pos = editor.view.state.selection.from;
+ startImageUpload(file, editor.view, pos, workspaceSlug, setIsSubmitting);
+ }
+ };
+ input.click();
+ },
+ },
+ ].filter((item) => {
+ if (typeof query === "string" && query.length > 0) {
+ const search = query.toLowerCase();
+ return (
+ item.title.toLowerCase().includes(search) ||
+ item.description.toLowerCase().includes(search) ||
+ (item.searchTerms && item.searchTerms.some((term: string) => term.includes(search)))
+ );
+ }
+ return true;
+ });
+
+export const updateScrollView = (container: HTMLElement, item: HTMLElement) => {
+ const containerHeight = container.offsetHeight;
+ const itemHeight = item ? item.offsetHeight : 0;
+
+ const top = item.offsetTop;
+ const bottom = top + itemHeight;
+
+ if (top < container.scrollTop) {
+ container.scrollTop -= container.scrollTop - top + 5;
+ } else if (bottom > containerHeight + container.scrollTop) {
+ container.scrollTop += bottom - containerHeight - container.scrollTop + 5;
+ }
+};
+
+const CommandList = ({
+ items,
+ command,
+}: {
+ items: CommandItemProps[];
+ command: any;
+ editor: any;
+ range: any;
+}) => {
+ const [selectedIndex, setSelectedIndex] = useState(0);
+
+ const selectItem = useCallback(
+ (index: number) => {
+ const item = items[index];
+ if (item) {
+ command(item);
+ }
+ },
+ [command, items]
+ );
+
+ useEffect(() => {
+ const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"];
+ const onKeyDown = (e: KeyboardEvent) => {
+ if (navigationKeys.includes(e.key)) {
+ e.preventDefault();
+ if (e.key === "ArrowUp") {
+ setSelectedIndex((selectedIndex + items.length - 1) % items.length);
+ return true;
+ }
+ if (e.key === "ArrowDown") {
+ setSelectedIndex((selectedIndex + 1) % items.length);
+ return true;
+ }
+ if (e.key === "Enter") {
+ selectItem(selectedIndex);
+ return true;
+ }
+ return false;
+ }
+ };
+ document.addEventListener("keydown", onKeyDown);
+ return () => {
+ document.removeEventListener("keydown", onKeyDown);
+ };
+ }, [items, selectedIndex, setSelectedIndex, selectItem]);
+
+ useEffect(() => {
+ setSelectedIndex(0);
+ }, [items]);
+
+ const commandListContainer = useRef(null);
+
+ useLayoutEffect(() => {
+ const container = commandListContainer?.current;
+
+ const item = container?.children[selectedIndex] as HTMLElement;
+
+ if (item && container) updateScrollView(container, item);
+ }, [selectedIndex]);
+
+ return items.length > 0 ? (
+
+ {items.map((item: CommandItemProps, index: number) => (
+
selectItem(index)}
+ >
+
+
{item.title}
+
{item.description}
+
+
+ ))}
+
+ ) : null;
+};
+
+const renderItems = () => {
+ let component: ReactRenderer | null = null;
+ let popup: any | null = null;
+
+ return {
+ onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
+ component = new ReactRenderer(CommandList, {
+ props,
+ editor: props.editor,
+ });
+
+ // @ts-ignore
+ popup = tippy("body", {
+ getReferenceClientRect: props.clientRect,
+ appendTo: () => document.querySelector("#tiptap-container"),
+ content: component.element,
+ showOnCreate: true,
+ interactive: true,
+ trigger: "manual",
+ placement: "bottom-start",
+ });
+ },
+ onUpdate: (props: { editor: Editor; clientRect: DOMRect }) => {
+ component?.updateProps(props);
+
+ popup &&
+ popup[0].setProps({
+ getReferenceClientRect: props.clientRect,
+ });
+ },
+ onKeyDown: (props: { event: KeyboardEvent }) => {
+ if (props.event.key === "Escape") {
+ popup?.[0].hide();
+
+ return true;
+ }
+
+ // @ts-ignore
+ return component?.ref?.onKeyDown(props);
+ },
+ onExit: () => {
+ popup?.[0].destroy();
+ component?.destroy();
+ },
+ };
+};
+
+export const SlashCommand = (
+ workspaceSlug: string,
+ setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
+) =>
+ Command.configure({
+ suggestion: {
+ items: getSuggestionItems(workspaceSlug, setIsSubmitting),
+ render: renderItems,
+ },
+ });
+
+export default SlashCommand;
diff --git a/web/components/tiptap/table-menu/InsertBottomTableIcon.tsx b/web/components/tiptap/table-menu/InsertBottomTableIcon.tsx
new file mode 100644
index 000000000..0e42ba648
--- /dev/null
+++ b/web/components/tiptap/table-menu/InsertBottomTableIcon.tsx
@@ -0,0 +1,16 @@
+const InsertBottomTableIcon = (props: any) => (
+
+
+
+);
+
+export default InsertBottomTableIcon;
diff --git a/web/components/tiptap/table-menu/InsertLeftTableIcon.tsx b/web/components/tiptap/table-menu/InsertLeftTableIcon.tsx
new file mode 100644
index 000000000..1fd75fe87
--- /dev/null
+++ b/web/components/tiptap/table-menu/InsertLeftTableIcon.tsx
@@ -0,0 +1,15 @@
+const InsertLeftTableIcon = (props: any) => (
+
+
+
+);
+export default InsertLeftTableIcon;
diff --git a/web/components/tiptap/table-menu/InsertRightTableIcon.tsx b/web/components/tiptap/table-menu/InsertRightTableIcon.tsx
new file mode 100644
index 000000000..1a6570969
--- /dev/null
+++ b/web/components/tiptap/table-menu/InsertRightTableIcon.tsx
@@ -0,0 +1,16 @@
+const InsertRightTableIcon = (props: any) => (
+
+
+
+);
+
+export default InsertRightTableIcon;
diff --git a/web/components/tiptap/table-menu/InsertTopTableIcon.tsx b/web/components/tiptap/table-menu/InsertTopTableIcon.tsx
new file mode 100644
index 000000000..8f04f4f61
--- /dev/null
+++ b/web/components/tiptap/table-menu/InsertTopTableIcon.tsx
@@ -0,0 +1,15 @@
+const InsertTopTableIcon = (props: any) => (
+
+
+
+);
+export default InsertTopTableIcon;
diff --git a/web/components/tiptap/table-menu/index.tsx b/web/components/tiptap/table-menu/index.tsx
new file mode 100644
index 000000000..94f9c0f8d
--- /dev/null
+++ b/web/components/tiptap/table-menu/index.tsx
@@ -0,0 +1,143 @@
+import { useState, useEffect } from "react";
+import { Rows, Columns, ToggleRight } from "lucide-react";
+import { cn } from "../utils";
+import { Tooltip } from "components/ui";
+import InsertLeftTableIcon from "./InsertLeftTableIcon";
+import InsertRightTableIcon from "./InsertRightTableIcon";
+import InsertTopTableIcon from "./InsertTopTableIcon";
+import InsertBottomTableIcon from "./InsertBottomTableIcon";
+
+interface TableMenuItem {
+ command: () => void;
+ icon: any;
+ key: string;
+ name: string;
+}
+
+export const findTableAncestor = (node: Node | null): HTMLTableElement | null => {
+ while (node !== null && node.nodeName !== "TABLE") {
+ node = node.parentNode;
+ }
+ return node as HTMLTableElement;
+};
+
+export const TableMenu = ({ editor }: { editor: any }) => {
+ const [tableLocation, setTableLocation] = useState({ bottom: 0, left: 0 });
+ const isOpen = editor?.isActive("table");
+
+ const items: TableMenuItem[] = [
+ {
+ command: () => editor.chain().focus().addColumnBefore().run(),
+ icon: InsertLeftTableIcon,
+ key: "insert-column-left",
+ name: "Insert 1 column left",
+ },
+ {
+ command: () => editor.chain().focus().addColumnAfter().run(),
+ icon: InsertRightTableIcon,
+ key: "insert-column-right",
+ name: "Insert 1 column right",
+ },
+ {
+ command: () => editor.chain().focus().addRowBefore().run(),
+ icon: InsertTopTableIcon,
+ key: "insert-row-above",
+ name: "Insert 1 row above",
+ },
+ {
+ command: () => editor.chain().focus().addRowAfter().run(),
+ icon: InsertBottomTableIcon,
+ key: "insert-row-below",
+ name: "Insert 1 row below",
+ },
+ {
+ command: () => editor.chain().focus().deleteColumn().run(),
+ icon: Columns,
+ key: "delete-column",
+ name: "Delete column",
+ },
+ {
+ command: () => editor.chain().focus().deleteRow().run(),
+ icon: Rows,
+ key: "delete-row",
+ name: "Delete row",
+ },
+ {
+ command: () => editor.chain().focus().toggleHeaderRow().run(),
+ icon: ToggleRight,
+ key: "toggle-header-row",
+ name: "Toggle header row",
+ },
+ ];
+
+ useEffect(() => {
+ if (!window) return;
+
+ const handleWindowClick = () => {
+ const selection: any = window?.getSelection();
+
+ if (selection.rangeCount !== 0) {
+ const range = selection.getRangeAt(0);
+ const tableNode = findTableAncestor(range.startContainer);
+
+ let parent = tableNode?.parentElement;
+
+ if (tableNode) {
+ const tableRect = tableNode.getBoundingClientRect();
+ const tableCenter = tableRect.left + tableRect.width / 2;
+ const menuWidth = 45;
+ const menuLeft = tableCenter - menuWidth / 2;
+ const tableBottom = tableRect.bottom;
+
+ setTableLocation({ bottom: tableBottom, left: menuLeft });
+
+ while (parent) {
+ if (!parent.classList.contains("disable-scroll"))
+ parent.classList.add("disable-scroll");
+ parent = parent.parentElement;
+ }
+ } else {
+ const scrollDisabledContainers = document.querySelectorAll(".disable-scroll");
+
+ scrollDisabledContainers.forEach((container) => {
+ container.classList.remove("disable-scroll");
+ });
+ }
+ }
+ };
+
+ window.addEventListener("click", handleWindowClick);
+
+ return () => {
+ window.removeEventListener("click", handleWindowClick);
+ };
+ }, [tableLocation, editor]);
+
+ return (
+
+ {items.map((item, index) => (
+
+
+
+
+
+ ))}
+
+ );
+};
diff --git a/web/components/tiptap/utils.ts b/web/components/tiptap/utils.ts
new file mode 100644
index 000000000..a5ef19350
--- /dev/null
+++ b/web/components/tiptap/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/web/components/toast-alert/index.tsx b/web/components/toast-alert/index.tsx
new file mode 100644
index 000000000..5d0c0123c
--- /dev/null
+++ b/web/components/toast-alert/index.tsx
@@ -0,0 +1,67 @@
+import React from "react";
+// hooks
+import {
+ CheckCircleIcon,
+ ExclamationTriangleIcon,
+ InformationCircleIcon,
+ XCircleIcon,
+ XMarkIcon,
+} from "@heroicons/react/24/outline";
+import useToast from "hooks/use-toast";
+// icons
+
+const ToastAlerts = () => {
+ const { alerts, removeAlert } = useToast();
+
+ if (!alerts) return null;
+
+ return (
+
+ {alerts.map((alert) => (
+
+
+ removeAlert(alert.id)}
+ >
+ Dismiss
+
+
+
+
+
+
+ {alert.type === "success" ? (
+
+ ) : alert.type === "error" ? (
+
+ ) : alert.type === "warning" ? (
+
+ ) : (
+
+ )}
+
+
+
{alert.title}
+ {alert.message &&
{alert.message}
}
+
+
+
+
+ ))}
+
+ );
+};
+
+export default ToastAlerts;
diff --git a/apps/app/components/ui/avatar.tsx b/web/components/ui/avatar.tsx
similarity index 100%
rename from apps/app/components/ui/avatar.tsx
rename to web/components/ui/avatar.tsx
diff --git a/apps/app/components/ui/buttons/danger-button.tsx b/web/components/ui/buttons/danger-button.tsx
similarity index 100%
rename from apps/app/components/ui/buttons/danger-button.tsx
rename to web/components/ui/buttons/danger-button.tsx
diff --git a/apps/app/components/ui/buttons/index.ts b/web/components/ui/buttons/index.ts
similarity index 100%
rename from apps/app/components/ui/buttons/index.ts
rename to web/components/ui/buttons/index.ts
diff --git a/apps/app/components/ui/buttons/primary-button.tsx b/web/components/ui/buttons/primary-button.tsx
similarity index 100%
rename from apps/app/components/ui/buttons/primary-button.tsx
rename to web/components/ui/buttons/primary-button.tsx
diff --git a/apps/app/components/ui/buttons/secondary-button.tsx b/web/components/ui/buttons/secondary-button.tsx
similarity index 100%
rename from apps/app/components/ui/buttons/secondary-button.tsx
rename to web/components/ui/buttons/secondary-button.tsx
diff --git a/apps/app/components/ui/buttons/type.d.ts b/web/components/ui/buttons/type.d.ts
similarity index 100%
rename from apps/app/components/ui/buttons/type.d.ts
rename to web/components/ui/buttons/type.d.ts
diff --git a/apps/app/components/ui/circular-progress.tsx b/web/components/ui/circular-progress.tsx
similarity index 100%
rename from apps/app/components/ui/circular-progress.tsx
rename to web/components/ui/circular-progress.tsx
diff --git a/apps/app/components/ui/date.tsx b/web/components/ui/date.tsx
similarity index 100%
rename from apps/app/components/ui/date.tsx
rename to web/components/ui/date.tsx
diff --git a/apps/app/components/ui/datepicker.tsx b/web/components/ui/datepicker.tsx
similarity index 100%
rename from apps/app/components/ui/datepicker.tsx
rename to web/components/ui/datepicker.tsx
diff --git a/apps/app/components/ui/dropdowns/context-menu.tsx b/web/components/ui/dropdowns/context-menu.tsx
similarity index 100%
rename from apps/app/components/ui/dropdowns/context-menu.tsx
rename to web/components/ui/dropdowns/context-menu.tsx
diff --git a/apps/app/components/ui/dropdowns/custom-menu.tsx b/web/components/ui/dropdowns/custom-menu.tsx
similarity index 100%
rename from apps/app/components/ui/dropdowns/custom-menu.tsx
rename to web/components/ui/dropdowns/custom-menu.tsx
diff --git a/apps/app/components/ui/dropdowns/custom-search-select.tsx b/web/components/ui/dropdowns/custom-search-select.tsx
similarity index 100%
rename from apps/app/components/ui/dropdowns/custom-search-select.tsx
rename to web/components/ui/dropdowns/custom-search-select.tsx
diff --git a/apps/app/components/ui/dropdowns/custom-select.tsx b/web/components/ui/dropdowns/custom-select.tsx
similarity index 97%
rename from apps/app/components/ui/dropdowns/custom-select.tsx
rename to web/components/ui/dropdowns/custom-select.tsx
index 4e495a210..ae814dccb 100644
--- a/apps/app/components/ui/dropdowns/custom-select.tsx
+++ b/web/components/ui/dropdowns/custom-select.tsx
@@ -41,7 +41,7 @@ const CustomSelect = ({
>
<>
{customButton ? (
- {customButton}
+ {customButton}
) : (
= ({ data, noTooltip=false }) => {
+export const LinearProgressIndicator: React.FC = ({ data, noTooltip = false }) => {
const total = data.reduce((acc: any, cur: any) => acc + cur.value, 0);
let progress = 0;
@@ -17,12 +17,13 @@ export const LinearProgressIndicator: React.FC = ({ data, noTooltip=false
backgroundColor: item.color,
};
progress += item.value;
- if (noTooltip) return
- else return (
-
-
-
- );
+ if (noTooltip) return
;
+ else
+ return (
+
+
+
+ );
});
return (
diff --git a/web/components/ui/loader.tsx b/web/components/ui/loader.tsx
new file mode 100644
index 000000000..b9d13883a
--- /dev/null
+++ b/web/components/ui/loader.tsx
@@ -0,0 +1,25 @@
+import React from "react";
+
+type Props = {
+ children: React.ReactNode;
+ className?: string;
+};
+
+const Loader = ({ children, className = "" }: Props) => (
+
+ {children}
+
+);
+
+type ItemProps = {
+ height?: string;
+ width?: string;
+};
+
+const Item: React.FC = ({ height = "auto", width = "auto" }) => (
+
+);
+
+Loader.Item = Item;
+
+export { Loader };
diff --git a/apps/app/components/ui/markdown-to-component.tsx b/web/components/ui/markdown-to-component.tsx
similarity index 100%
rename from apps/app/components/ui/markdown-to-component.tsx
rename to web/components/ui/markdown-to-component.tsx
diff --git a/apps/app/components/ui/multi-level-dropdown.tsx b/web/components/ui/multi-level-dropdown.tsx
similarity index 100%
rename from apps/app/components/ui/multi-level-dropdown.tsx
rename to web/components/ui/multi-level-dropdown.tsx
diff --git a/apps/app/components/ui/multi-level-select.tsx b/web/components/ui/multi-level-select.tsx
similarity index 100%
rename from apps/app/components/ui/multi-level-select.tsx
rename to web/components/ui/multi-level-select.tsx
diff --git a/apps/app/components/ui/product-updates-modal.tsx b/web/components/ui/product-updates-modal.tsx
similarity index 100%
rename from apps/app/components/ui/product-updates-modal.tsx
rename to web/components/ui/product-updates-modal.tsx
diff --git a/apps/app/components/ui/profile-empty-state.tsx b/web/components/ui/profile-empty-state.tsx
similarity index 100%
rename from apps/app/components/ui/profile-empty-state.tsx
rename to web/components/ui/profile-empty-state.tsx
diff --git a/apps/app/components/ui/progress-bar.tsx b/web/components/ui/progress-bar.tsx
similarity index 100%
rename from apps/app/components/ui/progress-bar.tsx
rename to web/components/ui/progress-bar.tsx
diff --git a/apps/app/components/ui/range-datepicker.tsx b/web/components/ui/range-datepicker.tsx
similarity index 100%
rename from apps/app/components/ui/range-datepicker.tsx
rename to web/components/ui/range-datepicker.tsx
diff --git a/apps/app/components/ui/spinner.tsx b/web/components/ui/spinner.tsx
similarity index 100%
rename from apps/app/components/ui/spinner.tsx
rename to web/components/ui/spinner.tsx
diff --git a/apps/app/components/ui/text-area/index.tsx b/web/components/ui/text-area/index.tsx
similarity index 100%
rename from apps/app/components/ui/text-area/index.tsx
rename to web/components/ui/text-area/index.tsx
diff --git a/apps/app/components/ui/text-area/types.d.ts b/web/components/ui/text-area/types.d.ts
similarity index 100%
rename from apps/app/components/ui/text-area/types.d.ts
rename to web/components/ui/text-area/types.d.ts
diff --git a/apps/app/components/ui/toggle-switch.tsx b/web/components/ui/toggle-switch.tsx
similarity index 100%
rename from apps/app/components/ui/toggle-switch.tsx
rename to web/components/ui/toggle-switch.tsx
diff --git a/apps/app/components/ui/tooltip.tsx b/web/components/ui/tooltip.tsx
similarity index 100%
rename from apps/app/components/ui/tooltip.tsx
rename to web/components/ui/tooltip.tsx
diff --git a/apps/app/components/views/delete-view-modal.tsx b/web/components/views/delete-view-modal.tsx
similarity index 97%
rename from apps/app/components/views/delete-view-modal.tsx
rename to web/components/views/delete-view-modal.tsx
index 61c627430..c65f7ba29 100644
--- a/apps/app/components/views/delete-view-modal.tsx
+++ b/web/components/views/delete-view-modal.tsx
@@ -46,8 +46,9 @@ export const DeleteViewModal: React.FC = ({ isOpen, data, setIsOpen, user
await viewsService
.deleteView(workspaceSlug as string, projectId as string, data.id, user)
.then(() => {
- mutate(VIEWS_LIST(projectId as string), (views) =>
- views?.filter((view) => view.id !== data.id)
+ mutate(
+ VIEWS_LIST(projectId as string),
+ (views) => views?.filter((view) => view.id !== data.id)
);
handleClose();
diff --git a/apps/app/components/views/form.tsx b/web/components/views/form.tsx
similarity index 96%
rename from apps/app/components/views/form.tsx
rename to web/components/views/form.tsx
index 9191a7b2b..0c57a9542 100644
--- a/apps/app/components/views/form.tsx
+++ b/web/components/views/form.tsx
@@ -94,6 +94,7 @@ export const ViewForm: React.FC = ({
labels: null,
priority: null,
state: null,
+ start_date: null,
target_date: null,
type: null,
});
@@ -155,14 +156,15 @@ export const ViewForm: React.FC = ({
onSelect={(option) => {
const key = option.key as keyof typeof filters;
- if (key === "target_date") {
+ if (key === "start_date" || key === "target_date") {
const valueExists = checkIfArraysHaveSameElements(
- filters?.target_date ?? [],
+ filters?.[key] ?? [],
option.value
);
setValue("query", {
- target_date: valueExists ? null : option.value,
+ ...filters,
+ [key]: valueExists ? null : option.value,
} as IQuery);
} else {
if (!filters?.[key]?.includes(option.value))
diff --git a/apps/app/components/views/gantt-chart.tsx b/web/components/views/gantt-chart.tsx
similarity index 53%
rename from apps/app/components/views/gantt-chart.tsx
rename to web/components/views/gantt-chart.tsx
index 630ffaca0..b25f034cd 100644
--- a/apps/app/components/views/gantt-chart.tsx
+++ b/web/components/views/gantt-chart.tsx
@@ -6,12 +6,10 @@ import { useRouter } from "next/router";
import useGanttChartViewIssues from "hooks/gantt-chart/view-issues-view";
import useUser from "hooks/use-user";
import { updateGanttIssue } from "components/gantt-chart/hooks/block-update";
+import useProjectDetails from "hooks/use-project-details";
// components
-import {
- GanttChartRoot,
- IssueGanttBlock,
- renderIssueBlocksStructure,
-} from "components/gantt-chart";
+import { GanttChartRoot, renderIssueBlocksStructure } from "components/gantt-chart";
+import { IssueGanttBlock, IssueGanttSidebarBlock } from "components/issues";
// types
import { IIssue } from "types";
@@ -22,6 +20,7 @@ export const ViewIssuesGanttChartView: FC = ({}) => {
const { workspaceSlug, projectId, viewId } = router.query;
const { user } = useUser();
+ const { projectDetails } = useProjectDetails();
const { ganttIssues, mutateGanttIssues } = useGanttChartViewIssues(
workspaceSlug as string,
@@ -29,28 +28,24 @@ export const ViewIssuesGanttChartView: FC = ({}) => {
viewId as string
);
- // rendering issues on gantt sidebar
- const GanttSidebarBlockView = ({ data }: any) => (
-
- );
+ const isAllowed = projectDetails?.member_role === 20 || projectDetails?.member_role === 15;
return (
-
+
updateGanttIssue(block, payload, mutateGanttIssues, user, workspaceSlug?.toString())
}
- sidebarBlockRender={(data: any) => }
- blockRender={(data: any) => }
+ SidebarBlockRender={IssueGanttSidebarBlock}
+ BlockRender={IssueGanttBlock}
+ enableBlockLeftResize={isAllowed}
+ enableBlockRightResize={isAllowed}
+ enableBlockMove={isAllowed}
+ enableReorder={isAllowed}
/>
);
diff --git a/apps/app/components/views/index.ts b/web/components/views/index.ts
similarity index 100%
rename from apps/app/components/views/index.ts
rename to web/components/views/index.ts
diff --git a/apps/app/components/views/modal.tsx b/web/components/views/modal.tsx
similarity index 100%
rename from apps/app/components/views/modal.tsx
rename to web/components/views/modal.tsx
diff --git a/apps/app/components/views/select-filters.tsx b/web/components/views/select-filters.tsx
similarity index 74%
rename from apps/app/components/views/select-filters.tsx
rename to web/components/views/select-filters.tsx
index c621241ca..7016afc00 100644
--- a/apps/app/components/views/select-filters.tsx
+++ b/web/components/views/select-filters.tsx
@@ -9,7 +9,7 @@ import stateService from "services/state.service";
import projectService from "services/project.service";
import issuesService from "services/issues.service";
// components
-import { DueDateFilterModal } from "components/core";
+import { DateFilterModal } from "components/core";
// ui
import { Avatar, MultiLevelDropdown } from "components/ui";
// icons
@@ -23,7 +23,7 @@ import { IIssueFilterOptions, IQuery } from "types";
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATES_LIST } from "constants/fetch-keys";
// constants
import { PRIORITIES } from "constants/project";
-import { DUE_DATES } from "constants/due-dates";
+import { DATE_FILTER_OPTIONS } from "constants/filters";
type Props = {
filters: Partial
| IQuery;
@@ -38,7 +38,14 @@ export const SelectFilters: React.FC = ({
direction = "right",
height = "md",
}) => {
- const [isDueDateFilterModalOpen, setIsDueDateFilterModalOpen] = useState(false);
+ const [isDateFilterModalOpen, setIsDateFilterModalOpen] = useState(false);
+ const [dateFilterType, setDateFilterType] = useState<{
+ title: string;
+ type: "start_date" | "target_date";
+ }>({
+ title: "",
+ type: "start_date",
+ });
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@@ -67,10 +74,12 @@ export const SelectFilters: React.FC = ({
return (
<>
- {isDueDateFilterModalOpen && (
- setIsDueDateFilterModalOpen(false)}
+ {isDateFilterModalOpen && (
+ setIsDateFilterModalOpen(false)}
/>
)}
= ({
})),
},
{
- id: "target_date",
- label: "Due date",
- value: DUE_DATES,
+ id: "start_date",
+ label: "Start date",
+ value: DATE_FILTER_OPTIONS,
hasChildren: true,
children: [
- ...DUE_DATES.map((option) => ({
+ ...DATE_FILTER_OPTIONS.map((option) => ({
+ id: option.name,
+ label: option.name,
+ value: {
+ key: "start_date",
+ value: option.value,
+ },
+ selected: checkIfArraysHaveSameElements(filters?.start_date ?? [], option.value),
+ })),
+ {
+ id: "custom",
+ label: "Custom",
+ value: "custom",
+ element: (
+ {
+ setIsDateFilterModalOpen(true);
+ setDateFilterType({
+ title: "Start date",
+ type: "start_date",
+ });
+ }}
+ className="w-full rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
+ >
+ Custom
+
+ ),
+ },
+ ],
+ },
+ {
+ id: "target_date",
+ label: "Due date",
+ value: DATE_FILTER_OPTIONS,
+ hasChildren: true,
+ children: [
+ ...DATE_FILTER_OPTIONS.map((option) => ({
id: option.name,
label: option.name,
value: {
@@ -203,7 +248,13 @@ export const SelectFilters: React.FC = ({
value: "custom",
element: (
setIsDueDateFilterModalOpen(true)}
+ onClick={() => {
+ setIsDateFilterModalOpen(true);
+ setDateFilterType({
+ title: "Due date",
+ type: "target_date",
+ });
+ }}
className="w-full rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
>
Custom
diff --git a/apps/app/components/views/single-view-item.tsx b/web/components/views/single-view-item.tsx
similarity index 100%
rename from apps/app/components/views/single-view-item.tsx
rename to web/components/views/single-view-item.tsx
diff --git a/apps/app/components/workspace/activity-graph.tsx b/web/components/workspace/activity-graph.tsx
similarity index 100%
rename from apps/app/components/workspace/activity-graph.tsx
rename to web/components/workspace/activity-graph.tsx
diff --git a/apps/app/components/workspace/completed-issues-graph.tsx b/web/components/workspace/completed-issues-graph.tsx
similarity index 100%
rename from apps/app/components/workspace/completed-issues-graph.tsx
rename to web/components/workspace/completed-issues-graph.tsx
diff --git a/apps/app/components/workspace/confirm-workspace-member-remove.tsx b/web/components/workspace/confirm-workspace-member-remove.tsx
similarity index 100%
rename from apps/app/components/workspace/confirm-workspace-member-remove.tsx
rename to web/components/workspace/confirm-workspace-member-remove.tsx
diff --git a/apps/app/components/workspace/create-workspace-form.tsx b/web/components/workspace/create-workspace-form.tsx
similarity index 100%
rename from apps/app/components/workspace/create-workspace-form.tsx
rename to web/components/workspace/create-workspace-form.tsx
diff --git a/apps/app/components/workspace/delete-workspace-modal.tsx b/web/components/workspace/delete-workspace-modal.tsx
similarity index 97%
rename from apps/app/components/workspace/delete-workspace-modal.tsx
rename to web/components/workspace/delete-workspace-modal.tsx
index 7ba8c0eff..80cf08cd1 100644
--- a/apps/app/components/workspace/delete-workspace-modal.tsx
+++ b/web/components/workspace/delete-workspace-modal.tsx
@@ -68,8 +68,9 @@ export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose, u
router.push("/");
- mutate(USER_WORKSPACES, (prevData) =>
- prevData?.filter((workspace) => workspace.id !== data.id)
+ mutate(
+ USER_WORKSPACES,
+ (prevData) => prevData?.filter((workspace) => workspace.id !== data.id)
);
setToastAlert({
diff --git a/apps/app/components/workspace/help-section.tsx b/web/components/workspace/help-section.tsx
similarity index 100%
rename from apps/app/components/workspace/help-section.tsx
rename to web/components/workspace/help-section.tsx
diff --git a/apps/app/components/workspace/index.ts b/web/components/workspace/index.ts
similarity index 100%
rename from apps/app/components/workspace/index.ts
rename to web/components/workspace/index.ts
diff --git a/apps/app/components/workspace/issues-list.tsx b/web/components/workspace/issues-list.tsx
similarity index 100%
rename from apps/app/components/workspace/issues-list.tsx
rename to web/components/workspace/issues-list.tsx
diff --git a/apps/app/components/workspace/issues-pie-chart.tsx b/web/components/workspace/issues-pie-chart.tsx
similarity index 100%
rename from apps/app/components/workspace/issues-pie-chart.tsx
rename to web/components/workspace/issues-pie-chart.tsx
diff --git a/web/components/workspace/issues-stats.tsx b/web/components/workspace/issues-stats.tsx
new file mode 100644
index 000000000..2c874d503
--- /dev/null
+++ b/web/components/workspace/issues-stats.tsx
@@ -0,0 +1,93 @@
+// components
+import { ActivityGraph } from "components/workspace";
+// ui
+import { Loader, Tooltip } from "components/ui";
+// icons
+import { InformationCircleIcon } from "@heroicons/react/24/outline";
+// types
+import { IUserWorkspaceDashboard } from "types";
+import { useRouter } from "next/router";
+
+type Props = {
+ data: IUserWorkspaceDashboard | undefined;
+};
+
+export const IssuesStats: React.FC = ({ data }) => {
+ const router = useRouter();
+ const { workspaceSlug } = router.query;
+ return (
+
+
+
+
+
Issues assigned to you
+
+ {data ? (
+ router.push(`/${workspaceSlug}/me/my-issues`)}
+ >
+ {data.assigned_issues_count}
+
+ ) : (
+
+
+
+ )}
+
+
+
+
Pending issues
+
+ {data ? (
+ data.pending_issues_count
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
Completed issues
+
+ {data ? (
+ data.completed_issues_count
+ ) : (
+
+
+
+ )}
+
+
+
+
Issues due by this week
+
+ {data ? (
+ data.issues_due_week_count
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+ Activity Graph
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/app/components/workspace/send-workspace-invitation-modal.tsx b/web/components/workspace/send-workspace-invitation-modal.tsx
similarity index 97%
rename from apps/app/components/workspace/send-workspace-invitation-modal.tsx
rename to web/components/workspace/send-workspace-invitation-modal.tsx
index 5bffa3264..c9d090405 100644
--- a/apps/app/components/workspace/send-workspace-invitation-modal.tsx
+++ b/web/components/workspace/send-workspace-invitation-modal.tsx
@@ -25,6 +25,7 @@ type Props = {
setIsOpen: React.Dispatch>;
workspace_slug: string;
user: ICurrentUserResponse | undefined;
+ onSuccess: () => void;
};
type EmailRole = {
@@ -45,12 +46,8 @@ const defaultValues: FormValues = {
],
};
-const SendWorkspaceInvitationModal: React.FC = ({
- isOpen,
- setIsOpen,
- workspace_slug,
- user,
-}) => {
+const SendWorkspaceInvitationModal: React.FC = (props) => {
+ const { isOpen, setIsOpen, workspace_slug, user, onSuccess } = props;
const {
control,
reset,
@@ -88,6 +85,7 @@ const SendWorkspaceInvitationModal: React.FC = ({
title: "Success!",
message: "Invitations sent successfully.",
});
+ onSuccess();
})
.catch((err) => {
setToastAlert({
diff --git a/apps/app/components/workspace/settings-header.tsx b/web/components/workspace/settings-header.tsx
similarity index 100%
rename from apps/app/components/workspace/settings-header.tsx
rename to web/components/workspace/settings-header.tsx
diff --git a/apps/app/components/workspace/sidebar-dropdown.tsx b/web/components/workspace/sidebar-dropdown.tsx
similarity index 100%
rename from apps/app/components/workspace/sidebar-dropdown.tsx
rename to web/components/workspace/sidebar-dropdown.tsx
diff --git a/apps/app/components/workspace/sidebar-menu.tsx b/web/components/workspace/sidebar-menu.tsx
similarity index 100%
rename from apps/app/components/workspace/sidebar-menu.tsx
rename to web/components/workspace/sidebar-menu.tsx
diff --git a/apps/app/components/workspace/sidebar-quick-action.tsx b/web/components/workspace/sidebar-quick-action.tsx
similarity index 100%
rename from apps/app/components/workspace/sidebar-quick-action.tsx
rename to web/components/workspace/sidebar-quick-action.tsx
diff --git a/apps/app/components/workspace/single-invitation.tsx b/web/components/workspace/single-invitation.tsx
similarity index 100%
rename from apps/app/components/workspace/single-invitation.tsx
rename to web/components/workspace/single-invitation.tsx
diff --git a/apps/app/constants/analytics.ts b/web/constants/analytics.ts
similarity index 100%
rename from apps/app/constants/analytics.ts
rename to web/constants/analytics.ts
diff --git a/apps/app/constants/calendar.ts b/web/constants/calendar.ts
similarity index 100%
rename from apps/app/constants/calendar.ts
rename to web/constants/calendar.ts
diff --git a/apps/app/constants/crisp.tsx b/web/constants/crisp.tsx
similarity index 100%
rename from apps/app/constants/crisp.tsx
rename to web/constants/crisp.tsx
diff --git a/apps/app/constants/fetch-keys.ts b/web/constants/fetch-keys.ts
similarity index 97%
rename from apps/app/constants/fetch-keys.ts
rename to web/constants/fetch-keys.ts
index 97e8dfc90..ac0bc8009 100644
--- a/apps/app/constants/fetch-keys.ts
+++ b/web/constants/fetch-keys.ts
@@ -8,6 +8,7 @@ const paramsToKey = (params: any) => {
assignees,
created_by,
labels,
+ start_date,
target_date,
sub_issue,
start_target_date,
@@ -19,6 +20,7 @@ const paramsToKey = (params: any) => {
let createdByKey = created_by ? created_by.split(",") : [];
let labelsKey = labels ? labels.split(",") : [];
const startTargetDate = start_target_date ? `${start_target_date}`.toUpperCase() : "FALSE";
+ const startDateKey = start_date ?? "";
const targetDateKey = target_date ?? "";
const type = params.type ? params.type.toUpperCase() : "NULL";
const groupBy = params.group_by ? params.group_by.toUpperCase() : "NULL";
@@ -31,7 +33,7 @@ const paramsToKey = (params: any) => {
createdByKey = createdByKey.sort().join("_");
labelsKey = labelsKey.sort().join("_");
- return `${stateKey}_${priorityKey}_${assigneesKey}_${createdByKey}_${type}_${groupBy}_${orderBy}_${labelsKey}_${targetDateKey}_${sub_issue}_${startTargetDate}`;
+ return `${stateKey}_${priorityKey}_${assigneesKey}_${createdByKey}_${type}_${groupBy}_${orderBy}_${labelsKey}_${startDateKey}_${targetDateKey}_${sub_issue}_${startTargetDate}`;
};
const inboxParamsToKey = (params: any) => {
@@ -48,7 +50,16 @@ const inboxParamsToKey = (params: any) => {
};
const myIssuesParamsToKey = (params: any) => {
- const { assignees, created_by, labels, priority, state_group, subscriber, target_date } = params;
+ const {
+ assignees,
+ created_by,
+ labels,
+ priority,
+ state_group,
+ subscriber,
+ start_date,
+ target_date,
+ } = params;
let assigneesKey = assignees ? assignees.split(",") : [];
let createdByKey = created_by ? created_by.split(",") : [];
@@ -56,6 +67,7 @@ const myIssuesParamsToKey = (params: any) => {
let subscriberKey = subscriber ? subscriber.split(",") : [];
let priorityKey = priority ? priority.split(",") : [];
let labelsKey = labels ? labels.split(",") : [];
+ const startDateKey = start_date ?? "";
const targetDateKey = target_date ?? "";
const type = params.type ? params.type.toUpperCase() : "NULL";
const groupBy = params.group_by ? params.group_by.toUpperCase() : "NULL";
@@ -69,7 +81,7 @@ const myIssuesParamsToKey = (params: any) => {
priorityKey = priorityKey.sort().join("_");
labelsKey = labelsKey.sort().join("_");
- return `${assigneesKey}_${createdByKey}_${stateGroupKey}_${subscriberKey}_${priorityKey}_${type}_${groupBy}_${orderBy}_${labelsKey}_${targetDateKey}`;
+ return `${assigneesKey}_${createdByKey}_${stateGroupKey}_${subscriberKey}_${priorityKey}_${type}_${groupBy}_${orderBy}_${labelsKey}_${startDateKey}_${targetDateKey}`;
};
export const CURRENT_USER = "CURRENT_USER";
@@ -273,9 +285,7 @@ export const ANALYTICS = (workspaceSlug: string, params: IAnalyticsParams) =>
params.segment
}_${params.project?.toString()}`;
export const DEFAULT_ANALYTICS = (workspaceSlug: string, params?: Partial) =>
- `DEFAULT_ANALYTICS_${workspaceSlug.toUpperCase()}_${params?.project?.toString()}_${
- params?.cycle
- }_${params?.module}`;
+ `DEFAULT_ANALYTICS_${workspaceSlug.toUpperCase()}_${params?.project?.toString()}_${params?.cycle}_${params?.module}`;
// notifications
export const USER_WORKSPACE_NOTIFICATIONS = (
diff --git a/apps/app/constants/due-dates.ts b/web/constants/filters.ts
similarity index 96%
rename from apps/app/constants/due-dates.ts
rename to web/constants/filters.ts
index 362fd41a5..1172ae47b 100644
--- a/apps/app/constants/due-dates.ts
+++ b/web/constants/filters.ts
@@ -1,7 +1,7 @@
// helper
import { renderDateFormat } from "helpers/date-time.helper";
-export const DUE_DATES = [
+export const DATE_FILTER_OPTIONS = [
{
name: "Last week",
value: [
diff --git a/apps/app/constants/graph.ts b/web/constants/graph.ts
similarity index 100%
rename from apps/app/constants/graph.ts
rename to web/constants/graph.ts
diff --git a/apps/app/constants/inbox.ts b/web/constants/inbox.ts
similarity index 100%
rename from apps/app/constants/inbox.ts
rename to web/constants/inbox.ts
diff --git a/apps/app/constants/issue.ts b/web/constants/issue.ts
similarity index 97%
rename from apps/app/constants/issue.ts
rename to web/constants/issue.ts
index 3665f180c..ff9317070 100644
--- a/apps/app/constants/issue.ts
+++ b/web/constants/issue.ts
@@ -7,6 +7,7 @@ export const GROUP_BY_OPTIONS: Array<{
{ name: "Priority", key: "priority" },
{ name: "Project", key: "project" },
{ name: "Labels", key: "labels" },
+ { name: "Assignees", key: "assignees" },
{ name: "Created by", key: "created_by" },
{ name: "None", key: null },
];
@@ -18,6 +19,7 @@ export const ORDER_BY_OPTIONS: Array<{
{ name: "Manual", key: "sort_order" },
{ name: "Last created", key: "-created_at" },
{ name: "Last updated", key: "-updated_at" },
+ { name: "Start date", key: "start_date" },
{ name: "Priority", key: "priority" },
];
diff --git a/apps/app/constants/label.ts b/web/constants/label.ts
similarity index 100%
rename from apps/app/constants/label.ts
rename to web/constants/label.ts
diff --git a/web/constants/module.ts b/web/constants/module.ts
new file mode 100644
index 000000000..058171328
--- /dev/null
+++ b/web/constants/module.ts
@@ -0,0 +1,15 @@
+// types
+import { TModuleStatus } from "types";
+
+export const MODULE_STATUS: {
+ label: string;
+ value: TModuleStatus;
+ color: string;
+}[] = [
+ { label: "Backlog", value: "backlog", color: "#a3a3a2" },
+ { label: "Planned", value: "planned", color: "#3f76ff" },
+ { label: "In Progress", value: "in-progress", color: "#f39e1f" },
+ { label: "Paused", value: "paused", color: "#525252" },
+ { label: "Completed", value: "completed", color: "#16a34a" },
+ { label: "Cancelled", value: "cancelled", color: "#ef4444" },
+];
diff --git a/apps/app/constants/notification.ts b/web/constants/notification.ts
similarity index 100%
rename from apps/app/constants/notification.ts
rename to web/constants/notification.ts
diff --git a/apps/app/constants/project.ts b/web/constants/project.ts
similarity index 100%
rename from apps/app/constants/project.ts
rename to web/constants/project.ts
diff --git a/apps/app/constants/seo-variables.ts b/web/constants/seo-variables.ts
similarity index 100%
rename from apps/app/constants/seo-variables.ts
rename to web/constants/seo-variables.ts
diff --git a/apps/app/constants/spreadsheet.ts b/web/constants/spreadsheet.ts
similarity index 100%
rename from apps/app/constants/spreadsheet.ts
rename to web/constants/spreadsheet.ts
diff --git a/apps/app/constants/state.ts b/web/constants/state.ts
similarity index 100%
rename from apps/app/constants/state.ts
rename to web/constants/state.ts
diff --git a/apps/app/constants/themes.ts b/web/constants/themes.ts
similarity index 100%
rename from apps/app/constants/themes.ts
rename to web/constants/themes.ts
diff --git a/web/constants/timezones.ts b/web/constants/timezones.ts
new file mode 100644
index 000000000..0ba1df4c0
--- /dev/null
+++ b/web/constants/timezones.ts
@@ -0,0 +1,2386 @@
+export const TIME_ZONES = [
+ {
+ label: "Africa/Abidjan, GMT",
+ value: "Africa/Abidjan",
+ },
+ {
+ label: "Africa/Accra, GMT",
+ value: "Africa/Accra",
+ },
+ {
+ label: "Africa/Addis_Ababa, GMT+03:00",
+ value: "Africa/Addis_Ababa",
+ },
+ {
+ label: "Africa/Algiers, GMT+01:00",
+ value: "Africa/Algiers",
+ },
+ {
+ label: "Africa/Asmara, GMT+03:00",
+ value: "Africa/Asmara",
+ },
+ {
+ label: "Africa/Asmera, GMT+03:00",
+ value: "Africa/Asmera",
+ },
+ {
+ label: "Africa/Bamako, GMT",
+ value: "Africa/Bamako",
+ },
+ {
+ label: "Africa/Bangui, GMT+01:00",
+ value: "Africa/Bangui",
+ },
+ {
+ label: "Africa/Banjul, GMT",
+ value: "Africa/Banjul",
+ },
+ {
+ label: "Africa/Bissau, GMT",
+ value: "Africa/Bissau",
+ },
+ {
+ label: "Africa/Blantyre, GMT+02:00",
+ value: "Africa/Blantyre",
+ },
+ {
+ label: "Africa/Brazzaville, GMT+01:00",
+ value: "Africa/Brazzaville",
+ },
+ {
+ label: "Africa/Bujumbura, GMT+02:00",
+ value: "Africa/Bujumbura",
+ },
+ {
+ label: "Africa/Cairo, GMT+03:00",
+ value: "Africa/Cairo",
+ },
+ {
+ label: "Africa/Casablanca, GMT+01:00",
+ value: "Africa/Casablanca",
+ },
+ {
+ label: "Africa/Ceuta, GMT+02:00",
+ value: "Africa/Ceuta",
+ },
+ {
+ label: "Africa/Conakry, GMT",
+ value: "Africa/Conakry",
+ },
+ {
+ label: "Africa/Dakar, GMT",
+ value: "Africa/Dakar",
+ },
+ {
+ label: "Africa/Dar_es_Salaam, GMT+03:00",
+ value: "Africa/Dar_es_Salaam",
+ },
+ {
+ label: "Africa/Djibouti, GMT+03:00",
+ value: "Africa/Djibouti",
+ },
+ {
+ label: "Africa/Douala, GMT+01:00",
+ value: "Africa/Douala",
+ },
+ {
+ label: "Africa/El_Aaiun, GMT+01:00",
+ value: "Africa/El_Aaiun",
+ },
+ {
+ label: "Africa/Freetown, GMT",
+ value: "Africa/Freetown",
+ },
+ {
+ label: "Africa/Gaborone, GMT+02:00",
+ value: "Africa/Gaborone",
+ },
+ {
+ label: "Africa/Harare, GMT+02:00",
+ value: "Africa/Harare",
+ },
+ {
+ label: "Africa/Johannesburg, GMT+02:00",
+ value: "Africa/Johannesburg",
+ },
+ {
+ label: "Africa/Juba, GMT+02:00",
+ value: "Africa/Juba",
+ },
+ {
+ label: "Africa/Kampala, GMT+03:00",
+ value: "Africa/Kampala",
+ },
+ {
+ label: "Africa/Khartoum, GMT+02:00",
+ value: "Africa/Khartoum",
+ },
+ {
+ label: "Africa/Kigali, GMT+02:00",
+ value: "Africa/Kigali",
+ },
+ {
+ label: "Africa/Kinshasa, GMT+01:00",
+ value: "Africa/Kinshasa",
+ },
+ {
+ label: "Africa/Lagos, GMT+01:00",
+ value: "Africa/Lagos",
+ },
+ {
+ label: "Africa/Libreville, GMT+01:00",
+ value: "Africa/Libreville",
+ },
+ {
+ label: "Africa/Lome, GMT",
+ value: "Africa/Lome",
+ },
+ {
+ label: "Africa/Luanda, GMT+01:00",
+ value: "Africa/Luanda",
+ },
+ {
+ label: "Africa/Lubumbashi, GMT+02:00",
+ value: "Africa/Lubumbashi",
+ },
+ {
+ label: "Africa/Lusaka, GMT+02:00",
+ value: "Africa/Lusaka",
+ },
+ {
+ label: "Africa/Malabo, GMT+01:00",
+ value: "Africa/Malabo",
+ },
+ {
+ label: "Africa/Maputo, GMT+02:00",
+ value: "Africa/Maputo",
+ },
+ {
+ label: "Africa/Maseru, GMT+02:00",
+ value: "Africa/Maseru",
+ },
+ {
+ label: "Africa/Mbabane, GMT+02:00",
+ value: "Africa/Mbabane",
+ },
+ {
+ label: "Africa/Mogadishu, GMT+03:00",
+ value: "Africa/Mogadishu",
+ },
+ {
+ label: "Africa/Monrovia, GMT",
+ value: "Africa/Monrovia",
+ },
+ {
+ label: "Africa/Nairobi, GMT+03:00",
+ value: "Africa/Nairobi",
+ },
+ {
+ label: "Africa/Ndjamena, GMT+01:00",
+ value: "Africa/Ndjamena",
+ },
+ {
+ label: "Africa/Niamey, GMT+01:00",
+ value: "Africa/Niamey",
+ },
+ {
+ label: "Africa/Nouakchott, GMT",
+ value: "Africa/Nouakchott",
+ },
+ {
+ label: "Africa/Ouagadougou, GMT",
+ value: "Africa/Ouagadougou",
+ },
+ {
+ label: "Africa/Porto-Novo, GMT+01:00",
+ value: "Africa/Porto-Novo",
+ },
+ {
+ label: "Africa/Sao_Tome, GMT",
+ value: "Africa/Sao_Tome",
+ },
+ {
+ label: "Africa/Timbuktu, GMT",
+ value: "Africa/Timbuktu",
+ },
+ {
+ label: "Africa/Tripoli, GMT+02:00",
+ value: "Africa/Tripoli",
+ },
+ {
+ label: "Africa/Tunis, GMT+01:00",
+ value: "Africa/Tunis",
+ },
+ {
+ label: "Africa/Windhoek, GMT+02:00",
+ value: "Africa/Windhoek",
+ },
+ {
+ label: "America/Adak, GMT-09:00",
+ value: "America/Adak",
+ },
+ {
+ label: "America/Anchorage, GMT-08:00",
+ value: "America/Anchorage",
+ },
+ {
+ label: "America/Anguilla, GMT-04:00",
+ value: "America/Anguilla",
+ },
+ {
+ label: "America/Antigua, GMT-04:00",
+ value: "America/Antigua",
+ },
+ {
+ label: "America/Araguaina, GMT-03:00",
+ value: "America/Araguaina",
+ },
+ {
+ label: "America/Argentina/Buenos_Aires, GMT-03:00",
+ value: "America/Argentina/Buenos_Aires",
+ },
+ {
+ label: "America/Argentina/Catamarca, GMT-03:00",
+ value: "America/Argentina/Catamarca",
+ },
+ {
+ label: "America/Argentina/ComodRivadavia, GMT-03:00",
+ value: "America/Argentina/ComodRivadavia",
+ },
+ {
+ label: "America/Argentina/Cordoba, GMT-03:00",
+ value: "America/Argentina/Cordoba",
+ },
+ {
+ label: "America/Argentina/Jujuy, GMT-03:00",
+ value: "America/Argentina/Jujuy",
+ },
+ {
+ label: "America/Argentina/La_Rioja, GMT-03:00",
+ value: "America/Argentina/La_Rioja",
+ },
+ {
+ label: "America/Argentina/Mendoza, GMT-03:00",
+ value: "America/Argentina/Mendoza",
+ },
+ {
+ label: "America/Argentina/Rio_Gallegos, GMT-03:00",
+ value: "America/Argentina/Rio_Gallegos",
+ },
+ {
+ label: "America/Argentina/Salta, GMT-03:00",
+ value: "America/Argentina/Salta",
+ },
+ {
+ label: "America/Argentina/San_Juan, GMT-03:00",
+ value: "America/Argentina/San_Juan",
+ },
+ {
+ label: "America/Argentina/San_Luis, GMT-03:00",
+ value: "America/Argentina/San_Luis",
+ },
+ {
+ label: "America/Argentina/Tucuman, GMT-03:00",
+ value: "America/Argentina/Tucuman",
+ },
+ {
+ label: "America/Argentina/Ushuaia, GMT-03:00",
+ value: "America/Argentina/Ushuaia",
+ },
+ {
+ label: "America/Aruba, GMT-04:00",
+ value: "America/Aruba",
+ },
+ {
+ label: "America/Asuncion, GMT-04:00",
+ value: "America/Asuncion",
+ },
+ {
+ label: "America/Atikokan, GMT-05:00",
+ value: "America/Atikokan",
+ },
+ {
+ label: "America/Atka, GMT-09:00",
+ value: "America/Atka",
+ },
+ {
+ label: "America/Bahia, GMT-03:00",
+ value: "America/Bahia",
+ },
+ {
+ label: "America/Bahia_Banderas, GMT-06:00",
+ value: "America/Bahia_Banderas",
+ },
+ {
+ label: "America/Barbados, GMT-04:00",
+ value: "America/Barbados",
+ },
+ {
+ label: "America/Belem, GMT-03:00",
+ value: "America/Belem",
+ },
+ {
+ label: "America/Belize, GMT-06:00",
+ value: "America/Belize",
+ },
+ {
+ label: "America/Blanc-Sablon, GMT-04:00",
+ value: "America/Blanc-Sablon",
+ },
+ {
+ label: "America/Boa_Vista, GMT-04:00",
+ value: "America/Boa_Vista",
+ },
+ {
+ label: "America/Bogota, GMT-05:00",
+ value: "America/Bogota",
+ },
+ {
+ label: "America/Boise, GMT-06:00",
+ value: "America/Boise",
+ },
+ {
+ label: "America/Buenos_Aires, GMT-03:00",
+ value: "America/Buenos_Aires",
+ },
+ {
+ label: "America/Cambridge_Bay, GMT-06:00",
+ value: "America/Cambridge_Bay",
+ },
+ {
+ label: "America/Campo_Grande, GMT-04:00",
+ value: "America/Campo_Grande",
+ },
+ {
+ label: "America/Cancun, GMT-05:00",
+ value: "America/Cancun",
+ },
+ {
+ label: "America/Caracas, GMT-04:00",
+ value: "America/Caracas",
+ },
+ {
+ label: "America/Catamarca, GMT-03:00",
+ value: "America/Catamarca",
+ },
+ {
+ label: "America/Cayenne, GMT-03:00",
+ value: "America/Cayenne",
+ },
+ {
+ label: "America/Cayman, GMT-05:00",
+ value: "America/Cayman",
+ },
+ {
+ label: "America/Chicago, GMT-05:00",
+ value: "America/Chicago",
+ },
+ {
+ label: "America/Chihuahua, GMT-06:00",
+ value: "America/Chihuahua",
+ },
+ {
+ label: "America/Ciudad_Juarez, GMT-06:00",
+ value: "America/Ciudad_Juarez",
+ },
+ {
+ label: "America/Coral_Harbour, GMT-05:00",
+ value: "America/Coral_Harbour",
+ },
+ {
+ label: "America/Cordoba, GMT-03:00",
+ value: "America/Cordoba",
+ },
+ {
+ label: "America/Costa_Rica, GMT-06:00",
+ value: "America/Costa_Rica",
+ },
+ {
+ label: "America/Creston, GMT-07:00",
+ value: "America/Creston",
+ },
+ {
+ label: "America/Cuiaba, GMT-04:00",
+ value: "America/Cuiaba",
+ },
+ {
+ label: "America/Curacao, GMT-04:00",
+ value: "America/Curacao",
+ },
+ {
+ label: "America/Danmarkshavn, GMT",
+ value: "America/Danmarkshavn",
+ },
+ {
+ label: "America/Dawson, GMT-07:00",
+ value: "America/Dawson",
+ },
+ {
+ label: "America/Dawson_Creek, GMT-07:00",
+ value: "America/Dawson_Creek",
+ },
+ {
+ label: "America/Denver, GMT-06:00",
+ value: "America/Denver",
+ },
+ {
+ label: "America/Detroit, GMT-04:00",
+ value: "America/Detroit",
+ },
+ {
+ label: "America/Dominica, GMT-04:00",
+ value: "America/Dominica",
+ },
+ {
+ label: "America/Edmonton, GMT-06:00",
+ value: "America/Edmonton",
+ },
+ {
+ label: "America/Eirunepe, GMT-05:00",
+ value: "America/Eirunepe",
+ },
+ {
+ label: "America/El_Salvador, GMT-06:00",
+ value: "America/El_Salvador",
+ },
+ {
+ label: "America/Ensenada, GMT-07:00",
+ value: "America/Ensenada",
+ },
+ {
+ label: "America/Fort_Nelson, GMT-07:00",
+ value: "America/Fort_Nelson",
+ },
+ {
+ label: "America/Fort_Wayne, GMT-04:00",
+ value: "America/Fort_Wayne",
+ },
+ {
+ label: "America/Fortaleza, GMT-03:00",
+ value: "America/Fortaleza",
+ },
+ {
+ label: "America/Glace_Bay, GMT-03:00",
+ value: "America/Glace_Bay",
+ },
+ {
+ label: "America/Godthab, GMT-02:00",
+ value: "America/Godthab",
+ },
+ {
+ label: "America/Goose_Bay, GMT-03:00",
+ value: "America/Goose_Bay",
+ },
+ {
+ label: "America/Grand_Turk, GMT-04:00",
+ value: "America/Grand_Turk",
+ },
+ {
+ label: "America/Grenada, GMT-04:00",
+ value: "America/Grenada",
+ },
+ {
+ label: "America/Guadeloupe, GMT-04:00",
+ value: "America/Guadeloupe",
+ },
+ {
+ label: "America/Guatemala, GMT-06:00",
+ value: "America/Guatemala",
+ },
+ {
+ label: "America/Guayaquil, GMT-05:00",
+ value: "America/Guayaquil",
+ },
+ {
+ label: "America/Guyana, GMT-04:00",
+ value: "America/Guyana",
+ },
+ {
+ label: "America/Halifax, GMT-03:00",
+ value: "America/Halifax",
+ },
+ {
+ label: "America/Havana, GMT-04:00",
+ value: "America/Havana",
+ },
+ {
+ label: "America/Hermosillo, GMT-07:00",
+ value: "America/Hermosillo",
+ },
+ {
+ label: "America/Indiana/Indianapolis, GMT-04:00",
+ value: "America/Indiana/Indianapolis",
+ },
+ {
+ label: "America/Indiana/Knox, GMT-05:00",
+ value: "America/Indiana/Knox",
+ },
+ {
+ label: "America/Indiana/Marengo, GMT-04:00",
+ value: "America/Indiana/Marengo",
+ },
+ {
+ label: "America/Indiana/Petersburg, GMT-04:00",
+ value: "America/Indiana/Petersburg",
+ },
+ {
+ label: "America/Indiana/Tell_City, GMT-05:00",
+ value: "America/Indiana/Tell_City",
+ },
+ {
+ label: "America/Indiana/Vevay, GMT-04:00",
+ value: "America/Indiana/Vevay",
+ },
+ {
+ label: "America/Indiana/Vincennes, GMT-04:00",
+ value: "America/Indiana/Vincennes",
+ },
+ {
+ label: "America/Indiana/Winamac, GMT-04:00",
+ value: "America/Indiana/Winamac",
+ },
+ {
+ label: "America/Indianapolis, GMT-04:00",
+ value: "America/Indianapolis",
+ },
+ {
+ label: "America/Inuvik, GMT-06:00",
+ value: "America/Inuvik",
+ },
+ {
+ label: "America/Iqaluit, GMT-04:00",
+ value: "America/Iqaluit",
+ },
+ {
+ label: "America/Jamaica, GMT-05:00",
+ value: "America/Jamaica",
+ },
+ {
+ label: "America/Jujuy, GMT-03:00",
+ value: "America/Jujuy",
+ },
+ {
+ label: "America/Juneau, GMT-08:00",
+ value: "America/Juneau",
+ },
+ {
+ label: "America/Kentucky/Louisville, GMT-04:00",
+ value: "America/Kentucky/Louisville",
+ },
+ {
+ label: "America/Kentucky/Monticello, GMT-04:00",
+ value: "America/Kentucky/Monticello",
+ },
+ {
+ label: "America/Knox_IN, GMT-05:00",
+ value: "America/Knox_IN",
+ },
+ {
+ label: "America/Kralendijk, GMT-04:00",
+ value: "America/Kralendijk",
+ },
+ {
+ label: "America/La_Paz, GMT-04:00",
+ value: "America/La_Paz",
+ },
+ {
+ label: "America/Lima, GMT-05:00",
+ value: "America/Lima",
+ },
+ {
+ label: "America/Los_Angeles, GMT-07:00",
+ value: "America/Los_Angeles",
+ },
+ {
+ label: "America/Louisville, GMT-04:00",
+ value: "America/Louisville",
+ },
+ {
+ label: "America/Lower_Princes, GMT-04:00",
+ value: "America/Lower_Princes",
+ },
+ {
+ label: "America/Maceio, GMT-03:00",
+ value: "America/Maceio",
+ },
+ {
+ label: "America/Managua, GMT-06:00",
+ value: "America/Managua",
+ },
+ {
+ label: "America/Manaus, GMT-04:00",
+ value: "America/Manaus",
+ },
+ {
+ label: "America/Marigot, GMT-04:00",
+ value: "America/Marigot",
+ },
+ {
+ label: "America/Martinique, GMT-04:00",
+ value: "America/Martinique",
+ },
+ {
+ label: "America/Matamoros, GMT-05:00",
+ value: "America/Matamoros",
+ },
+ {
+ label: "America/Mazatlan, GMT-07:00",
+ value: "America/Mazatlan",
+ },
+ {
+ label: "America/Mendoza, GMT-03:00",
+ value: "America/Mendoza",
+ },
+ {
+ label: "America/Menominee, GMT-05:00",
+ value: "America/Menominee",
+ },
+ {
+ label: "America/Merida, GMT-06:00",
+ value: "America/Merida",
+ },
+ {
+ label: "America/Metlakatla, GMT-08:00",
+ value: "America/Metlakatla",
+ },
+ {
+ label: "America/Mexico_City, GMT-06:00",
+ value: "America/Mexico_City",
+ },
+ {
+ label: "America/Miquelon, GMT-02:00",
+ value: "America/Miquelon",
+ },
+ {
+ label: "America/Moncton, GMT-03:00",
+ value: "America/Moncton",
+ },
+ {
+ label: "America/Monterrey, GMT-06:00",
+ value: "America/Monterrey",
+ },
+ {
+ label: "America/Montevideo, GMT-03:00",
+ value: "America/Montevideo",
+ },
+ {
+ label: "America/Montreal, GMT-04:00",
+ value: "America/Montreal",
+ },
+ {
+ label: "America/Montserrat, GMT-04:00",
+ value: "America/Montserrat",
+ },
+ {
+ label: "America/Nassau, GMT-04:00",
+ value: "America/Nassau",
+ },
+ {
+ label: "America/New_York, GMT-04:00",
+ value: "America/New_York",
+ },
+ {
+ label: "America/Nipigon, GMT-04:00",
+ value: "America/Nipigon",
+ },
+ {
+ label: "America/Nome, GMT-08:00",
+ value: "America/Nome",
+ },
+ {
+ label: "America/Noronha, GMT-02:00",
+ value: "America/Noronha",
+ },
+ {
+ label: "America/North_Dakota/Beulah, GMT-05:00",
+ value: "America/North_Dakota/Beulah",
+ },
+ {
+ label: "America/North_Dakota/Center, GMT-05:00",
+ value: "America/North_Dakota/Center",
+ },
+ {
+ label: "America/North_Dakota/New_Salem, GMT-05:00",
+ value: "America/North_Dakota/New_Salem",
+ },
+ {
+ label: "America/Nuuk, GMT-02:00",
+ value: "America/Nuuk",
+ },
+ {
+ label: "America/Ojinaga, GMT-05:00",
+ value: "America/Ojinaga",
+ },
+ {
+ label: "America/Panama, GMT-05:00",
+ value: "America/Panama",
+ },
+ {
+ label: "America/Pangnirtung, GMT-04:00",
+ value: "America/Pangnirtung",
+ },
+ {
+ label: "America/Paramaribo, GMT-03:00",
+ value: "America/Paramaribo",
+ },
+ {
+ label: "America/Phoenix, GMT-07:00",
+ value: "America/Phoenix",
+ },
+ {
+ label: "America/Port-au-Prince, GMT-04:00",
+ value: "America/Port-au-Prince",
+ },
+ {
+ label: "America/Port_of_Spain, GMT-04:00",
+ value: "America/Port_of_Spain",
+ },
+ {
+ label: "America/Porto_Acre, GMT-05:00",
+ value: "America/Porto_Acre",
+ },
+ {
+ label: "America/Porto_Velho, GMT-04:00",
+ value: "America/Porto_Velho",
+ },
+ {
+ label: "America/Puerto_Rico, GMT-04:00",
+ value: "America/Puerto_Rico",
+ },
+ {
+ label: "America/Punta_Arenas, GMT-03:00",
+ value: "America/Punta_Arenas",
+ },
+ {
+ label: "America/Rainy_River, GMT-05:00",
+ value: "America/Rainy_River",
+ },
+ {
+ label: "America/Rankin_Inlet, GMT-05:00",
+ value: "America/Rankin_Inlet",
+ },
+ {
+ label: "America/Recife, GMT-03:00",
+ value: "America/Recife",
+ },
+ {
+ label: "America/Regina, GMT-06:00",
+ value: "America/Regina",
+ },
+ {
+ label: "America/Resolute, GMT-05:00",
+ value: "America/Resolute",
+ },
+ {
+ label: "America/Rio_Branco, GMT-05:00",
+ value: "America/Rio_Branco",
+ },
+ {
+ label: "America/Rosario, GMT-03:00",
+ value: "America/Rosario",
+ },
+ {
+ label: "America/Santa_Isabel, GMT-07:00",
+ value: "America/Santa_Isabel",
+ },
+ {
+ label: "America/Santarem, GMT-03:00",
+ value: "America/Santarem",
+ },
+ {
+ label: "America/Santiago, GMT-04:00",
+ value: "America/Santiago",
+ },
+ {
+ label: "America/Santo_Domingo, GMT-04:00",
+ value: "America/Santo_Domingo",
+ },
+ {
+ label: "America/Sao_Paulo, GMT-03:00",
+ value: "America/Sao_Paulo",
+ },
+ {
+ label: "America/Scoresbysund, GMT",
+ value: "America/Scoresbysund",
+ },
+ {
+ label: "America/Shiprock, GMT-06:00",
+ value: "America/Shiprock",
+ },
+ {
+ label: "America/Sitka, GMT-08:00",
+ value: "America/Sitka",
+ },
+ {
+ label: "America/St_Barthelemy, GMT-04:00",
+ value: "America/St_Barthelemy",
+ },
+ {
+ label: "America/St_Johns, GMT-02:30",
+ value: "America/St_Johns",
+ },
+ {
+ label: "America/St_Kitts, GMT-04:00",
+ value: "America/St_Kitts",
+ },
+ {
+ label: "America/St_Lucia, GMT-04:00",
+ value: "America/St_Lucia",
+ },
+ {
+ label: "America/St_Thomas, GMT-04:00",
+ value: "America/St_Thomas",
+ },
+ {
+ label: "America/St_Vincent, GMT-04:00",
+ value: "America/St_Vincent",
+ },
+ {
+ label: "America/Swift_Current, GMT-06:00",
+ value: "America/Swift_Current",
+ },
+ {
+ label: "America/Tegucigalpa, GMT-06:00",
+ value: "America/Tegucigalpa",
+ },
+ {
+ label: "America/Thule, GMT-03:00",
+ value: "America/Thule",
+ },
+ {
+ label: "America/Thunder_Bay, GMT-04:00",
+ value: "America/Thunder_Bay",
+ },
+ {
+ label: "America/Tijuana, GMT-07:00",
+ value: "America/Tijuana",
+ },
+ {
+ label: "America/Toronto, GMT-04:00",
+ value: "America/Toronto",
+ },
+ {
+ label: "America/Tortola, GMT-04:00",
+ value: "America/Tortola",
+ },
+ {
+ label: "America/Vancouver, GMT-07:00",
+ value: "America/Vancouver",
+ },
+ {
+ label: "America/Virgin, GMT-04:00",
+ value: "America/Virgin",
+ },
+ {
+ label: "America/Whitehorse, GMT-07:00",
+ value: "America/Whitehorse",
+ },
+ {
+ label: "America/Winnipeg, GMT-05:00",
+ value: "America/Winnipeg",
+ },
+ {
+ label: "America/Yakutat, GMT-08:00",
+ value: "America/Yakutat",
+ },
+ {
+ label: "America/Yellowknife, GMT-06:00",
+ value: "America/Yellowknife",
+ },
+ {
+ label: "Antarctica/Casey, GMT+11:00",
+ value: "Antarctica/Casey",
+ },
+ {
+ label: "Antarctica/Davis, GMT+07:00",
+ value: "Antarctica/Davis",
+ },
+ {
+ label: "Antarctica/DumontDUrville, GMT+10:00",
+ value: "Antarctica/DumontDUrville",
+ },
+ {
+ label: "Antarctica/Macquarie, GMT+10:00",
+ value: "Antarctica/Macquarie",
+ },
+ {
+ label: "Antarctica/Mawson, GMT+05:00",
+ value: "Antarctica/Mawson",
+ },
+ {
+ label: "Antarctica/McMurdo, GMT+12:00",
+ value: "Antarctica/McMurdo",
+ },
+ {
+ label: "Antarctica/Palmer, GMT-03:00",
+ value: "Antarctica/Palmer",
+ },
+ {
+ label: "Antarctica/Rothera, GMT-03:00",
+ value: "Antarctica/Rothera",
+ },
+ {
+ label: "Antarctica/South_Pole, GMT+12:00",
+ value: "Antarctica/South_Pole",
+ },
+ {
+ label: "Antarctica/Syowa, GMT+03:00",
+ value: "Antarctica/Syowa",
+ },
+ {
+ label: "Antarctica/Troll, GMT+02:00",
+ value: "Antarctica/Troll",
+ },
+ {
+ label: "Antarctica/Vostok, GMT+06:00",
+ value: "Antarctica/Vostok",
+ },
+ {
+ label: "Arctic/Longyearbyen, GMT+02:00",
+ value: "Arctic/Longyearbyen",
+ },
+ {
+ label: "Asia/Aden, GMT+03:00",
+ value: "Asia/Aden",
+ },
+ {
+ label: "Asia/Almaty, GMT+06:00",
+ value: "Asia/Almaty",
+ },
+ {
+ label: "Asia/Amman, GMT+03:00",
+ value: "Asia/Amman",
+ },
+ {
+ label: "Asia/Anadyr, GMT+12:00",
+ value: "Asia/Anadyr",
+ },
+ {
+ label: "Asia/Aqtau, GMT+05:00",
+ value: "Asia/Aqtau",
+ },
+ {
+ label: "Asia/Aqtobe, GMT+05:00",
+ value: "Asia/Aqtobe",
+ },
+ {
+ label: "Asia/Ashgabat, GMT+05:00",
+ value: "Asia/Ashgabat",
+ },
+ {
+ label: "Asia/Ashkhabad, GMT+05:00",
+ value: "Asia/Ashkhabad",
+ },
+ {
+ label: "Asia/Atyrau, GMT+05:00",
+ value: "Asia/Atyrau",
+ },
+ {
+ label: "Asia/Baghdad, GMT+03:00",
+ value: "Asia/Baghdad",
+ },
+ {
+ label: "Asia/Bahrain, GMT+03:00",
+ value: "Asia/Bahrain",
+ },
+ {
+ label: "Asia/Baku, GMT+04:00",
+ value: "Asia/Baku",
+ },
+ {
+ label: "Asia/Bangkok, GMT+07:00",
+ value: "Asia/Bangkok",
+ },
+ {
+ label: "Asia/Barnaul, GMT+07:00",
+ value: "Asia/Barnaul",
+ },
+ {
+ label: "Asia/Beirut, GMT+03:00",
+ value: "Asia/Beirut",
+ },
+ {
+ label: "Asia/Bishkek, GMT+06:00",
+ value: "Asia/Bishkek",
+ },
+ {
+ label: "Asia/Brunei, GMT+08:00",
+ value: "Asia/Brunei",
+ },
+ {
+ label: "Asia/Calcutta, GMT+05:30",
+ value: "Asia/Calcutta",
+ },
+ {
+ label: "Asia/Chita, GMT+09:00",
+ value: "Asia/Chita",
+ },
+ {
+ label: "Asia/Choibalsan, GMT+08:00",
+ value: "Asia/Choibalsan",
+ },
+ {
+ label: "Asia/Chongqing, GMT+08:00",
+ value: "Asia/Chongqing",
+ },
+ {
+ label: "Asia/Chungking, GMT+08:00",
+ value: "Asia/Chungking",
+ },
+ {
+ label: "Asia/Colombo, GMT+05:30",
+ value: "Asia/Colombo",
+ },
+ {
+ label: "Asia/Dacca, GMT+06:00",
+ value: "Asia/Dacca",
+ },
+ {
+ label: "Asia/Damascus, GMT+03:00",
+ value: "Asia/Damascus",
+ },
+ {
+ label: "Asia/Dhaka, GMT+06:00",
+ value: "Asia/Dhaka",
+ },
+ {
+ label: "Asia/Dili, GMT+09:00",
+ value: "Asia/Dili",
+ },
+ {
+ label: "Asia/Dubai, GMT+04:00",
+ value: "Asia/Dubai",
+ },
+ {
+ label: "Asia/Dushanbe, GMT+05:00",
+ value: "Asia/Dushanbe",
+ },
+ {
+ label: "Asia/Famagusta, GMT+03:00",
+ value: "Asia/Famagusta",
+ },
+ {
+ label: "Asia/Gaza, GMT+03:00",
+ value: "Asia/Gaza",
+ },
+ {
+ label: "Asia/Harbin, GMT+08:00",
+ value: "Asia/Harbin",
+ },
+ {
+ label: "Asia/Hebron, GMT+03:00",
+ value: "Asia/Hebron",
+ },
+ {
+ label: "Asia/Ho_Chi_Minh, GMT+07:00",
+ value: "Asia/Ho_Chi_Minh",
+ },
+ {
+ label: "Asia/Hong_Kong, GMT+08:00",
+ value: "Asia/Hong_Kong",
+ },
+ {
+ label: "Asia/Hovd, GMT+07:00",
+ value: "Asia/Hovd",
+ },
+ {
+ label: "Asia/Irkutsk, GMT+08:00",
+ value: "Asia/Irkutsk",
+ },
+ {
+ label: "Asia/Istanbul, GMT+03:00",
+ value: "Asia/Istanbul",
+ },
+ {
+ label: "Asia/Jakarta, GMT+07:00",
+ value: "Asia/Jakarta",
+ },
+ {
+ label: "Asia/Jayapura, GMT+09:00",
+ value: "Asia/Jayapura",
+ },
+ {
+ label: "Asia/Jerusalem, GMT+03:00",
+ value: "Asia/Jerusalem",
+ },
+ {
+ label: "Asia/Kabul, GMT+04:30",
+ value: "Asia/Kabul",
+ },
+ {
+ label: "Asia/Kamchatka, GMT+12:00",
+ value: "Asia/Kamchatka",
+ },
+ {
+ label: "Asia/Karachi, GMT+05:00",
+ value: "Asia/Karachi",
+ },
+ {
+ label: "Asia/Kashgar, GMT+06:00",
+ value: "Asia/Kashgar",
+ },
+ {
+ label: "Asia/Kathmandu, GMT+05:45",
+ value: "Asia/Kathmandu",
+ },
+ {
+ label: "Asia/Katmandu, GMT+05:45",
+ value: "Asia/Katmandu",
+ },
+ {
+ label: "Asia/Khandyga, GMT+09:00",
+ value: "Asia/Khandyga",
+ },
+ {
+ label: "Asia/Kolkata, GMT+05:30",
+ value: "Asia/Kolkata",
+ },
+ {
+ label: "Asia/Krasnoyarsk, GMT+07:00",
+ value: "Asia/Krasnoyarsk",
+ },
+ {
+ label: "Asia/Kuala_Lumpur, GMT+08:00",
+ value: "Asia/Kuala_Lumpur",
+ },
+ {
+ label: "Asia/Kuching, GMT+08:00",
+ value: "Asia/Kuching",
+ },
+ {
+ label: "Asia/Kuwait, GMT+03:00",
+ value: "Asia/Kuwait",
+ },
+ {
+ label: "Asia/Macao, GMT+08:00",
+ value: "Asia/Macao",
+ },
+ {
+ label: "Asia/Macau, GMT+08:00",
+ value: "Asia/Macau",
+ },
+ {
+ label: "Asia/Magadan, GMT+11:00",
+ value: "Asia/Magadan",
+ },
+ {
+ label: "Asia/Makassar, GMT+08:00",
+ value: "Asia/Makassar",
+ },
+ {
+ label: "Asia/Manila, GMT+08:00",
+ value: "Asia/Manila",
+ },
+ {
+ label: "Asia/Muscat, GMT+04:00",
+ value: "Asia/Muscat",
+ },
+ {
+ label: "Asia/Nicosia, GMT+03:00",
+ value: "Asia/Nicosia",
+ },
+ {
+ label: "Asia/Novokuznetsk, GMT+07:00",
+ value: "Asia/Novokuznetsk",
+ },
+ {
+ label: "Asia/Novosibirsk, GMT+07:00",
+ value: "Asia/Novosibirsk",
+ },
+ {
+ label: "Asia/Omsk, GMT+06:00",
+ value: "Asia/Omsk",
+ },
+ {
+ label: "Asia/Oral, GMT+05:00",
+ value: "Asia/Oral",
+ },
+ {
+ label: "Asia/Phnom_Penh, GMT+07:00",
+ value: "Asia/Phnom_Penh",
+ },
+ {
+ label: "Asia/Pontianak, GMT+07:00",
+ value: "Asia/Pontianak",
+ },
+ {
+ label: "Asia/Pyongyang, GMT+09:00",
+ value: "Asia/Pyongyang",
+ },
+ {
+ label: "Asia/Qatar, GMT+03:00",
+ value: "Asia/Qatar",
+ },
+ {
+ label: "Asia/Qostanay, GMT+06:00",
+ value: "Asia/Qostanay",
+ },
+ {
+ label: "Asia/Qyzylorda, GMT+05:00",
+ value: "Asia/Qyzylorda",
+ },
+ {
+ label: "Asia/Rangoon, GMT+06:30",
+ value: "Asia/Rangoon",
+ },
+ {
+ label: "Asia/Riyadh, GMT+03:00",
+ value: "Asia/Riyadh",
+ },
+ {
+ label: "Asia/Saigon, GMT+07:00",
+ value: "Asia/Saigon",
+ },
+ {
+ label: "Asia/Sakhalin, GMT+11:00",
+ value: "Asia/Sakhalin",
+ },
+ {
+ label: "Asia/Samarkand, GMT+05:00",
+ value: "Asia/Samarkand",
+ },
+ {
+ label: "Asia/Seoul, GMT+09:00",
+ value: "Asia/Seoul",
+ },
+ {
+ label: "Asia/Shanghai, GMT+08:00",
+ value: "Asia/Shanghai",
+ },
+ {
+ label: "Asia/Singapore, GMT+08:00",
+ value: "Asia/Singapore",
+ },
+ {
+ label: "Asia/Srednekolymsk, GMT+11:00",
+ value: "Asia/Srednekolymsk",
+ },
+ {
+ label: "Asia/Taipei, GMT+08:00",
+ value: "Asia/Taipei",
+ },
+ {
+ label: "Asia/Tashkent, GMT+05:00",
+ value: "Asia/Tashkent",
+ },
+ {
+ label: "Asia/Tbilisi, GMT+04:00",
+ value: "Asia/Tbilisi",
+ },
+ {
+ label: "Asia/Tehran, GMT+03:30",
+ value: "Asia/Tehran",
+ },
+ {
+ label: "Asia/Tel_Aviv, GMT+03:00",
+ value: "Asia/Tel_Aviv",
+ },
+ {
+ label: "Asia/Thimbu, GMT+06:00",
+ value: "Asia/Thimbu",
+ },
+ {
+ label: "Asia/Thimphu, GMT+06:00",
+ value: "Asia/Thimphu",
+ },
+ {
+ label: "Asia/Tokyo, GMT+09:00",
+ value: "Asia/Tokyo",
+ },
+ {
+ label: "Asia/Tomsk, GMT+07:00",
+ value: "Asia/Tomsk",
+ },
+ {
+ label: "Asia/Ujung_Pandang, GMT+08:00",
+ value: "Asia/Ujung_Pandang",
+ },
+ {
+ label: "Asia/Ulaanbaatar, GMT+08:00",
+ value: "Asia/Ulaanbaatar",
+ },
+ {
+ label: "Asia/Ulan_Bator, GMT+08:00",
+ value: "Asia/Ulan_Bator",
+ },
+ {
+ label: "Asia/Urumqi, GMT+06:00",
+ value: "Asia/Urumqi",
+ },
+ {
+ label: "Asia/Ust-Nera, GMT+10:00",
+ value: "Asia/Ust-Nera",
+ },
+ {
+ label: "Asia/Vientiane, GMT+07:00",
+ value: "Asia/Vientiane",
+ },
+ {
+ label: "Asia/Vladivostok, GMT+10:00",
+ value: "Asia/Vladivostok",
+ },
+ {
+ label: "Asia/Yakutsk, GMT+09:00",
+ value: "Asia/Yakutsk",
+ },
+ {
+ label: "Asia/Yangon, GMT+06:30",
+ value: "Asia/Yangon",
+ },
+ {
+ label: "Asia/Yekaterinburg, GMT+05:00",
+ value: "Asia/Yekaterinburg",
+ },
+ {
+ label: "Asia/Yerevan, GMT+04:00",
+ value: "Asia/Yerevan",
+ },
+ {
+ label: "Atlantic/Azores, GMT",
+ value: "Atlantic/Azores",
+ },
+ {
+ label: "Atlantic/Bermuda, GMT-03:00",
+ value: "Atlantic/Bermuda",
+ },
+ {
+ label: "Atlantic/Canary, GMT+01:00",
+ value: "Atlantic/Canary",
+ },
+ {
+ label: "Atlantic/Cape_Verde, GMT-01:00",
+ value: "Atlantic/Cape_Verde",
+ },
+ {
+ label: "Atlantic/Faeroe, GMT+01:00",
+ value: "Atlantic/Faeroe",
+ },
+ {
+ label: "Atlantic/Faroe, GMT+01:00",
+ value: "Atlantic/Faroe",
+ },
+ {
+ label: "Atlantic/Jan_Mayen, GMT+02:00",
+ value: "Atlantic/Jan_Mayen",
+ },
+ {
+ label: "Atlantic/Madeira, GMT+01:00",
+ value: "Atlantic/Madeira",
+ },
+ {
+ label: "Atlantic/Reykjavik, GMT",
+ value: "Atlantic/Reykjavik",
+ },
+ {
+ label: "Atlantic/South_Georgia, GMT-02:00",
+ value: "Atlantic/South_Georgia",
+ },
+ {
+ label: "Atlantic/St_Helena, GMT",
+ value: "Atlantic/St_Helena",
+ },
+ {
+ label: "Atlantic/Stanley, GMT-03:00",
+ value: "Atlantic/Stanley",
+ },
+ {
+ label: "Australia/ACT, GMT+10:00",
+ value: "Australia/ACT",
+ },
+ {
+ label: "Australia/Adelaide, GMT+09:30",
+ value: "Australia/Adelaide",
+ },
+ {
+ label: "Australia/Brisbane, GMT+10:00",
+ value: "Australia/Brisbane",
+ },
+ {
+ label: "Australia/Broken_Hill, GMT+09:30",
+ value: "Australia/Broken_Hill",
+ },
+ {
+ label: "Australia/Canberra, GMT+10:00",
+ value: "Australia/Canberra",
+ },
+ {
+ label: "Australia/Currie, GMT+10:00",
+ value: "Australia/Currie",
+ },
+ {
+ label: "Australia/Darwin, GMT+09:30",
+ value: "Australia/Darwin",
+ },
+ {
+ label: "Australia/Eucla, GMT+08:45",
+ value: "Australia/Eucla",
+ },
+ {
+ label: "Australia/Hobart, GMT+10:00",
+ value: "Australia/Hobart",
+ },
+ {
+ label: "Australia/LHI, GMT+10:30",
+ value: "Australia/LHI",
+ },
+ {
+ label: "Australia/Lindeman, GMT+10:00",
+ value: "Australia/Lindeman",
+ },
+ {
+ label: "Australia/Lord_Howe, GMT+10:30",
+ value: "Australia/Lord_Howe",
+ },
+ {
+ label: "Australia/Melbourne, GMT+10:00",
+ value: "Australia/Melbourne",
+ },
+ {
+ label: "Australia/NSW, GMT+10:00",
+ value: "Australia/NSW",
+ },
+ {
+ label: "Australia/North, GMT+09:30",
+ value: "Australia/North",
+ },
+ {
+ label: "Australia/Perth, GMT+08:00",
+ value: "Australia/Perth",
+ },
+ {
+ label: "Australia/Queensland, GMT+10:00",
+ value: "Australia/Queensland",
+ },
+ {
+ label: "Australia/South, GMT+09:30",
+ value: "Australia/South",
+ },
+ {
+ label: "Australia/Sydney, GMT+10:00",
+ value: "Australia/Sydney",
+ },
+ {
+ label: "Australia/Tasmania, GMT+10:00",
+ value: "Australia/Tasmania",
+ },
+ {
+ label: "Australia/Victoria, GMT+10:00",
+ value: "Australia/Victoria",
+ },
+ {
+ label: "Australia/West, GMT+08:00",
+ value: "Australia/West",
+ },
+ {
+ label: "Australia/Yancowinna, GMT+09:30",
+ value: "Australia/Yancowinna",
+ },
+ {
+ label: "Brazil/Acre, GMT-05:00",
+ value: "Brazil/Acre",
+ },
+ {
+ label: "Brazil/DeNoronha, GMT-02:00",
+ value: "Brazil/DeNoronha",
+ },
+ {
+ label: "Brazil/East, GMT-03:00",
+ value: "Brazil/East",
+ },
+ {
+ label: "Brazil/West, GMT-04:00",
+ value: "Brazil/West",
+ },
+ {
+ label: "CET, GMT+02:00",
+ value: "CET",
+ },
+ {
+ label: "CST6CDT, GMT-05:00",
+ value: "CST6CDT",
+ },
+ {
+ label: "Canada/Atlantic, GMT-03:00",
+ value: "Canada/Atlantic",
+ },
+ {
+ label: "Canada/Central, GMT-05:00",
+ value: "Canada/Central",
+ },
+ {
+ label: "Canada/Eastern, GMT-04:00",
+ value: "Canada/Eastern",
+ },
+ {
+ label: "Canada/Mountain, GMT-06:00",
+ value: "Canada/Mountain",
+ },
+ {
+ label: "Canada/Newfoundland, GMT-02:30",
+ value: "Canada/Newfoundland",
+ },
+ {
+ label: "Canada/Pacific, GMT-07:00",
+ value: "Canada/Pacific",
+ },
+ {
+ label: "Canada/Saskatchewan, GMT-06:00",
+ value: "Canada/Saskatchewan",
+ },
+ {
+ label: "Canada/Yukon, GMT-07:00",
+ value: "Canada/Yukon",
+ },
+ {
+ label: "Chile/Continental, GMT-04:00",
+ value: "Chile/Continental",
+ },
+ {
+ label: "Chile/EasterIsland, GMT-06:00",
+ value: "Chile/EasterIsland",
+ },
+ {
+ label: "Cuba, GMT-04:00",
+ value: "Cuba",
+ },
+ {
+ label: "EET, GMT+03:00",
+ value: "EET",
+ },
+ {
+ label: "EST, GMT-05:00",
+ value: "EST",
+ },
+ {
+ label: "EST5EDT, GMT-04:00",
+ value: "EST5EDT",
+ },
+ {
+ label: "Egypt, GMT+03:00",
+ value: "Egypt",
+ },
+ {
+ label: "Eire, GMT+01:00",
+ value: "Eire",
+ },
+ {
+ label: "Etc/GMT, GMT",
+ value: "Etc/GMT",
+ },
+ {
+ label: "Etc/GMT+0, GMT",
+ value: "Etc/GMT+0",
+ },
+ {
+ label: "Etc/GMT+1, GMT-01:00",
+ value: "Etc/GMT+1",
+ },
+ {
+ label: "Etc/GMT+10, GMT-10:00",
+ value: "Etc/GMT+10",
+ },
+ {
+ label: "Etc/GMT+11, GMT-11:00",
+ value: "Etc/GMT+11",
+ },
+ {
+ label: "Etc/GMT+12, GMT-12:00",
+ value: "Etc/GMT+12",
+ },
+ {
+ label: "Etc/GMT+2, GMT-02:00",
+ value: "Etc/GMT+2",
+ },
+ {
+ label: "Etc/GMT+3, GMT-03:00",
+ value: "Etc/GMT+3",
+ },
+ {
+ label: "Etc/GMT+4, GMT-04:00",
+ value: "Etc/GMT+4",
+ },
+ {
+ label: "Etc/GMT+5, GMT-05:00",
+ value: "Etc/GMT+5",
+ },
+ {
+ label: "Etc/GMT+6, GMT-06:00",
+ value: "Etc/GMT+6",
+ },
+ {
+ label: "Etc/GMT+7, GMT-07:00",
+ value: "Etc/GMT+7",
+ },
+ {
+ label: "Etc/GMT+8, GMT-08:00",
+ value: "Etc/GMT+8",
+ },
+ {
+ label: "Etc/GMT+9, GMT-09:00",
+ value: "Etc/GMT+9",
+ },
+ {
+ label: "Etc/GMT-0, GMT",
+ value: "Etc/GMT-0",
+ },
+ {
+ label: "Etc/GMT-1, GMT+01:00",
+ value: "Etc/GMT-1",
+ },
+ {
+ label: "Etc/GMT-10, GMT+10:00",
+ value: "Etc/GMT-10",
+ },
+ {
+ label: "Etc/GMT-11, GMT+11:00",
+ value: "Etc/GMT-11",
+ },
+ {
+ label: "Etc/GMT-12, GMT+12:00",
+ value: "Etc/GMT-12",
+ },
+ {
+ label: "Etc/GMT-13, GMT+13:00",
+ value: "Etc/GMT-13",
+ },
+ {
+ label: "Etc/GMT-14, GMT+14:00",
+ value: "Etc/GMT-14",
+ },
+ {
+ label: "Etc/GMT-2, GMT+02:00",
+ value: "Etc/GMT-2",
+ },
+ {
+ label: "Etc/GMT-3, GMT+03:00",
+ value: "Etc/GMT-3",
+ },
+ {
+ label: "Etc/GMT-4, GMT+04:00",
+ value: "Etc/GMT-4",
+ },
+ {
+ label: "Etc/GMT-5, GMT+05:00",
+ value: "Etc/GMT-5",
+ },
+ {
+ label: "Etc/GMT-6, GMT+06:00",
+ value: "Etc/GMT-6",
+ },
+ {
+ label: "Etc/GMT-7, GMT+07:00",
+ value: "Etc/GMT-7",
+ },
+ {
+ label: "Etc/GMT-8, GMT+08:00",
+ value: "Etc/GMT-8",
+ },
+ {
+ label: "Etc/GMT-9, GMT+09:00",
+ value: "Etc/GMT-9",
+ },
+ {
+ label: "Etc/GMT0, GMT",
+ value: "Etc/GMT0",
+ },
+ {
+ label: "Etc/Greenwich, GMT",
+ value: "Etc/Greenwich",
+ },
+ {
+ label: "Etc/UCT, GMT",
+ value: "Etc/UCT",
+ },
+ {
+ label: "Etc/UTC, GMT",
+ value: "Etc/UTC",
+ },
+ {
+ label: "Etc/Universal, GMT",
+ value: "Etc/Universal",
+ },
+ {
+ label: "Etc/Zulu, GMT",
+ value: "Etc/Zulu",
+ },
+ {
+ label: "Europe/Amsterdam, GMT+02:00",
+ value: "Europe/Amsterdam",
+ },
+ {
+ label: "Europe/Andorra, GMT+02:00",
+ value: "Europe/Andorra",
+ },
+ {
+ label: "Europe/Astrakhan, GMT+04:00",
+ value: "Europe/Astrakhan",
+ },
+ {
+ label: "Europe/Athens, GMT+03:00",
+ value: "Europe/Athens",
+ },
+ {
+ label: "Europe/Belfast, GMT+01:00",
+ value: "Europe/Belfast",
+ },
+ {
+ label: "Europe/Belgrade, GMT+02:00",
+ value: "Europe/Belgrade",
+ },
+ {
+ label: "Europe/Berlin, GMT+02:00",
+ value: "Europe/Berlin",
+ },
+ {
+ label: "Europe/Bratislava, GMT+02:00",
+ value: "Europe/Bratislava",
+ },
+ {
+ label: "Europe/Brussels, GMT+02:00",
+ value: "Europe/Brussels",
+ },
+ {
+ label: "Europe/Bucharest, GMT+03:00",
+ value: "Europe/Bucharest",
+ },
+ {
+ label: "Europe/Budapest, GMT+02:00",
+ value: "Europe/Budapest",
+ },
+ {
+ label: "Europe/Busingen, GMT+02:00",
+ value: "Europe/Busingen",
+ },
+ {
+ label: "Europe/Chisinau, GMT+03:00",
+ value: "Europe/Chisinau",
+ },
+ {
+ label: "Europe/Copenhagen, GMT+02:00",
+ value: "Europe/Copenhagen",
+ },
+ {
+ label: "Europe/Dublin, GMT+01:00",
+ value: "Europe/Dublin",
+ },
+ {
+ label: "Europe/Gibraltar, GMT+02:00",
+ value: "Europe/Gibraltar",
+ },
+ {
+ label: "Europe/Guernsey, GMT+01:00",
+ value: "Europe/Guernsey",
+ },
+ {
+ label: "Europe/Helsinki, GMT+03:00",
+ value: "Europe/Helsinki",
+ },
+ {
+ label: "Europe/Isle_of_Man, GMT+01:00",
+ value: "Europe/Isle_of_Man",
+ },
+ {
+ label: "Europe/Istanbul, GMT+03:00",
+ value: "Europe/Istanbul",
+ },
+ {
+ label: "Europe/Jersey, GMT+01:00",
+ value: "Europe/Jersey",
+ },
+ {
+ label: "Europe/Kaliningrad, GMT+02:00",
+ value: "Europe/Kaliningrad",
+ },
+ {
+ label: "Europe/Kiev, GMT+03:00",
+ value: "Europe/Kiev",
+ },
+ {
+ label: "Europe/Kirov, GMT+03:00",
+ value: "Europe/Kirov",
+ },
+ {
+ label: "Europe/Kyiv, GMT+03:00",
+ value: "Europe/Kyiv",
+ },
+ {
+ label: "Europe/Lisbon, GMT+01:00",
+ value: "Europe/Lisbon",
+ },
+ {
+ label: "Europe/Ljubljana, GMT+02:00",
+ value: "Europe/Ljubljana",
+ },
+ {
+ label: "Europe/London, GMT+01:00",
+ value: "Europe/London",
+ },
+ {
+ label: "Europe/Luxembourg, GMT+02:00",
+ value: "Europe/Luxembourg",
+ },
+ {
+ label: "Europe/Madrid, GMT+02:00",
+ value: "Europe/Madrid",
+ },
+ {
+ label: "Europe/Malta, GMT+02:00",
+ value: "Europe/Malta",
+ },
+ {
+ label: "Europe/Mariehamn, GMT+03:00",
+ value: "Europe/Mariehamn",
+ },
+ {
+ label: "Europe/Minsk, GMT+03:00",
+ value: "Europe/Minsk",
+ },
+ {
+ label: "Europe/Monaco, GMT+02:00",
+ value: "Europe/Monaco",
+ },
+ {
+ label: "Europe/Moscow, GMT+03:00",
+ value: "Europe/Moscow",
+ },
+ {
+ label: "Europe/Nicosia, GMT+03:00",
+ value: "Europe/Nicosia",
+ },
+ {
+ label: "Europe/Oslo, GMT+02:00",
+ value: "Europe/Oslo",
+ },
+ {
+ label: "Europe/Paris, GMT+02:00",
+ value: "Europe/Paris",
+ },
+ {
+ label: "Europe/Podgorica, GMT+02:00",
+ value: "Europe/Podgorica",
+ },
+ {
+ label: "Europe/Prague, GMT+02:00",
+ value: "Europe/Prague",
+ },
+ {
+ label: "Europe/Riga, GMT+03:00",
+ value: "Europe/Riga",
+ },
+ {
+ label: "Europe/Rome, GMT+02:00",
+ value: "Europe/Rome",
+ },
+ {
+ label: "Europe/Samara, GMT+04:00",
+ value: "Europe/Samara",
+ },
+ {
+ label: "Europe/San_Marino, GMT+02:00",
+ value: "Europe/San_Marino",
+ },
+ {
+ label: "Europe/Sarajevo, GMT+02:00",
+ value: "Europe/Sarajevo",
+ },
+ {
+ label: "Europe/Saratov, GMT+04:00",
+ value: "Europe/Saratov",
+ },
+ {
+ label: "Europe/Simferopol, GMT+03:00",
+ value: "Europe/Simferopol",
+ },
+ {
+ label: "Europe/Skopje, GMT+02:00",
+ value: "Europe/Skopje",
+ },
+ {
+ label: "Europe/Sofia, GMT+03:00",
+ value: "Europe/Sofia",
+ },
+ {
+ label: "Europe/Stockholm, GMT+02:00",
+ value: "Europe/Stockholm",
+ },
+ {
+ label: "Europe/Tallinn, GMT+03:00",
+ value: "Europe/Tallinn",
+ },
+ {
+ label: "Europe/Tirane, GMT+02:00",
+ value: "Europe/Tirane",
+ },
+ {
+ label: "Europe/Tiraspol, GMT+03:00",
+ value: "Europe/Tiraspol",
+ },
+ {
+ label: "Europe/Ulyanovsk, GMT+04:00",
+ value: "Europe/Ulyanovsk",
+ },
+ {
+ label: "Europe/Uzhgorod, GMT+03:00",
+ value: "Europe/Uzhgorod",
+ },
+ {
+ label: "Europe/Vaduz, GMT+02:00",
+ value: "Europe/Vaduz",
+ },
+ {
+ label: "Europe/Vatican, GMT+02:00",
+ value: "Europe/Vatican",
+ },
+ {
+ label: "Europe/Vienna, GMT+02:00",
+ value: "Europe/Vienna",
+ },
+ {
+ label: "Europe/Vilnius, GMT+03:00",
+ value: "Europe/Vilnius",
+ },
+ {
+ label: "Europe/Volgograd, GMT+03:00",
+ value: "Europe/Volgograd",
+ },
+ {
+ label: "Europe/Warsaw, GMT+02:00",
+ value: "Europe/Warsaw",
+ },
+ {
+ label: "Europe/Zagreb, GMT+02:00",
+ value: "Europe/Zagreb",
+ },
+ {
+ label: "Europe/Zaporozhye, GMT+03:00",
+ value: "Europe/Zaporozhye",
+ },
+ {
+ label: "Europe/Zurich, GMT+02:00",
+ value: "Europe/Zurich",
+ },
+ {
+ label: "GB, GMT+01:00",
+ value: "GB",
+ },
+ {
+ label: "GB-Eire, GMT+01:00",
+ value: "GB-Eire",
+ },
+ {
+ label: "GMT, GMT",
+ value: "GMT",
+ },
+ {
+ label: "GMT+0, GMT",
+ value: "GMT+0",
+ },
+ {
+ label: "GMT-0, GMT",
+ value: "GMT-0",
+ },
+ {
+ label: "GMT0, GMT",
+ value: "GMT0",
+ },
+ {
+ label: "Greenwich, GMT",
+ value: "Greenwich",
+ },
+ {
+ label: "HST, GMT-10:00",
+ value: "HST",
+ },
+ {
+ label: "Hongkong, GMT+08:00",
+ value: "Hongkong",
+ },
+ {
+ label: "Iceland, GMT",
+ value: "Iceland",
+ },
+ {
+ label: "Indian/Antananarivo, GMT+03:00",
+ value: "Indian/Antananarivo",
+ },
+ {
+ label: "Indian/Chagos, GMT+06:00",
+ value: "Indian/Chagos",
+ },
+ {
+ label: "Indian/Christmas, GMT+07:00",
+ value: "Indian/Christmas",
+ },
+ {
+ label: "Indian/Cocos, GMT+06:30",
+ value: "Indian/Cocos",
+ },
+ {
+ label: "Indian/Comoro, GMT+03:00",
+ value: "Indian/Comoro",
+ },
+ {
+ label: "Indian/Kerguelen, GMT+05:00",
+ value: "Indian/Kerguelen",
+ },
+ {
+ label: "Indian/Mahe, GMT+04:00",
+ value: "Indian/Mahe",
+ },
+ {
+ label: "Indian/Maldives, GMT+05:00",
+ value: "Indian/Maldives",
+ },
+ {
+ label: "Indian/Mauritius, GMT+04:00",
+ value: "Indian/Mauritius",
+ },
+ {
+ label: "Indian/Mayotte, GMT+03:00",
+ value: "Indian/Mayotte",
+ },
+ {
+ label: "Indian/Reunion, GMT+04:00",
+ value: "Indian/Reunion",
+ },
+ {
+ label: "Iran, GMT+03:30",
+ value: "Iran",
+ },
+ {
+ label: "Israel, GMT+03:00",
+ value: "Israel",
+ },
+ {
+ label: "Jamaica, GMT-05:00",
+ value: "Jamaica",
+ },
+ {
+ label: "Japan, GMT+09:00",
+ value: "Japan",
+ },
+ {
+ label: "Kwajalein, GMT+12:00",
+ value: "Kwajalein",
+ },
+ {
+ label: "Libya, GMT+02:00",
+ value: "Libya",
+ },
+ {
+ label: "MET, GMT+02:00",
+ value: "MET",
+ },
+ {
+ label: "MST, GMT-07:00",
+ value: "MST",
+ },
+ {
+ label: "MST7MDT, GMT-06:00",
+ value: "MST7MDT",
+ },
+ {
+ label: "Mexico/BajaNorte, GMT-07:00",
+ value: "Mexico/BajaNorte",
+ },
+ {
+ label: "Mexico/BajaSur, GMT-07:00",
+ value: "Mexico/BajaSur",
+ },
+ {
+ label: "Mexico/General, GMT-06:00",
+ value: "Mexico/General",
+ },
+ {
+ label: "NZ, GMT+12:00",
+ value: "NZ",
+ },
+ {
+ label: "NZ-CHAT, GMT+12:45",
+ value: "NZ-CHAT",
+ },
+ {
+ label: "Navajo, GMT-06:00",
+ value: "Navajo",
+ },
+ {
+ label: "PRC, GMT+08:00",
+ value: "PRC",
+ },
+ {
+ label: "PST8PDT, GMT-07:00",
+ value: "PST8PDT",
+ },
+ {
+ label: "Pacific/Apia, GMT+13:00",
+ value: "Pacific/Apia",
+ },
+ {
+ label: "Pacific/Auckland, GMT+12:00",
+ value: "Pacific/Auckland",
+ },
+ {
+ label: "Pacific/Bougainville, GMT+11:00",
+ value: "Pacific/Bougainville",
+ },
+ {
+ label: "Pacific/Chatham, GMT+12:45",
+ value: "Pacific/Chatham",
+ },
+ {
+ label: "Pacific/Chuuk, GMT+10:00",
+ value: "Pacific/Chuuk",
+ },
+ {
+ label: "Pacific/Easter, GMT-06:00",
+ value: "Pacific/Easter",
+ },
+ {
+ label: "Pacific/Efate, GMT+11:00",
+ value: "Pacific/Efate",
+ },
+ {
+ label: "Pacific/Enderbury, GMT+13:00",
+ value: "Pacific/Enderbury",
+ },
+ {
+ label: "Pacific/Fakaofo, GMT+13:00",
+ value: "Pacific/Fakaofo",
+ },
+ {
+ label: "Pacific/Fiji, GMT+12:00",
+ value: "Pacific/Fiji",
+ },
+ {
+ label: "Pacific/Funafuti, GMT+12:00",
+ value: "Pacific/Funafuti",
+ },
+ {
+ label: "Pacific/Galapagos, GMT-06:00",
+ value: "Pacific/Galapagos",
+ },
+ {
+ label: "Pacific/Gambier, GMT-09:00",
+ value: "Pacific/Gambier",
+ },
+ {
+ label: "Pacific/Guadalcanal, GMT+11:00",
+ value: "Pacific/Guadalcanal",
+ },
+ {
+ label: "Pacific/Guam, GMT+10:00",
+ value: "Pacific/Guam",
+ },
+ {
+ label: "Pacific/Honolulu, GMT-10:00",
+ value: "Pacific/Honolulu",
+ },
+ {
+ label: "Pacific/Johnston, GMT-10:00",
+ value: "Pacific/Johnston",
+ },
+ {
+ label: "Pacific/Kanton, GMT+13:00",
+ value: "Pacific/Kanton",
+ },
+ {
+ label: "Pacific/Kiritimati, GMT+14:00",
+ value: "Pacific/Kiritimati",
+ },
+ {
+ label: "Pacific/Kosrae, GMT+11:00",
+ value: "Pacific/Kosrae",
+ },
+ {
+ label: "Pacific/Kwajalein, GMT+12:00",
+ value: "Pacific/Kwajalein",
+ },
+ {
+ label: "Pacific/Majuro, GMT+12:00",
+ value: "Pacific/Majuro",
+ },
+ {
+ label: "Pacific/Marquesas, GMT-09:30",
+ value: "Pacific/Marquesas",
+ },
+ {
+ label: "Pacific/Midway, GMT-11:00",
+ value: "Pacific/Midway",
+ },
+ {
+ label: "Pacific/Nauru, GMT+12:00",
+ value: "Pacific/Nauru",
+ },
+ {
+ label: "Pacific/Niue, GMT-11:00",
+ value: "Pacific/Niue",
+ },
+ {
+ label: "Pacific/Norfolk, GMT+11:00",
+ value: "Pacific/Norfolk",
+ },
+ {
+ label: "Pacific/Noumea, GMT+11:00",
+ value: "Pacific/Noumea",
+ },
+ {
+ label: "Pacific/Pago_Pago, GMT-11:00",
+ value: "Pacific/Pago_Pago",
+ },
+ {
+ label: "Pacific/Palau, GMT+09:00",
+ value: "Pacific/Palau",
+ },
+ {
+ label: "Pacific/Pitcairn, GMT-08:00",
+ value: "Pacific/Pitcairn",
+ },
+ {
+ label: "Pacific/Pohnpei, GMT+11:00",
+ value: "Pacific/Pohnpei",
+ },
+ {
+ label: "Pacific/Ponape, GMT+11:00",
+ value: "Pacific/Ponape",
+ },
+ {
+ label: "Pacific/Port_Moresby, GMT+10:00",
+ value: "Pacific/Port_Moresby",
+ },
+ {
+ label: "Pacific/Rarotonga, GMT-10:00",
+ value: "Pacific/Rarotonga",
+ },
+ {
+ label: "Pacific/Saipan, GMT+10:00",
+ value: "Pacific/Saipan",
+ },
+ {
+ label: "Pacific/Samoa, GMT-11:00",
+ value: "Pacific/Samoa",
+ },
+ {
+ label: "Pacific/Tahiti, GMT-10:00",
+ value: "Pacific/Tahiti",
+ },
+ {
+ label: "Pacific/Tarawa, GMT+12:00",
+ value: "Pacific/Tarawa",
+ },
+ {
+ label: "Pacific/Tongatapu, GMT+13:00",
+ value: "Pacific/Tongatapu",
+ },
+ {
+ label: "Pacific/Truk, GMT+10:00",
+ value: "Pacific/Truk",
+ },
+ {
+ label: "Pacific/Wake, GMT+12:00",
+ value: "Pacific/Wake",
+ },
+ {
+ label: "Pacific/Wallis, GMT+12:00",
+ value: "Pacific/Wallis",
+ },
+ {
+ label: "Pacific/Yap, GMT+10:00",
+ value: "Pacific/Yap",
+ },
+ {
+ label: "Poland, GMT+02:00",
+ value: "Poland",
+ },
+ {
+ label: "Portugal, GMT+01:00",
+ value: "Portugal",
+ },
+ {
+ label: "ROC, GMT+08:00",
+ value: "ROC",
+ },
+ {
+ label: "ROK, GMT+09:00",
+ value: "ROK",
+ },
+ {
+ label: "Singapore, GMT+08:00",
+ value: "Singapore",
+ },
+ {
+ label: "Turkey, GMT+03:00",
+ value: "Turkey",
+ },
+ {
+ label: "UCT, GMT",
+ value: "UCT",
+ },
+ {
+ label: "US/Alaska, GMT-08:00",
+ value: "US/Alaska",
+ },
+ {
+ label: "US/Aleutian, GMT-09:00",
+ value: "US/Aleutian",
+ },
+ {
+ label: "US/Arizona, GMT-07:00",
+ value: "US/Arizona",
+ },
+ {
+ label: "US/Central, GMT-05:00",
+ value: "US/Central",
+ },
+ {
+ label: "US/East-Indiana, GMT-04:00",
+ value: "US/East-Indiana",
+ },
+ {
+ label: "US/Eastern, GMT-04:00",
+ value: "US/Eastern",
+ },
+ {
+ label: "US/Hawaii, GMT-10:00",
+ value: "US/Hawaii",
+ },
+ {
+ label: "US/Indiana-Starke, GMT-05:00",
+ value: "US/Indiana-Starke",
+ },
+ {
+ label: "US/Michigan, GMT-04:00",
+ value: "US/Michigan",
+ },
+ {
+ label: "US/Mountain, GMT-06:00",
+ value: "US/Mountain",
+ },
+ {
+ label: "US/Pacific, GMT-07:00",
+ value: "US/Pacific",
+ },
+ {
+ label: "US/Samoa, GMT-11:00",
+ value: "US/Samoa",
+ },
+ {
+ label: "UTC, GMT",
+ value: "UTC",
+ },
+ {
+ label: "Universal, GMT",
+ value: "Universal",
+ },
+ {
+ label: "W-SU, GMT+03:00",
+ value: "W-SU",
+ },
+ {
+ label: "WET, GMT+01:00",
+ value: "WET",
+ },
+ {
+ label: "Zulu, GMT",
+ value: "Zulu",
+ },
+];
diff --git a/apps/app/constants/workspace.ts b/web/constants/workspace.ts
similarity index 100%
rename from apps/app/constants/workspace.ts
rename to web/constants/workspace.ts
diff --git a/apps/app/contexts/inbox-view-context.tsx b/web/contexts/inbox-view-context.tsx
similarity index 100%
rename from apps/app/contexts/inbox-view-context.tsx
rename to web/contexts/inbox-view-context.tsx
diff --git a/apps/app/contexts/issue-view.context.tsx b/web/contexts/issue-view.context.tsx
similarity index 99%
rename from apps/app/contexts/issue-view.context.tsx
rename to web/contexts/issue-view.context.tsx
index 530dbee4e..134e0d8f6 100644
--- a/apps/app/contexts/issue-view.context.tsx
+++ b/web/contexts/issue-view.context.tsx
@@ -94,6 +94,7 @@ export const initialState: StateType = {
state_group: null,
subscriber: null,
created_by: null,
+ start_date: null,
target_date: null,
},
};
diff --git a/apps/app/contexts/profile-issues-context.tsx b/web/contexts/profile-issues-context.tsx
similarity index 93%
rename from apps/app/contexts/profile-issues-context.tsx
rename to web/contexts/profile-issues-context.tsx
index 34540acb7..db54f2470 100644
--- a/apps/app/contexts/profile-issues-context.tsx
+++ b/web/contexts/profile-issues-context.tsx
@@ -72,6 +72,7 @@ export const initialState: StateType = {
state_group: null,
subscriber: null,
created_by: null,
+ start_date: null,
target_date: null,
},
properties: {
@@ -196,23 +197,26 @@ export const ProfileIssuesContextProvider: React.FC<{ children: React.ReactNode
}) => {
const [state, dispatch] = useReducer(reducer, initialState);
- const setIssueView = useCallback((property: TIssueViewOptions) => {
- dispatch({
- type: "SET_ISSUE_VIEW",
- payload: {
- issueView: property,
- },
- });
-
- if (property === "kanban") {
+ const setIssueView = useCallback(
+ (property: TIssueViewOptions) => {
dispatch({
- type: "SET_GROUP_BY_PROPERTY",
+ type: "SET_ISSUE_VIEW",
payload: {
- groupByProperty: "state_detail.group",
+ issueView: property,
},
});
- }
- }, []);
+
+ if (property === "kanban" && state.groupByProperty === null) {
+ dispatch({
+ type: "SET_GROUP_BY_PROPERTY",
+ payload: {
+ groupByProperty: "state_detail.group",
+ },
+ });
+ }
+ },
+ [state]
+ );
const setGroupByProperty = useCallback((property: TIssueGroupByOptions) => {
dispatch({
diff --git a/apps/app/contexts/project-member.context.tsx b/web/contexts/project-member.context.tsx
similarity index 100%
rename from apps/app/contexts/project-member.context.tsx
rename to web/contexts/project-member.context.tsx
diff --git a/apps/app/contexts/theme.context.tsx b/web/contexts/theme.context.tsx
similarity index 100%
rename from apps/app/contexts/theme.context.tsx
rename to web/contexts/theme.context.tsx
diff --git a/apps/app/contexts/toast.context.tsx b/web/contexts/toast.context.tsx
similarity index 100%
rename from apps/app/contexts/toast.context.tsx
rename to web/contexts/toast.context.tsx
diff --git a/apps/app/contexts/user-notification-context.tsx b/web/contexts/user-notification-context.tsx
similarity index 100%
rename from apps/app/contexts/user-notification-context.tsx
rename to web/contexts/user-notification-context.tsx
diff --git a/apps/app/contexts/user.context.tsx b/web/contexts/user.context.tsx
similarity index 100%
rename from apps/app/contexts/user.context.tsx
rename to web/contexts/user.context.tsx
diff --git a/apps/app/contexts/workspace-member.context.tsx b/web/contexts/workspace-member.context.tsx
similarity index 100%
rename from apps/app/contexts/workspace-member.context.tsx
rename to web/contexts/workspace-member.context.tsx
diff --git a/apps/app/contexts/workspace.context.tsx b/web/contexts/workspace.context.tsx
similarity index 100%
rename from apps/app/contexts/workspace.context.tsx
rename to web/contexts/workspace.context.tsx
diff --git a/apps/app/google.d.ts b/web/google.d.ts
similarity index 100%
rename from apps/app/google.d.ts
rename to web/google.d.ts
diff --git a/apps/app/helpers/analytics.helper.ts b/web/helpers/analytics.helper.ts
similarity index 100%
rename from apps/app/helpers/analytics.helper.ts
rename to web/helpers/analytics.helper.ts
diff --git a/apps/app/helpers/array.helper.ts b/web/helpers/array.helper.ts
similarity index 100%
rename from apps/app/helpers/array.helper.ts
rename to web/helpers/array.helper.ts
diff --git a/apps/app/helpers/attachment.helper.ts b/web/helpers/attachment.helper.ts
similarity index 100%
rename from apps/app/helpers/attachment.helper.ts
rename to web/helpers/attachment.helper.ts
diff --git a/apps/app/helpers/calendar.helper.ts b/web/helpers/calendar.helper.ts
similarity index 100%
rename from apps/app/helpers/calendar.helper.ts
rename to web/helpers/calendar.helper.ts
diff --git a/apps/app/helpers/color.helper.ts b/web/helpers/color.helper.ts
similarity index 100%
rename from apps/app/helpers/color.helper.ts
rename to web/helpers/color.helper.ts
diff --git a/apps/app/helpers/common.helper.ts b/web/helpers/common.helper.ts
similarity index 100%
rename from apps/app/helpers/common.helper.ts
rename to web/helpers/common.helper.ts
diff --git a/apps/app/helpers/date-time.helper.ts b/web/helpers/date-time.helper.ts
similarity index 92%
rename from apps/app/helpers/date-time.helper.ts
rename to web/helpers/date-time.helper.ts
index a98f08cb7..39a68bf3b 100644
--- a/apps/app/helpers/date-time.helper.ts
+++ b/web/helpers/date-time.helper.ts
@@ -374,3 +374,32 @@ export const getAllTimeIn30MinutesInterval = (): Array<{
{ label: "11:00", value: "11:00" },
{ label: "11:30", value: "11:30" },
];
+
+/**
+ * @returns {number} total number of days in range
+ * @description Returns total number of days in range
+ * @param {string} startDate
+ * @param {string} endDate
+ * @param {boolean} inclusive
+ * @example checkIfStringIsDate("2021-01-01", "2021-01-08") // 8
+ */
+
+export const findTotalDaysInRange = (
+ startDate: Date | string,
+ endDate: Date | string,
+ inclusive: boolean
+): number => {
+ if (!startDate || !endDate) return 0;
+
+ startDate = new Date(startDate);
+ endDate = new Date(endDate);
+
+ // find number of days between startDate and endDate
+ const diffInTime = endDate.getTime() - startDate.getTime();
+ const diffInDays = diffInTime / (1000 * 3600 * 24);
+
+ // if inclusive is true, add 1 to diffInDays
+ if (inclusive) return diffInDays + 1;
+
+ return diffInDays;
+};
diff --git a/web/helpers/emoji.helper.tsx b/web/helpers/emoji.helper.tsx
new file mode 100644
index 000000000..7c9f3cfcb
--- /dev/null
+++ b/web/helpers/emoji.helper.tsx
@@ -0,0 +1,56 @@
+export const getRandomEmoji = () => {
+ const emojis = [
+ "8986",
+ "9200",
+ "128204",
+ "127773",
+ "127891",
+ "127947",
+ "128076",
+ "128077",
+ "128187",
+ "128188",
+ "128512",
+ "128522",
+ "128578",
+ ];
+
+ return emojis[Math.floor(Math.random() * emojis.length)];
+};
+
+export const renderEmoji = (
+ emoji:
+ | string
+ | {
+ name: string;
+ color: string;
+ }
+) => {
+ if (!emoji) return;
+
+ if (typeof emoji === "object")
+ return (
+
+ {emoji.name}
+
+ );
+ else return isNaN(parseInt(emoji)) ? emoji : String.fromCodePoint(parseInt(emoji));
+};
+
+export const groupReactions: (reactions: any[], key: string) => { [key: string]: any[] } = (
+ reactions: any,
+ key: string
+) => {
+ const groupedReactions = reactions.reduce(
+ (acc: any, reaction: any) => {
+ if (!acc[reaction[key]]) {
+ acc[reaction[key]] = [];
+ }
+ acc[reaction[key]].push(reaction);
+ return acc;
+ },
+ {} as { [key: string]: any[] }
+ );
+
+ return groupedReactions;
+};
diff --git a/apps/app/helpers/graph.helper.ts b/web/helpers/graph.helper.ts
similarity index 100%
rename from apps/app/helpers/graph.helper.ts
rename to web/helpers/graph.helper.ts
diff --git a/apps/app/helpers/state.helper.ts b/web/helpers/state.helper.ts
similarity index 100%
rename from apps/app/helpers/state.helper.ts
rename to web/helpers/state.helper.ts
diff --git a/apps/app/helpers/string.helper.ts b/web/helpers/string.helper.ts
similarity index 100%
rename from apps/app/helpers/string.helper.ts
rename to web/helpers/string.helper.ts
diff --git a/apps/app/helpers/theme.helper.ts b/web/helpers/theme.helper.ts
similarity index 100%
rename from apps/app/helpers/theme.helper.ts
rename to web/helpers/theme.helper.ts
diff --git a/apps/app/hooks/gantt-chart/cycle-issues-view.tsx b/web/hooks/gantt-chart/cycle-issues-view.tsx
similarity index 65%
rename from apps/app/hooks/gantt-chart/cycle-issues-view.tsx
rename to web/hooks/gantt-chart/cycle-issues-view.tsx
index 25baf0d3e..8d32d5e4b 100644
--- a/apps/app/hooks/gantt-chart/cycle-issues-view.tsx
+++ b/web/hooks/gantt-chart/cycle-issues-view.tsx
@@ -18,7 +18,14 @@ const useGanttChartCycleIssues = (
order_by: orderBy,
type: filters?.type ? filters?.type : undefined,
sub_issue: showSubIssues,
- start_target_date: true,
+ assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
+ state: filters?.state ? filters?.state.join(",") : undefined,
+ priority: filters?.priority ? filters?.priority.join(",") : undefined,
+ labels: filters?.labels ? filters?.labels.join(",") : undefined,
+ created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
+ start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
+ target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
+ start_target_date: true, // to fetch only issues with a start and target date
};
// all issues under the workspace and project
diff --git a/apps/app/hooks/gantt-chart/issue-view.tsx b/web/hooks/gantt-chart/issue-view.tsx
similarity index 62%
rename from apps/app/hooks/gantt-chart/issue-view.tsx
rename to web/hooks/gantt-chart/issue-view.tsx
index c7ffa0ffe..ba9465114 100644
--- a/apps/app/hooks/gantt-chart/issue-view.tsx
+++ b/web/hooks/gantt-chart/issue-view.tsx
@@ -14,7 +14,14 @@ const useGanttChartIssues = (workspaceSlug: string | undefined, projectId: strin
order_by: orderBy,
type: filters?.type ? filters?.type : undefined,
sub_issue: showSubIssues,
- start_target_date: true,
+ assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
+ state: filters?.state ? filters?.state.join(",") : undefined,
+ priority: filters?.priority ? filters?.priority.join(",") : undefined,
+ labels: filters?.labels ? filters?.labels.join(",") : undefined,
+ created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
+ start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
+ target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
+ start_target_date: true, // to fetch only issues with a start and target date
};
// all issues under the workspace and project
diff --git a/apps/app/hooks/gantt-chart/module-issues-view.tsx b/web/hooks/gantt-chart/module-issues-view.tsx
similarity index 65%
rename from apps/app/hooks/gantt-chart/module-issues-view.tsx
rename to web/hooks/gantt-chart/module-issues-view.tsx
index ca686f4e0..3d88cab4f 100644
--- a/apps/app/hooks/gantt-chart/module-issues-view.tsx
+++ b/web/hooks/gantt-chart/module-issues-view.tsx
@@ -18,7 +18,14 @@ const useGanttChartModuleIssues = (
order_by: orderBy,
type: filters?.type ? filters?.type : undefined,
sub_issue: showSubIssues,
- start_target_date: true,
+ assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
+ state: filters?.state ? filters?.state.join(",") : undefined,
+ priority: filters?.priority ? filters?.priority.join(",") : undefined,
+ labels: filters?.labels ? filters?.labels.join(",") : undefined,
+ created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
+ start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
+ target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
+ start_target_date: true, // to fetch only issues with a start and target date
};
// all issues under the workspace and project
diff --git a/apps/app/hooks/gantt-chart/view-issues-view.tsx b/web/hooks/gantt-chart/view-issues-view.tsx
similarity index 90%
rename from apps/app/hooks/gantt-chart/view-issues-view.tsx
rename to web/hooks/gantt-chart/view-issues-view.tsx
index b66b35128..8e0bc496b 100644
--- a/apps/app/hooks/gantt-chart/view-issues-view.tsx
+++ b/web/hooks/gantt-chart/view-issues-view.tsx
@@ -18,7 +18,7 @@ const useGanttChartViewIssues = (
// all issues under the view
const { data: ganttIssues, mutate: mutateGanttIssues } = useSWR(
workspaceSlug && projectId && viewId
- ? VIEW_ISSUES(viewId.toString(), { ...viewGanttParams, start_target_date: true })
+ ? VIEW_ISSUES(viewId.toString(), { ...viewGanttParams, order_by, start_target_date: true })
: null,
workspaceSlug && projectId && viewId
? () =>
diff --git a/apps/app/hooks/my-issues/use-my-issues-filter.tsx b/web/hooks/my-issues/use-my-issues-filter.tsx
similarity index 99%
rename from apps/app/hooks/my-issues/use-my-issues-filter.tsx
rename to web/hooks/my-issues/use-my-issues-filter.tsx
index 2ca77cd55..2de72918f 100644
--- a/apps/app/hooks/my-issues/use-my-issues-filter.tsx
+++ b/web/hooks/my-issues/use-my-issues-filter.tsx
@@ -26,6 +26,7 @@ const initialValues: IWorkspaceViewProps = {
priority: null,
state_group: null,
subscriber: null,
+ start_date: null,
target_date: null,
type: null,
},
diff --git a/apps/app/hooks/my-issues/use-my-issues.tsx b/web/hooks/my-issues/use-my-issues.tsx
similarity index 96%
rename from apps/app/hooks/my-issues/use-my-issues.tsx
rename to web/hooks/my-issues/use-my-issues.tsx
index aae05bc84..2cb97ecd0 100644
--- a/apps/app/hooks/my-issues/use-my-issues.tsx
+++ b/web/hooks/my-issues/use-my-issues.tsx
@@ -27,6 +27,7 @@ const useMyIssues = (workspaceSlug: string | undefined) => {
priority: filters?.priority ? filters?.priority.join(",") : undefined,
state_group: filters?.state_group ? filters?.state_group.join(",") : undefined,
subscriber: filters?.subscriber ? filters?.subscriber.join(",") : undefined,
+ start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
type: filters?.type ? filters?.type : undefined,
};
diff --git a/apps/app/hooks/use-calendar-issues-view.tsx b/web/hooks/use-calendar-issues-view.tsx
similarity index 97%
rename from apps/app/hooks/use-calendar-issues-view.tsx
rename to web/hooks/use-calendar-issues-view.tsx
index d8daae922..d69864c2d 100644
--- a/apps/app/hooks/use-calendar-issues-view.tsx
+++ b/web/hooks/use-calendar-issues-view.tsx
@@ -42,6 +42,7 @@ const useCalendarIssuesView = () => {
type: filters?.type ? filters?.type : undefined,
labels: filters?.labels ? filters?.labels.join(",") : undefined,
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
+ start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
target_date: calendarDateRange,
};
diff --git a/apps/app/hooks/use-comment-reaction.tsx b/web/hooks/use-comment-reaction.tsx
similarity index 100%
rename from apps/app/hooks/use-comment-reaction.tsx
rename to web/hooks/use-comment-reaction.tsx
diff --git a/apps/app/hooks/use-debounce.tsx b/web/hooks/use-debounce.tsx
similarity index 100%
rename from apps/app/hooks/use-debounce.tsx
rename to web/hooks/use-debounce.tsx
diff --git a/apps/app/hooks/use-estimate-option.tsx b/web/hooks/use-estimate-option.tsx
similarity index 100%
rename from apps/app/hooks/use-estimate-option.tsx
rename to web/hooks/use-estimate-option.tsx
diff --git a/apps/app/hooks/use-inbox-view.tsx b/web/hooks/use-inbox-view.tsx
similarity index 100%
rename from apps/app/hooks/use-inbox-view.tsx
rename to web/hooks/use-inbox-view.tsx
diff --git a/apps/app/hooks/use-integration-popup.tsx b/web/hooks/use-integration-popup.tsx
similarity index 100%
rename from apps/app/hooks/use-integration-popup.tsx
rename to web/hooks/use-integration-popup.tsx
diff --git a/apps/app/hooks/use-issue-notification-subscription.tsx b/web/hooks/use-issue-notification-subscription.tsx
similarity index 100%
rename from apps/app/hooks/use-issue-notification-subscription.tsx
rename to web/hooks/use-issue-notification-subscription.tsx
diff --git a/apps/app/hooks/use-issue-properties.tsx b/web/hooks/use-issue-properties.tsx
similarity index 98%
rename from apps/app/hooks/use-issue-properties.tsx
rename to web/hooks/use-issue-properties.tsx
index d5d1072ce..6f4f093e0 100644
--- a/apps/app/hooks/use-issue-properties.tsx
+++ b/web/hooks/use-issue-properties.tsx
@@ -68,7 +68,7 @@ const useIssuesProperties = (workspaceSlug?: string, projectId?: string) => {
({
...prev,
properties: { ...prev?.properties, [key]: !prev?.properties?.[key] },
- } as IssuePriorities),
+ }) as IssuePriorities,
false
);
if (Object.keys(issueProperties).length > 0) {
diff --git a/apps/app/hooks/use-issue-reaction.tsx b/web/hooks/use-issue-reaction.tsx
similarity index 100%
rename from apps/app/hooks/use-issue-reaction.tsx
rename to web/hooks/use-issue-reaction.tsx
diff --git a/apps/app/hooks/use-issues-view.tsx b/web/hooks/use-issues-view.tsx
similarity index 98%
rename from apps/app/hooks/use-issues-view.tsx
rename to web/hooks/use-issues-view.tsx
index 3d702abea..767dbdb4c 100644
--- a/apps/app/hooks/use-issues-view.tsx
+++ b/web/hooks/use-issues-view.tsx
@@ -58,6 +58,7 @@ const useIssuesView = () => {
type: filters?.type ? filters?.type : undefined,
labels: filters?.labels ? filters?.labels.join(",") : undefined,
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
+ start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
sub_issue: showSubIssues,
};
diff --git a/apps/app/hooks/use-local-storage.tsx b/web/hooks/use-local-storage.tsx
similarity index 100%
rename from apps/app/hooks/use-local-storage.tsx
rename to web/hooks/use-local-storage.tsx
diff --git a/apps/app/hooks/use-outside-click-detector.tsx b/web/hooks/use-outside-click-detector.tsx
similarity index 100%
rename from apps/app/hooks/use-outside-click-detector.tsx
rename to web/hooks/use-outside-click-detector.tsx
diff --git a/apps/app/hooks/use-profile-issues.tsx b/web/hooks/use-profile-issues.tsx
similarity index 88%
rename from apps/app/hooks/use-profile-issues.tsx
rename to web/hooks/use-profile-issues.tsx
index 7e7f24372..c232199bc 100644
--- a/apps/app/hooks/use-profile-issues.tsx
+++ b/web/hooks/use-profile-issues.tsx
@@ -44,6 +44,7 @@ const useProfileIssues = (workspaceSlug: string | undefined, userId: string | un
order_by: orderBy,
priority: filters?.priority ? filters?.priority.join(",") : undefined,
state_group: filters?.state_group ? filters?.state_group.join(",") : undefined,
+ start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
type: filters?.type ? filters?.type : undefined,
subscriber: filters?.subscriber ? filters?.subscriber.join(",") : undefined,
@@ -70,8 +71,23 @@ const useProfileIssues = (workspaceSlug: string | undefined, userId: string | un
allIssues: userProfileIssues,
};
+ if (groupByProperty === "state_detail.group") {
+ return userProfileIssues
+ ? Object.assign(
+ {
+ backlog: [],
+ unstarted: [],
+ started: [],
+ completed: [],
+ cancelled: [],
+ },
+ userProfileIssues
+ )
+ : undefined;
+ }
+
return userProfileIssues;
- }, [userProfileIssues]);
+ }, [groupByProperty, userProfileIssues]);
useEffect(() => {
if (!userId || !filters) return;
diff --git a/apps/app/hooks/use-project-details.tsx b/web/hooks/use-project-details.tsx
similarity index 100%
rename from apps/app/hooks/use-project-details.tsx
rename to web/hooks/use-project-details.tsx
diff --git a/apps/app/hooks/use-project-members.tsx b/web/hooks/use-project-members.tsx
similarity index 100%
rename from apps/app/hooks/use-project-members.tsx
rename to web/hooks/use-project-members.tsx
diff --git a/apps/app/hooks/use-projects.tsx b/web/hooks/use-projects.tsx
similarity index 100%
rename from apps/app/hooks/use-projects.tsx
rename to web/hooks/use-projects.tsx
diff --git a/apps/app/hooks/use-reload-confirmation.tsx b/web/hooks/use-reload-confirmation.tsx
similarity index 100%
rename from apps/app/hooks/use-reload-confirmation.tsx
rename to web/hooks/use-reload-confirmation.tsx
diff --git a/apps/app/hooks/use-spreadsheet-issues-view.tsx b/web/hooks/use-spreadsheet-issues-view.tsx
similarity index 81%
rename from apps/app/hooks/use-spreadsheet-issues-view.tsx
rename to web/hooks/use-spreadsheet-issues-view.tsx
index 797ddf7d6..145313dac 100644
--- a/apps/app/hooks/use-spreadsheet-issues-view.tsx
+++ b/web/hooks/use-spreadsheet-issues-view.tsx
@@ -43,10 +43,12 @@ const useSpreadsheetIssuesView = () => {
type: filters?.type ? filters?.type : undefined,
labels: filters?.labels ? filters?.labels.join(",") : undefined,
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
+ start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
+ target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
sub_issue: "false",
};
- const { data: projectSpreadsheetIssues } = useSWR(
+ const { data: projectSpreadsheetIssues, mutate: mutateProjectSpreadsheetIssues } = useSWR(
workspaceSlug && projectId
? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params)
: null,
@@ -56,7 +58,7 @@ const useSpreadsheetIssuesView = () => {
: null
);
- const { data: cycleSpreadsheetIssues } = useSWR(
+ const { data: cycleSpreadsheetIssues, mutate: mutateCycleSpreadsheetIssues } = useSWR(
workspaceSlug && projectId && cycleId
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params)
: null,
@@ -71,7 +73,7 @@ const useSpreadsheetIssuesView = () => {
: null
);
- const { data: moduleSpreadsheetIssues } = useSWR(
+ const { data: moduleSpreadsheetIssues, mutate: mutateModuleSpreadsheetIssues } = useSWR(
workspaceSlug && projectId && moduleId
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params)
: null,
@@ -86,7 +88,7 @@ const useSpreadsheetIssuesView = () => {
: null
);
- const { data: viewSpreadsheetIssues } = useSWR(
+ const { data: viewSpreadsheetIssues, mutate: mutateViewSpreadsheetIssues } = useSWR(
workspaceSlug && projectId && viewId && params ? VIEW_ISSUES(viewId.toString(), params) : null,
workspaceSlug && projectId && viewId && params
? () =>
@@ -104,6 +106,13 @@ const useSpreadsheetIssuesView = () => {
return {
issueView,
+ mutateIssues: cycleId
+ ? mutateCycleSpreadsheetIssues
+ : moduleId
+ ? mutateModuleSpreadsheetIssues
+ : viewId
+ ? mutateViewSpreadsheetIssues
+ : mutateProjectSpreadsheetIssues,
spreadsheetIssues: spreadsheetIssues ?? [],
orderBy,
setOrderBy,
diff --git a/apps/app/hooks/use-sub-issue.tsx b/web/hooks/use-sub-issue.tsx
similarity index 100%
rename from apps/app/hooks/use-sub-issue.tsx
rename to web/hooks/use-sub-issue.tsx
diff --git a/apps/app/hooks/use-theme.tsx b/web/hooks/use-theme.tsx
similarity index 100%
rename from apps/app/hooks/use-theme.tsx
rename to web/hooks/use-theme.tsx
diff --git a/web/hooks/use-timer.tsx b/web/hooks/use-timer.tsx
new file mode 100644
index 000000000..1edf4931a
--- /dev/null
+++ b/web/hooks/use-timer.tsx
@@ -0,0 +1,19 @@
+import { useState, useEffect } from "react";
+
+const TIMER = 30;
+
+const useTimer = (initialValue: number = TIMER) => {
+ const [timer, setTimer] = useState(initialValue);
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setTimer((prev) => prev - 1);
+ }, 1000);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return { timer, setTimer };
+};
+
+export default useTimer;
diff --git a/web/hooks/use-toast.tsx b/web/hooks/use-toast.tsx
new file mode 100644
index 000000000..6de3c104c
--- /dev/null
+++ b/web/hooks/use-toast.tsx
@@ -0,0 +1,9 @@
+import { useContext } from "react";
+import { toastContext } from "contexts/toast.context";
+
+const useToast = () => {
+ const toastContextData = useContext(toastContext);
+ return toastContextData;
+};
+
+export default useToast;
diff --git a/apps/app/hooks/use-user-auth.tsx b/web/hooks/use-user-auth.tsx
similarity index 100%
rename from apps/app/hooks/use-user-auth.tsx
rename to web/hooks/use-user-auth.tsx
diff --git a/apps/app/hooks/use-user-notifications.tsx b/web/hooks/use-user-notifications.tsx
similarity index 90%
rename from apps/app/hooks/use-user-notifications.tsx
rename to web/hooks/use-user-notifications.tsx
index fe539d805..5ddc9ddf5 100644
--- a/apps/app/hooks/use-user-notifications.tsx
+++ b/web/hooks/use-user-notifications.tsx
@@ -9,11 +9,14 @@ import useSWRInfinite from "swr/infinite";
// services
import userNotificationServices from "services/notifications.service";
+// hooks
+import useToast from "./use-toast";
+
// fetch-keys
import { UNREAD_NOTIFICATIONS_COUNT, getPaginatedNotificationKey } from "constants/fetch-keys";
// type
-import type { NotificationType, NotificationCount } from "types";
+import type { NotificationType, NotificationCount, IMarkAllAsReadPayload } from "types";
const PER_PAGE = 30;
@@ -21,6 +24,8 @@ const useUserNotification = () => {
const router = useRouter();
const { workspaceSlug } = router.query;
+ const { setToastAlert } = useToast();
+
const [snoozed, setSnoozed] = useState(false);
const [archived, setArchived] = useState(false);
const [readNotification, setReadNotification] = useState(false);
@@ -274,6 +279,30 @@ const useUserNotification = () => {
}
};
+ const markAllNotificationsAsRead = async () => {
+ if (!workspaceSlug) return;
+
+ let markAsReadParams: IMarkAllAsReadPayload;
+
+ if (snoozed) markAsReadParams = { archived: false, snoozed: true };
+ else if (archived) markAsReadParams = { archived: true, snoozed: false };
+ else markAsReadParams = { archived: false, snoozed: false, type: selectedTab };
+
+ await userNotificationServices
+ .markAllNotificationsAsRead(workspaceSlug.toString(), markAsReadParams)
+ .catch(() => {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Something went wrong. Please try again.",
+ });
+ })
+ .finally(() => {
+ notificationMutate();
+ mutateNotificationCount();
+ });
+ };
+
return {
notifications,
notificationMutate,
@@ -304,6 +333,7 @@ const useUserNotification = () => {
isRefreshing,
setFetchNotifications,
markNotificationAsRead,
+ markAllNotificationsAsRead,
};
};
diff --git a/apps/app/hooks/use-user.tsx b/web/hooks/use-user.tsx
similarity index 100%
rename from apps/app/hooks/use-user.tsx
rename to web/hooks/use-user.tsx
diff --git a/apps/app/hooks/use-workspace-details.tsx b/web/hooks/use-workspace-details.tsx
similarity index 100%
rename from apps/app/hooks/use-workspace-details.tsx
rename to web/hooks/use-workspace-details.tsx
diff --git a/apps/app/hooks/use-workspace-members.tsx b/web/hooks/use-workspace-members.tsx
similarity index 100%
rename from apps/app/hooks/use-workspace-members.tsx
rename to web/hooks/use-workspace-members.tsx
diff --git a/apps/app/hooks/use-workspaces.tsx b/web/hooks/use-workspaces.tsx
similarity index 100%
rename from apps/app/hooks/use-workspaces.tsx
rename to web/hooks/use-workspaces.tsx
diff --git a/apps/app/layouts/app-layout/app-header.tsx b/web/layouts/app-layout/app-header.tsx
similarity index 100%
rename from apps/app/layouts/app-layout/app-header.tsx
rename to web/layouts/app-layout/app-header.tsx
diff --git a/apps/app/layouts/app-layout/app-sidebar.tsx b/web/layouts/app-layout/app-sidebar.tsx
similarity index 88%
rename from apps/app/layouts/app-layout/app-sidebar.tsx
rename to web/layouts/app-layout/app-sidebar.tsx
index 9290c00c6..03ac72387 100644
--- a/apps/app/layouts/app-layout/app-sidebar.tsx
+++ b/web/layouts/app-layout/app-sidebar.tsx
@@ -9,6 +9,7 @@ import {
} from "components/workspace";
import { ProjectSidebarList } from "components/project";
import { PublishProjectModal } from "components/project/publish-project/modal";
+import { ConfirmProjectLeaveModal } from "components/project/confirm-project-leave-modal";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store
@@ -38,7 +39,10 @@ const Sidebar: React.FC = observer(({ toggleSidebar, setToggleSide
+ {/* publish project modal */}
+ {/* project leave modal */}
+
);
});
diff --git a/apps/app/layouts/auth-layout/index.ts b/web/layouts/auth-layout/index.ts
similarity index 100%
rename from apps/app/layouts/auth-layout/index.ts
rename to web/layouts/auth-layout/index.ts
diff --git a/apps/app/layouts/auth-layout/project-authorization-wrapper.tsx b/web/layouts/auth-layout/project-authorization-wrapper.tsx
similarity index 100%
rename from apps/app/layouts/auth-layout/project-authorization-wrapper.tsx
rename to web/layouts/auth-layout/project-authorization-wrapper.tsx
diff --git a/apps/app/layouts/auth-layout/user-authorization-wrapper.tsx b/web/layouts/auth-layout/user-authorization-wrapper.tsx
similarity index 100%
rename from apps/app/layouts/auth-layout/user-authorization-wrapper.tsx
rename to web/layouts/auth-layout/user-authorization-wrapper.tsx
diff --git a/apps/app/layouts/auth-layout/workspace-authorization-wrapper.tsx b/web/layouts/auth-layout/workspace-authorization-wrapper.tsx
similarity index 100%
rename from apps/app/layouts/auth-layout/workspace-authorization-wrapper.tsx
rename to web/layouts/auth-layout/workspace-authorization-wrapper.tsx
diff --git a/apps/app/layouts/default-layout/index.tsx b/web/layouts/default-layout/index.tsx
similarity index 100%
rename from apps/app/layouts/default-layout/index.tsx
rename to web/layouts/default-layout/index.tsx
diff --git a/apps/app/layouts/profile-layout.tsx b/web/layouts/profile-layout.tsx
similarity index 100%
rename from apps/app/layouts/profile-layout.tsx
rename to web/layouts/profile-layout.tsx
diff --git a/apps/app/layouts/settings-navbar.tsx b/web/layouts/settings-navbar.tsx
similarity index 100%
rename from apps/app/layouts/settings-navbar.tsx
rename to web/layouts/settings-navbar.tsx
diff --git a/apps/app/lib/auth.ts b/web/lib/auth.ts
similarity index 100%
rename from apps/app/lib/auth.ts
rename to web/lib/auth.ts
diff --git a/apps/app/lib/cookie.ts b/web/lib/cookie.ts
similarity index 100%
rename from apps/app/lib/cookie.ts
rename to web/lib/cookie.ts
diff --git a/apps/app/lib/mobx/store-init.tsx b/web/lib/mobx/store-init.tsx
similarity index 100%
rename from apps/app/lib/mobx/store-init.tsx
rename to web/lib/mobx/store-init.tsx
diff --git a/apps/space/lib/mobx/store-provider.tsx b/web/lib/mobx/store-provider.tsx
similarity index 100%
rename from apps/space/lib/mobx/store-provider.tsx
rename to web/lib/mobx/store-provider.tsx
diff --git a/apps/app/lib/redirect.ts b/web/lib/redirect.ts
similarity index 100%
rename from apps/app/lib/redirect.ts
rename to web/lib/redirect.ts
diff --git a/apps/app/manifest.json b/web/manifest.json
similarity index 100%
rename from apps/app/manifest.json
rename to web/manifest.json
diff --git a/apps/app/next-env.d.ts b/web/next-env.d.ts
similarity index 100%
rename from apps/app/next-env.d.ts
rename to web/next-env.d.ts
diff --git a/apps/app/next.config.js b/web/next.config.js
similarity index 94%
rename from apps/app/next.config.js
rename to web/next.config.js
index 646504a54..b50066f86 100644
--- a/apps/app/next.config.js
+++ b/web/next.config.js
@@ -23,7 +23,7 @@ const nextConfig = {
output: "standalone",
experimental: {
// this includes files from the monorepo base two directories up
- outputFileTracingRoot: path.join(__dirname, "../../"),
+ outputFileTracingRoot: path.join(__dirname, "../"),
},
};
diff --git a/apps/app/package.json b/web/package.json
similarity index 92%
rename from apps/app/package.json
rename to web/package.json
index 578a95716..1743e4b6c 100644
--- a/apps/app/package.json
+++ b/web/package.json
@@ -1,5 +1,5 @@
{
- "name": "app",
+ "name": "web",
"version": "0.1.0",
"private": true,
"scripts": {
@@ -30,11 +30,16 @@
"@tiptap-pro/extension-unique-id": "^2.1.0",
"@tiptap/extension-code-block-lowlight": "^2.0.4",
"@tiptap/extension-color": "^2.0.4",
+ "@tiptap/extension-gapcursor": "^2.1.7",
"@tiptap/extension-highlight": "^2.0.4",
"@tiptap/extension-horizontal-rule": "^2.0.4",
"@tiptap/extension-image": "^2.0.4",
"@tiptap/extension-link": "^2.0.4",
"@tiptap/extension-placeholder": "^2.0.4",
+ "@tiptap/extension-table": "^2.1.6",
+ "@tiptap/extension-table-cell": "^2.1.6",
+ "@tiptap/extension-table-header": "^2.1.6",
+ "@tiptap/extension-table-row": "^2.1.6",
"@tiptap/extension-task-item": "^2.0.4",
"@tiptap/extension-task-list": "^2.0.4",
"@tiptap/extension-text-style": "^2.0.4",
diff --git a/apps/app/pages/404.tsx b/web/pages/404.tsx
similarity index 100%
rename from apps/app/pages/404.tsx
rename to web/pages/404.tsx
diff --git a/apps/app/pages/[workspaceSlug]/analytics.tsx b/web/pages/[workspaceSlug]/analytics.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/analytics.tsx
rename to web/pages/[workspaceSlug]/analytics.tsx
diff --git a/web/pages/[workspaceSlug]/editor.tsx b/web/pages/[workspaceSlug]/editor.tsx
new file mode 100644
index 000000000..73f0932ea
--- /dev/null
+++ b/web/pages/[workspaceSlug]/editor.tsx
@@ -0,0 +1,192 @@
+import { TipTapEditor } from "components/tiptap";
+import type { NextPage } from "next";
+import { useCallback, useEffect, useState } from "react";
+import { Controller, useForm } from "react-hook-form";
+import issuesService from "services/issues.service";
+import { ICurrentUserResponse, IIssue } from "types";
+import useReloadConfirmations from "hooks/use-reload-confirmation";
+import { Spinner } from "components/ui";
+import Image404 from "public/404.svg";
+import DefaultLayout from "layouts/default-layout";
+import Image from "next/image";
+import userService from "services/user.service";
+import { useRouter } from "next/router";
+
+const Editor: NextPage = () => {
+ const [user, setUser] = useState();
+ const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
+ const [isLoading, setIsLoading] = useState("false");
+ const { setShowAlert } = useReloadConfirmations();
+ const [cookies, setCookies] = useState({});
+ const [issueDetail, setIssueDetail] = useState(null);
+ const router = useRouter();
+ const { editable } = router.query;
+ const {
+ handleSubmit,
+ watch,
+ setValue,
+ control,
+ formState: { errors },
+ } = useForm({
+ defaultValues: {
+ name: "",
+ description: "",
+ description_html: "",
+ },
+ });
+
+ const getCookies = () => {
+ const cookies = document.cookie.split(";");
+ const cookieObj: any = {};
+ cookies.forEach((cookie) => {
+ const cookieArr = cookie.split("=");
+ cookieObj[cookieArr[0].trim()] = cookieArr[1];
+ });
+
+ setCookies(cookieObj);
+ return cookieObj;
+ };
+
+ const getIssueDetail = async (cookiesData: any) => {
+ try {
+ setIsLoading("true");
+ const userData = await userService.currentUser();
+ setUser(userData);
+ const issueDetail = await issuesService.retrieve(
+ cookiesData.MOBILE_slug,
+ cookiesData.MOBILE_project_id,
+ cookiesData.MOBILE_issue_id
+ );
+ setIssueDetail(issueDetail);
+ setIsLoading("false");
+ setValue("description_html", issueDetail.description_html);
+ setValue("description", issueDetail.description);
+ } catch (e) {
+ setIsLoading("error");
+ console.log(e);
+ }
+ };
+ useEffect(() => {
+ const cookiesData = getCookies();
+
+ getIssueDetail(cookiesData);
+ }, []);
+
+ useEffect(() => {
+ if (isSubmitting === "submitted") {
+ setShowAlert(false);
+ setTimeout(async () => {
+ setIsSubmitting("saved");
+ }, 2000);
+ } else if (isSubmitting === "submitting") {
+ setShowAlert(true);
+ }
+ }, [isSubmitting, setShowAlert]);
+
+ const submitChanges = async (
+ formData: Partial,
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string
+ ) => {
+ if (!workspaceSlug || !projectId || !issueId) return;
+
+ const payload: Partial = {
+ ...formData,
+ };
+
+ delete payload.blocker_issues;
+ delete payload.blocked_issues;
+ await issuesService
+ .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user)
+ .catch((e) => {
+ console.log(e);
+ });
+ };
+
+ const handleDescriptionFormSubmit = useCallback(
+ async (formData: Partial) => {
+ if (!formData) return;
+
+ await submitChanges(
+ {
+ name: issueDetail?.name ?? "",
+ description: formData.description ?? "",
+ description_html: formData.description_html ?? "
",
+ },
+ cookies.MOBILE_slug,
+ cookies.MOBILE_project_id,
+ cookies.MOBILE_issue_id
+ );
+ },
+ [submitChanges]
+ );
+
+ return isLoading === "error" ? (
+
+ ) : isLoading === "true" ? (
+
+
+
+ ) : (
+
+
(
+ {
+ setShowAlert(true);
+ setIsSubmitting("submitting");
+ onChange(description_html);
+ setValue("description", description);
+ handleSubmit(handleDescriptionFormSubmit)().finally(() => {
+ setIsSubmitting("submitted");
+ });
+ }}
+ />
+ )}
+ />
+
+ {isSubmitting === "submitting" ? "Saving..." : "Saved"}
+
+
+ );
+};
+
+const ErrorEncountered: NextPage = () => (
+
+
+
+
+
+
+
+
Oops! Something went wrong.
+
+
+
+
+);
+
+export default Editor;
diff --git a/apps/app/pages/[workspaceSlug]/index.tsx b/web/pages/[workspaceSlug]/index.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/index.tsx
rename to web/pages/[workspaceSlug]/index.tsx
diff --git a/apps/app/pages/[workspaceSlug]/me/my-issues.tsx b/web/pages/[workspaceSlug]/me/my-issues.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/me/my-issues.tsx
rename to web/pages/[workspaceSlug]/me/my-issues.tsx
diff --git a/apps/app/pages/[workspaceSlug]/me/profile/activity.tsx b/web/pages/[workspaceSlug]/me/profile/activity.tsx
similarity index 95%
rename from apps/app/pages/[workspaceSlug]/me/profile/activity.tsx
rename to web/pages/[workspaceSlug]/me/profile/activity.tsx
index 148d738c0..20f278427 100644
--- a/apps/app/pages/[workspaceSlug]/me/profile/activity.tsx
+++ b/web/pages/[workspaceSlug]/me/profile/activity.tsx
@@ -10,7 +10,7 @@ import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
import SettingsNavbar from "layouts/settings-navbar";
// components
import { ActivityIcon, ActivityMessage } from "components/core";
-import Tiptap, { ITiptapRichTextEditor } from "components/tiptap";
+import { TipTapEditor } from "components/tiptap";
// icons
import { ArrowTopRightOnSquareIcon, ChatBubbleLeftEllipsisIcon } from "@heroicons/react/24/outline";
// ui
@@ -25,18 +25,10 @@ const ProfileActivity = () => {
const router = useRouter();
const { workspaceSlug } = router.query;
- const { data: userActivity } = useSWR(USER_ACTIVITY, () => userService.getUserActivity());
-
- if (!userActivity) {
- return (
-
-
-
-
-
-
- );
- }
+ const { data: userActivity } = useSWR(
+ workspaceSlug ? USER_ACTIVITY : null,
+ workspaceSlug ? () => userService.getUserWorkspaceActivity(workspaceSlug.toString()) : null
+ );
return (
{
- {userActivity && userActivity.results.length > 0 && (
+ {userActivity ? (
{userActivity.results.map((activityItem: any, activityIdx: number) => {
@@ -105,7 +97,7 @@ const ProfileActivity = () => {
- {
})}
+ ) : (
+
+
+
+
+
+
)}
diff --git a/apps/app/pages/[workspaceSlug]/me/profile/index.tsx b/web/pages/[workspaceSlug]/me/profile/index.tsx
similarity index 88%
rename from apps/app/pages/[workspaceSlug]/me/profile/index.tsx
rename to web/pages/[workspaceSlug]/me/profile/index.tsx
index 4ea92d49d..6c0af1bc2 100644
--- a/apps/app/pages/[workspaceSlug]/me/profile/index.tsx
+++ b/web/pages/[workspaceSlug]/me/profile/index.tsx
@@ -14,7 +14,14 @@ import SettingsNavbar from "layouts/settings-navbar";
// components
import { ImagePickerPopover, ImageUploadModal } from "components/core";
// ui
-import { CustomSelect, DangerButton, Input, SecondaryButton, Spinner } from "components/ui";
+import {
+ CustomSearchSelect,
+ CustomSelect,
+ DangerButton,
+ Input,
+ SecondaryButton,
+ Spinner,
+} from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { UserIcon } from "@heroicons/react/24/outline";
@@ -23,6 +30,7 @@ import type { NextPage } from "next";
import type { IUser } from "types";
// constants
import { USER_ROLES } from "constants/workspace";
+import { TIME_ZONES } from "constants/timezones";
const defaultValues: Partial
= {
avatar: "",
@@ -31,6 +39,7 @@ const defaultValues: Partial = {
last_name: "",
email: "",
role: "Product / Project Manager",
+ user_timezone: "Asia/Kolkata",
};
const Profile: NextPage = () => {
@@ -72,6 +81,7 @@ const Profile: NextPage = () => {
cover_image: formData.cover_image,
role: formData.role,
display_name: formData.display_name,
+ user_timezone: formData.user_timezone,
};
await userService
@@ -128,6 +138,12 @@ const Profile: NextPage = () => {
});
};
+ const timeZoneOptions = TIME_ZONES.map((timeZone) => ({
+ value: timeZone.value,
+ query: timeZone.label + " " + timeZone.value,
+ content: timeZone.label,
+ }));
+
return (
{
{errors.role && Please select a role }
+
+
+
Timezone
+
Select a timezone
+
+
+ (
+ t.value === value)?.label ?? value
+ : "Select a timezone"
+ }
+ options={timeZoneOptions}
+ onChange={onChange}
+ verticalPosition="top"
+ optionsClassName="w-full"
+ input
+ />
+ )}
+ />
+ {errors.role && Please select a role }
+
+
{isSubmitting ? "Updating..." : "Update profile"}
diff --git a/apps/app/pages/[workspaceSlug]/me/profile/preferences.tsx b/web/pages/[workspaceSlug]/me/profile/preferences.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/me/profile/preferences.tsx
rename to web/pages/[workspaceSlug]/me/profile/preferences.tsx
diff --git a/apps/app/pages/[workspaceSlug]/profile/[userId]/assigned.tsx b/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/profile/[userId]/assigned.tsx
rename to web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx
diff --git a/apps/app/pages/[workspaceSlug]/profile/[userId]/created.tsx b/web/pages/[workspaceSlug]/profile/[userId]/created.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/profile/[userId]/created.tsx
rename to web/pages/[workspaceSlug]/profile/[userId]/created.tsx
diff --git a/apps/app/pages/[workspaceSlug]/profile/[userId]/index.tsx b/web/pages/[workspaceSlug]/profile/[userId]/index.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/profile/[userId]/index.tsx
rename to web/pages/[workspaceSlug]/profile/[userId]/index.tsx
diff --git a/apps/app/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx b/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx
rename to web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/archived-issues/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/index.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/archived-issues/index.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/index.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx
similarity index 67%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx
index 98f678d5d..6e7e1bca4 100644
--- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx
@@ -18,10 +18,10 @@ import {
SingleModuleCard,
} from "components/modules";
// ui
-import { EmptyState, Loader, PrimaryButton } from "components/ui";
+import { EmptyState, Icon, Loader, PrimaryButton, Tooltip } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
-import { PlusIcon, Squares2X2Icon } from "@heroicons/react/24/outline";
+import { PlusIcon } from "@heroicons/react/24/outline";
// images
import emptyModule from "public/empty-state/module.svg";
// types
@@ -30,7 +30,18 @@ import type { NextPage } from "next";
// fetch-keys
import { MODULE_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
// helper
-import { truncateText } from "helpers/string.helper";
+import { replaceUnderscoreIfSnakeCase, truncateText } from "helpers/string.helper";
+
+const moduleViewOptions: { type: "grid" | "gantt_chart"; icon: any }[] = [
+ {
+ type: "gantt_chart",
+ icon: "view_timeline",
+ },
+ {
+ type: "grid",
+ icon: "table_rows",
+ },
+];
const ProjectModules: NextPage = () => {
const [selectedModule, setSelectedModule] = useState();
@@ -64,6 +75,7 @@ const ProjectModules: NextPage = () => {
useEffect(() => {
if (createUpdateModule) return;
+
const timer = setTimeout(() => {
setSelectedModule(undefined);
clearTimeout(timer);
@@ -79,16 +91,42 @@ const ProjectModules: NextPage = () => {
}
right={
- {
- const e = new KeyboardEvent("keydown", { key: "m" });
- document.dispatchEvent(e);
- }}
- >
-
- Add Module
-
+
+ {moduleViewOptions.map((option) => (
+
{replaceUnderscoreIfSnakeCase(option.type)} View
+ }
+ position="bottom"
+ >
+ setModulesView(option.type)}
+ >
+
+
+
+ ))}
+
{
+ const e = new KeyboardEvent("keydown", { key: "m" });
+ document.dispatchEvent(e);
+ }}
+ >
+
+ Add Module
+
+
}
>
{
/>
{modules ? (
modules.length > 0 ? (
-
-
-
Modules
-
- setModulesView("grid")}
- >
-
-
- setModulesView("gantt_chart")}
- >
-
- waterfall_chart
-
-
-
-
+ <>
{modulesView === "grid" && (
-
-
+
+
{modules.map((module) => (
{
{modulesView === "gantt_chart" && (
)}
-
+ >
) : (
{
: "text-custom-sidebar-text-200"
}`}
>
- View
+ Display
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/automations.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/automations.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/automations.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/automations.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/control.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/control.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/control.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/control.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx
similarity index 86%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx
index 4287cee5d..882bdb41e 100644
--- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx
@@ -183,14 +183,11 @@ const GeneralSettings: NextPage = () => {
data={projectDetails ?? null}
isOpen={Boolean(selectProject)}
onClose={() => setSelectedProject(null)}
- onSuccess={() => {
- router.push(`/${workspaceSlug}/projects`);
- }}
user={user}
/>
-
+
Icon & Name
@@ -209,6 +206,7 @@ const GeneralSettings: NextPage = () => {
label={value ? renderEmoji(value) : "Icon"}
value={value}
onChange={onChange}
+ disabled={!isAdmin}
/>
)}
/>
@@ -228,6 +226,7 @@ const GeneralSettings: NextPage = () => {
validations={{
required: "Name is required",
}}
+ disabled={!isAdmin}
/>
) : (
@@ -251,6 +250,7 @@ const GeneralSettings: NextPage = () => {
placeholder="Enter project description"
validations={{}}
className="min-h-[46px] text-sm"
+ disabled={!isAdmin}
/>
) : (
@@ -282,6 +282,7 @@ const GeneralSettings: NextPage = () => {
setValue("cover_image", imageUrl);
}}
value={watch("cover_image")}
+ disabled={!isAdmin}
/>
@@ -322,6 +323,7 @@ const GeneralSettings: NextPage = () => {
message: "Identifier must at most be of 5 characters",
},
}}
+ disabled={!isAdmin}
/>
) : (
@@ -346,6 +348,7 @@ const GeneralSettings: NextPage = () => {
onChange={onChange}
label={currentNetwork?.label ?? "Select network"}
input
+ disabled={!isAdmin}
>
{NETWORK_CHOICES.map((network) => (
@@ -362,44 +365,48 @@ const GeneralSettings: NextPage = () => {
)}
-
- {projectDetails ? (
-
- {isSubmitting ? "Updating Project..." : "Update Project"}
-
- ) : (
-
-
-
- )}
-
- {memberDetails?.role === 20 && (
-
-
-
Danger Zone
-
- The danger zone of the project delete page is a critical area that requires
- careful consideration and attention. When deleting a project, all of the data and
- resources within that project will be permanently removed and cannot be recovered.
-
-
-
+
+ {isAdmin && (
+ <>
+
{projectDetails ? (
-
- setSelectedProject(projectDetails.id ?? null)}
- outline
- >
- Delete Project
-
-
+
+ {isSubmitting ? "Updating Project..." : "Update Project"}
+
) : (
-
+
)}
-
+
+
+
Danger Zone
+
+ The danger zone of the project delete page is a critical area that requires
+ careful consideration and attention. When deleting a project, all of the data
+ and resources within that project will be permanently removed and cannot be
+ recovered.
+
+
+
+ {projectDetails ? (
+
+ setSelectedProject(projectDetails.id ?? null)}
+ outline
+ >
+ Delete Project
+
+
+ ) : (
+
+
+
+ )}
+
+
+ >
)}
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx
similarity index 99%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx
index 6fb29efb2..ec8c0c43b 100644
--- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx
@@ -108,6 +108,8 @@ const MembersSettings: NextPage = () => {
const currentUser = projectMembers?.find((item) => item.member.id === user?.id);
+ const handleProjectInvitationSuccess = () => {};
+
return (
{
setIsOpen={setInviteModal}
members={members}
user={user}
+ onSuccess={() => mutateMembers()}
/>
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx
rename to web/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx
diff --git a/apps/app/pages/[workspaceSlug]/projects/index.tsx b/web/pages/[workspaceSlug]/projects/index.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/projects/index.tsx
rename to web/pages/[workspaceSlug]/projects/index.tsx
diff --git a/apps/app/pages/[workspaceSlug]/settings/billing.tsx b/web/pages/[workspaceSlug]/settings/billing.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/settings/billing.tsx
rename to web/pages/[workspaceSlug]/settings/billing.tsx
diff --git a/apps/app/pages/[workspaceSlug]/settings/exports.tsx b/web/pages/[workspaceSlug]/settings/exports.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/settings/exports.tsx
rename to web/pages/[workspaceSlug]/settings/exports.tsx
diff --git a/apps/app/pages/[workspaceSlug]/settings/imports.tsx b/web/pages/[workspaceSlug]/settings/imports.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/settings/imports.tsx
rename to web/pages/[workspaceSlug]/settings/imports.tsx
diff --git a/apps/app/pages/[workspaceSlug]/settings/index.tsx b/web/pages/[workspaceSlug]/settings/index.tsx
similarity index 79%
rename from apps/app/pages/[workspaceSlug]/settings/index.tsx
rename to web/pages/[workspaceSlug]/settings/index.tsx
index a254c7a49..407f9b402 100644
--- a/apps/app/pages/[workspaceSlug]/settings/index.tsx
+++ b/web/pages/[workspaceSlug]/settings/index.tsx
@@ -90,8 +90,9 @@ const WorkspaceSettings: NextPage = () => {
await workspaceService
.updateWorkspace(activeWorkspace.slug, payload, user)
.then((res) => {
- mutate
(USER_WORKSPACES, (prevData) =>
- prevData?.map((workspace) => (workspace.id === res.id ? res : workspace))
+ mutate(
+ USER_WORKSPACES,
+ (prevData) => prevData?.map((workspace) => (workspace.id === res.id ? res : workspace))
);
mutate(WORKSPACE_DETAILS(workspaceSlug as string), (prevData) => {
if (!prevData) return prevData;
@@ -124,8 +125,9 @@ const WorkspaceSettings: NextPage = () => {
title: "Success!",
message: "Workspace picture removed successfully.",
});
- mutate(USER_WORKSPACES, (prevData) =>
- prevData?.map((workspace) => (workspace.id === res.id ? res : workspace))
+ mutate(
+ USER_WORKSPACES,
+ (prevData) => prevData?.map((workspace) => (workspace.id === res.id ? res : workspace))
);
mutate(WORKSPACE_DETAILS(workspaceSlug as string), (prevData) => {
if (!prevData) return prevData;
@@ -181,7 +183,7 @@ const WorkspaceSettings: NextPage = () => {
{activeWorkspace ? (
-
+
Logo
@@ -191,7 +193,11 @@ const WorkspaceSettings: NextPage = () => {
-
setIsImageUploadModalOpen(true)}>
+ setIsImageUploadModalOpen(true)}
+ disabled={!isAdmin}
+ >
{watch("logo") && watch("logo") !== null && watch("logo") !== "" ? (
{
)}
-
-
{
- setIsImageUploadModalOpen(true);
- }}
- >
- {isImageUploading ? "Uploading..." : "Upload"}
-
- {activeWorkspace.logo && activeWorkspace.logo !== "" && (
-
handleDelete(activeWorkspace.logo)}
- loading={isImageRemoving}
+ {isAdmin && (
+
+ {
+ setIsImageUploadModalOpen(true);
+ }}
>
- {isImageRemoving ? "Removing..." : "Remove"}
-
- )}
-
+ {isImageUploading ? "Uploading..." : "Upload"}
+
+ {activeWorkspace.logo && activeWorkspace.logo !== "" && (
+ handleDelete(activeWorkspace.logo)}
+ loading={isImageRemoving}
+ >
+ {isImageRemoving ? "Removing..." : "Remove"}
+
+ )}
+
+ )}
@@ -288,6 +296,7 @@ const WorkspaceSettings: NextPage = () => {
message: "Workspace name should not exceed 80 characters",
},
}}
+ disabled={!isAdmin}
/>
@@ -309,6 +318,7 @@ const WorkspaceSettings: NextPage = () => {
}
width="w-full"
input
+ disabled={!isAdmin}
>
{ORGANIZATION_SIZE?.map((item) => (
@@ -320,32 +330,35 @@ const WorkspaceSettings: NextPage = () => {
/>
-
-
- {isSubmitting ? "Updating..." : "Update Workspace"}
-
-
- {memberDetails?.role === 20 && (
-
-
-
Danger Zone
-
- The danger zone of the workspace delete page is a critical area that requires
- careful consideration and attention. When deleting a workspace, all of the data
- and resources within that workspace will be permanently removed and cannot be
- recovered.
-
+
+ {isAdmin && (
+ <>
+
+
+ {isSubmitting ? "Updating..." : "Update Workspace"}
+
-
-
setIsOpen(true)} outline>
- Delete the workspace
-
+
+
+
Danger Zone
+
+ The danger zone of the workspace delete page is a critical area that requires
+ careful consideration and attention. When deleting a workspace, all of the
+ data and resources within that workspace will be permanently removed and
+ cannot be recovered.
+
+
+
+ setIsOpen(true)} outline>
+ Delete the workspace
+
+
-
+ >
)}
) : (
diff --git a/apps/app/pages/[workspaceSlug]/settings/integrations.tsx b/web/pages/[workspaceSlug]/settings/integrations.tsx
similarity index 100%
rename from apps/app/pages/[workspaceSlug]/settings/integrations.tsx
rename to web/pages/[workspaceSlug]/settings/integrations.tsx
diff --git a/apps/app/pages/[workspaceSlug]/settings/members.tsx b/web/pages/[workspaceSlug]/settings/members.tsx
similarity index 97%
rename from apps/app/pages/[workspaceSlug]/settings/members.tsx
rename to web/pages/[workspaceSlug]/settings/members.tsx
index 5f6fbc150..9090e1c17 100644
--- a/apps/app/pages/[workspaceSlug]/settings/members.tsx
+++ b/web/pages/[workspaceSlug]/settings/members.tsx
@@ -69,19 +69,6 @@ const MembersSettings: NextPage = () => {
);
const members = [
- ...(workspaceMembers?.map((item) => ({
- id: item.id,
- memberId: item.member?.id,
- avatar: item.member?.avatar,
- first_name: item.member?.first_name,
- last_name: item.member?.last_name,
- email: item.member?.email,
- display_name: item.member?.display_name,
- role: item.role,
- status: true,
- member: true,
- accountCreated: true,
- })) || []),
...(workspaceInvitations?.map((item) => ({
id: item.id,
memberId: item.id,
@@ -95,10 +82,27 @@ const MembersSettings: NextPage = () => {
member: false,
accountCreated: item?.accepted ? false : true,
})) || []),
+ ...(workspaceMembers?.map((item) => ({
+ id: item.id,
+ memberId: item.member?.id,
+ avatar: item.member?.avatar,
+ first_name: item.member?.first_name,
+ last_name: item.member?.last_name,
+ email: item.member?.email,
+ display_name: item.member?.display_name,
+ role: item.role,
+ status: true,
+ member: true,
+ accountCreated: true,
+ })) || []),
];
const currentUser = workspaceMembers?.find((item) => item.member?.id === user?.id);
+ const handleInviteModalSuccess = () => {
+ mutateInvitations();
+ };
+
return (
{
});
})
.finally(() => {
- mutateMembers((prevData: any) =>
- prevData?.filter((item: any) => item.id !== selectedRemoveMember)
+ mutateMembers(
+ (prevData: any) =>
+ prevData?.filter((item: any) => item.id !== selectedRemoveMember)
);
});
}
@@ -180,6 +185,7 @@ const MembersSettings: NextPage = () => {
setIsOpen={setInviteModal}
workspace_slug={workspaceSlug as string}
user={user}
+ onSuccess={handleInviteModalSuccess}
/>
diff --git a/apps/app/pages/_app.tsx b/web/pages/_app.tsx
similarity index 100%
rename from apps/app/pages/_app.tsx
rename to web/pages/_app.tsx
diff --git a/apps/app/pages/_document.tsx b/web/pages/_document.tsx
similarity index 100%
rename from apps/app/pages/_document.tsx
rename to web/pages/_document.tsx
diff --git a/apps/app/pages/_error.tsx b/web/pages/_error.tsx
similarity index 100%
rename from apps/app/pages/_error.tsx
rename to web/pages/_error.tsx
diff --git a/apps/app/pages/api/slack-redirect.ts b/web/pages/api/slack-redirect.ts
similarity index 94%
rename from apps/app/pages/api/slack-redirect.ts
rename to web/pages/api/slack-redirect.ts
index e4a220bd5..d9382f055 100644
--- a/apps/app/pages/api/slack-redirect.ts
+++ b/web/pages/api/slack-redirect.ts
@@ -18,6 +18,6 @@ export default async function handleSlackAuthorize(req: NextApiRequest, res: Nex
});
// if (response?.data?.ok)
- res.status(200).json(response.data);
+ res.status(200).json(response.data);
// else res.status(404).json(response.data);
}
diff --git a/apps/app/pages/api/track-event.ts b/web/pages/api/track-event.ts
similarity index 100%
rename from apps/app/pages/api/track-event.ts
rename to web/pages/api/track-event.ts
diff --git a/apps/app/pages/api/unsplash.ts b/web/pages/api/unsplash.ts
similarity index 100%
rename from apps/app/pages/api/unsplash.ts
rename to web/pages/api/unsplash.ts
diff --git a/apps/app/pages/create-workspace.tsx b/web/pages/create-workspace.tsx
similarity index 100%
rename from apps/app/pages/create-workspace.tsx
rename to web/pages/create-workspace.tsx
diff --git a/apps/app/pages/error.tsx b/web/pages/error.tsx
similarity index 100%
rename from apps/app/pages/error.tsx
rename to web/pages/error.tsx
diff --git a/apps/app/pages/index.tsx b/web/pages/index.tsx
similarity index 100%
rename from apps/app/pages/index.tsx
rename to web/pages/index.tsx
diff --git a/apps/app/pages/installations/[provider]/index.tsx b/web/pages/installations/[provider]/index.tsx
similarity index 100%
rename from apps/app/pages/installations/[provider]/index.tsx
rename to web/pages/installations/[provider]/index.tsx
diff --git a/apps/app/pages/invitations.tsx b/web/pages/invitations.tsx
similarity index 90%
rename from apps/app/pages/invitations.tsx
rename to web/pages/invitations.tsx
index 34aeca8f3..8e823b450 100644
--- a/apps/app/pages/invitations.tsx
+++ b/web/pages/invitations.tsx
@@ -33,6 +33,7 @@ import type { IWorkspaceMemberInvitation } from "types";
import { USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys";
// constants
import { ROLE } from "constants/workspace";
+import userService from "services/user.service";
const OnBoard: NextPage = () => {
const [invitationsRespond, setInvitationsRespond] = useState
([]);
@@ -78,12 +79,32 @@ const OnBoard: NextPage = () => {
workspaceService
.joinWorkspaces({ invitations: invitationsRespond })
.then(() => {
- mutateInvitations();
mutate("USER_WORKSPACES");
-
- setIsJoiningWorkspaces(false);
+ const firstInviteId = invitationsRespond[0];
+ const redirectWorkspace = invitations?.find((i) => i.id === firstInviteId)?.workspace;
+ userService
+ .updateUser({ last_workspace_id: redirectWorkspace?.id })
+ .then(() => {
+ setIsJoiningWorkspaces(false);
+ router.push(`/${redirectWorkspace?.slug}`);
+ })
+ .catch(() => {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Something went wrong, Please try again.",
+ });
+ setIsJoiningWorkspaces(false);
+ });
})
- .catch(() => setIsJoiningWorkspaces(false));
+ .catch(() => {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Something went wrong, Please try again.",
+ });
+ setIsJoiningWorkspaces(false);
+ });
};
return (
@@ -167,6 +188,7 @@ const OnBoard: NextPage = () => {
size="md"
onClick={submitInvitations}
disabled={isJoiningWorkspaces || invitationsRespond.length === 0}
+ loading={isJoiningWorkspaces}
>
Accept & Join
diff --git a/apps/app/pages/magic-sign-in.tsx b/web/pages/magic-sign-in.tsx
similarity index 100%
rename from apps/app/pages/magic-sign-in.tsx
rename to web/pages/magic-sign-in.tsx
diff --git a/apps/app/pages/onboarding.tsx b/web/pages/onboarding.tsx
similarity index 100%
rename from apps/app/pages/onboarding.tsx
rename to web/pages/onboarding.tsx
diff --git a/apps/app/pages/reset-password.tsx b/web/pages/reset-password.tsx
similarity index 100%
rename from apps/app/pages/reset-password.tsx
rename to web/pages/reset-password.tsx
diff --git a/apps/app/pages/sign-up.tsx b/web/pages/sign-up.tsx
similarity index 100%
rename from apps/app/pages/sign-up.tsx
rename to web/pages/sign-up.tsx
diff --git a/apps/app/pages/workspace-member-invitation.tsx b/web/pages/workspace-member-invitation.tsx
similarity index 100%
rename from apps/app/pages/workspace-member-invitation.tsx
rename to web/pages/workspace-member-invitation.tsx
diff --git a/apps/space/postcss.config.js b/web/postcss.config.js
similarity index 72%
rename from apps/space/postcss.config.js
rename to web/postcss.config.js
index 12a703d90..cbfea5ea2 100644
--- a/apps/space/postcss.config.js
+++ b/web/postcss.config.js
@@ -1,5 +1,6 @@
module.exports = {
plugins: {
+ "tailwindcss/nesting": {},
tailwindcss: {},
autoprefixer: {},
},
diff --git a/apps/space/public/404.svg b/web/public/404.svg
similarity index 100%
rename from apps/space/public/404.svg
rename to web/public/404.svg
diff --git a/apps/app/public/animated-icons/uploading.json b/web/public/animated-icons/uploading.json
similarity index 100%
rename from apps/app/public/animated-icons/uploading.json
rename to web/public/animated-icons/uploading.json
diff --git a/apps/app/public/attachment/audio-icon.png b/web/public/attachment/audio-icon.png
similarity index 100%
rename from apps/app/public/attachment/audio-icon.png
rename to web/public/attachment/audio-icon.png
diff --git a/apps/app/public/attachment/css-icon.png b/web/public/attachment/css-icon.png
similarity index 100%
rename from apps/app/public/attachment/css-icon.png
rename to web/public/attachment/css-icon.png
diff --git a/apps/app/public/attachment/csv-icon.png b/web/public/attachment/csv-icon.png
similarity index 100%
rename from apps/app/public/attachment/csv-icon.png
rename to web/public/attachment/csv-icon.png
diff --git a/apps/app/public/attachment/default-icon.png b/web/public/attachment/default-icon.png
similarity index 100%
rename from apps/app/public/attachment/default-icon.png
rename to web/public/attachment/default-icon.png
diff --git a/apps/app/public/attachment/doc-icon.png b/web/public/attachment/doc-icon.png
similarity index 100%
rename from apps/app/public/attachment/doc-icon.png
rename to web/public/attachment/doc-icon.png
diff --git a/apps/app/public/attachment/excel-icon.png b/web/public/attachment/excel-icon.png
similarity index 100%
rename from apps/app/public/attachment/excel-icon.png
rename to web/public/attachment/excel-icon.png
diff --git a/apps/app/public/attachment/figma-icon.png b/web/public/attachment/figma-icon.png
similarity index 100%
rename from apps/app/public/attachment/figma-icon.png
rename to web/public/attachment/figma-icon.png
diff --git a/apps/app/public/attachment/html-icon.png b/web/public/attachment/html-icon.png
similarity index 100%
rename from apps/app/public/attachment/html-icon.png
rename to web/public/attachment/html-icon.png
diff --git a/apps/app/public/attachment/img-icon.png b/web/public/attachment/img-icon.png
similarity index 100%
rename from apps/app/public/attachment/img-icon.png
rename to web/public/attachment/img-icon.png
diff --git a/apps/app/public/attachment/jpg-icon.png b/web/public/attachment/jpg-icon.png
similarity index 100%
rename from apps/app/public/attachment/jpg-icon.png
rename to web/public/attachment/jpg-icon.png
diff --git a/apps/app/public/attachment/js-icon.png b/web/public/attachment/js-icon.png
similarity index 100%
rename from apps/app/public/attachment/js-icon.png
rename to web/public/attachment/js-icon.png
diff --git a/apps/app/public/attachment/pdf-icon.png b/web/public/attachment/pdf-icon.png
similarity index 100%
rename from apps/app/public/attachment/pdf-icon.png
rename to web/public/attachment/pdf-icon.png
diff --git a/apps/app/public/attachment/png-icon.png b/web/public/attachment/png-icon.png
similarity index 100%
rename from apps/app/public/attachment/png-icon.png
rename to web/public/attachment/png-icon.png
diff --git a/apps/app/public/attachment/svg-icon.png b/web/public/attachment/svg-icon.png
similarity index 100%
rename from apps/app/public/attachment/svg-icon.png
rename to web/public/attachment/svg-icon.png
diff --git a/apps/app/public/attachment/txt-icon.png b/web/public/attachment/txt-icon.png
similarity index 100%
rename from apps/app/public/attachment/txt-icon.png
rename to web/public/attachment/txt-icon.png
diff --git a/apps/app/public/attachment/video-icon.png b/web/public/attachment/video-icon.png
similarity index 100%
rename from apps/app/public/attachment/video-icon.png
rename to web/public/attachment/video-icon.png
diff --git a/apps/app/public/auth/project-not-authorized.svg b/web/public/auth/project-not-authorized.svg
similarity index 100%
rename from apps/app/public/auth/project-not-authorized.svg
rename to web/public/auth/project-not-authorized.svg
diff --git a/apps/app/public/auth/workspace-not-authorized.svg b/web/public/auth/workspace-not-authorized.svg
similarity index 100%
rename from apps/app/public/auth/workspace-not-authorized.svg
rename to web/public/auth/workspace-not-authorized.svg
diff --git a/apps/app/public/empty-state/analytics.svg b/web/public/empty-state/analytics.svg
similarity index 100%
rename from apps/app/public/empty-state/analytics.svg
rename to web/public/empty-state/analytics.svg
diff --git a/apps/app/public/empty-state/cycle.svg b/web/public/empty-state/cycle.svg
similarity index 100%
rename from apps/app/public/empty-state/cycle.svg
rename to web/public/empty-state/cycle.svg
diff --git a/apps/app/public/empty-state/dashboard.svg b/web/public/empty-state/dashboard.svg
similarity index 100%
rename from apps/app/public/empty-state/dashboard.svg
rename to web/public/empty-state/dashboard.svg
diff --git a/apps/app/public/empty-state/empty_bar_graph.svg b/web/public/empty-state/empty_bar_graph.svg
similarity index 100%
rename from apps/app/public/empty-state/empty_bar_graph.svg
rename to web/public/empty-state/empty_bar_graph.svg
diff --git a/apps/app/public/empty-state/empty_graph.svg b/web/public/empty-state/empty_graph.svg
similarity index 100%
rename from apps/app/public/empty-state/empty_graph.svg
rename to web/public/empty-state/empty_graph.svg
diff --git a/apps/app/public/empty-state/empty_users.svg b/web/public/empty-state/empty_users.svg
similarity index 100%
rename from apps/app/public/empty-state/empty_users.svg
rename to web/public/empty-state/empty_users.svg
diff --git a/apps/app/public/empty-state/estimate.svg b/web/public/empty-state/estimate.svg
similarity index 100%
rename from apps/app/public/empty-state/estimate.svg
rename to web/public/empty-state/estimate.svg
diff --git a/apps/app/public/empty-state/integration.svg b/web/public/empty-state/integration.svg
similarity index 100%
rename from apps/app/public/empty-state/integration.svg
rename to web/public/empty-state/integration.svg
diff --git a/apps/app/public/empty-state/invitation.svg b/web/public/empty-state/invitation.svg
similarity index 100%
rename from apps/app/public/empty-state/invitation.svg
rename to web/public/empty-state/invitation.svg
diff --git a/apps/app/public/empty-state/issue-archive.svg b/web/public/empty-state/issue-archive.svg
similarity index 100%
rename from apps/app/public/empty-state/issue-archive.svg
rename to web/public/empty-state/issue-archive.svg
diff --git a/apps/app/public/empty-state/issue.svg b/web/public/empty-state/issue.svg
similarity index 100%
rename from apps/app/public/empty-state/issue.svg
rename to web/public/empty-state/issue.svg
diff --git a/apps/app/public/empty-state/label.svg b/web/public/empty-state/label.svg
similarity index 100%
rename from apps/app/public/empty-state/label.svg
rename to web/public/empty-state/label.svg
diff --git a/apps/app/public/empty-state/module.svg b/web/public/empty-state/module.svg
similarity index 100%
rename from apps/app/public/empty-state/module.svg
rename to web/public/empty-state/module.svg
diff --git a/apps/app/public/empty-state/my-issues.svg b/web/public/empty-state/my-issues.svg
similarity index 100%
rename from apps/app/public/empty-state/my-issues.svg
rename to web/public/empty-state/my-issues.svg
diff --git a/apps/app/public/empty-state/notification.svg b/web/public/empty-state/notification.svg
similarity index 100%
rename from apps/app/public/empty-state/notification.svg
rename to web/public/empty-state/notification.svg
diff --git a/apps/app/public/empty-state/page.svg b/web/public/empty-state/page.svg
similarity index 100%
rename from apps/app/public/empty-state/page.svg
rename to web/public/empty-state/page.svg
diff --git a/apps/app/public/empty-state/project.svg b/web/public/empty-state/project.svg
similarity index 100%
rename from apps/app/public/empty-state/project.svg
rename to web/public/empty-state/project.svg
diff --git a/apps/app/public/empty-state/recent_activity.svg b/web/public/empty-state/recent_activity.svg
similarity index 100%
rename from apps/app/public/empty-state/recent_activity.svg
rename to web/public/empty-state/recent_activity.svg
diff --git a/apps/app/public/empty-state/state_graph.svg b/web/public/empty-state/state_graph.svg
similarity index 100%
rename from apps/app/public/empty-state/state_graph.svg
rename to web/public/empty-state/state_graph.svg
diff --git a/apps/app/public/empty-state/view.svg b/web/public/empty-state/view.svg
similarity index 100%
rename from apps/app/public/empty-state/view.svg
rename to web/public/empty-state/view.svg
diff --git a/web/public/favicon/android-chrome-192x192.png b/web/public/favicon/android-chrome-192x192.png
new file mode 100644
index 000000000..62e95acfc
Binary files /dev/null and b/web/public/favicon/android-chrome-192x192.png differ
diff --git a/web/public/favicon/android-chrome-512x512.png b/web/public/favicon/android-chrome-512x512.png
new file mode 100644
index 000000000..41400832b
Binary files /dev/null and b/web/public/favicon/android-chrome-512x512.png differ
diff --git a/web/public/favicon/apple-touch-icon.png b/web/public/favicon/apple-touch-icon.png
new file mode 100644
index 000000000..5273d4951
Binary files /dev/null and b/web/public/favicon/apple-touch-icon.png differ
diff --git a/web/public/favicon/favicon-16x16.png b/web/public/favicon/favicon-16x16.png
new file mode 100644
index 000000000..8ddbd49c0
Binary files /dev/null and b/web/public/favicon/favicon-16x16.png differ
diff --git a/web/public/favicon/favicon-32x32.png b/web/public/favicon/favicon-32x32.png
new file mode 100644
index 000000000..80cbe7a68
Binary files /dev/null and b/web/public/favicon/favicon-32x32.png differ
diff --git a/web/public/favicon/favicon.ico b/web/public/favicon/favicon.ico
new file mode 100644
index 000000000..9094a07c7
Binary files /dev/null and b/web/public/favicon/favicon.ico differ
diff --git a/web/public/favicon/site.webmanifest b/web/public/favicon/site.webmanifest
new file mode 100644
index 000000000..45dc8a206
--- /dev/null
+++ b/web/public/favicon/site.webmanifest
@@ -0,0 +1 @@
+{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of file
diff --git a/apps/app/public/logos/github-black.png b/web/public/logos/github-black.png
similarity index 100%
rename from apps/app/public/logos/github-black.png
rename to web/public/logos/github-black.png
diff --git a/apps/app/public/logos/github-square.png b/web/public/logos/github-square.png
similarity index 100%
rename from apps/app/public/logos/github-square.png
rename to web/public/logos/github-square.png
diff --git a/apps/app/public/logos/github-white.png b/web/public/logos/github-white.png
similarity index 100%
rename from apps/app/public/logos/github-white.png
rename to web/public/logos/github-white.png
diff --git a/apps/app/public/mac-command.svg b/web/public/mac-command.svg
similarity index 100%
rename from apps/app/public/mac-command.svg
rename to web/public/mac-command.svg
diff --git a/apps/app/public/onboarding/cycles.svg b/web/public/onboarding/cycles.svg
similarity index 100%
rename from apps/app/public/onboarding/cycles.svg
rename to web/public/onboarding/cycles.svg
diff --git a/apps/app/public/onboarding/cycles.webp b/web/public/onboarding/cycles.webp
similarity index 100%
rename from apps/app/public/onboarding/cycles.webp
rename to web/public/onboarding/cycles.webp
diff --git a/apps/app/public/onboarding/issues.svg b/web/public/onboarding/issues.svg
similarity index 100%
rename from apps/app/public/onboarding/issues.svg
rename to web/public/onboarding/issues.svg
diff --git a/apps/app/public/onboarding/issues.webp b/web/public/onboarding/issues.webp
similarity index 100%
rename from apps/app/public/onboarding/issues.webp
rename to web/public/onboarding/issues.webp
diff --git a/apps/app/public/onboarding/modules.svg b/web/public/onboarding/modules.svg
similarity index 100%
rename from apps/app/public/onboarding/modules.svg
rename to web/public/onboarding/modules.svg
diff --git a/apps/app/public/onboarding/modules.webp b/web/public/onboarding/modules.webp
similarity index 100%
rename from apps/app/public/onboarding/modules.webp
rename to web/public/onboarding/modules.webp
diff --git a/apps/app/public/onboarding/pages.svg b/web/public/onboarding/pages.svg
similarity index 100%
rename from apps/app/public/onboarding/pages.svg
rename to web/public/onboarding/pages.svg
diff --git a/apps/app/public/onboarding/pages.webp b/web/public/onboarding/pages.webp
similarity index 100%
rename from apps/app/public/onboarding/pages.webp
rename to web/public/onboarding/pages.webp
diff --git a/apps/app/public/onboarding/views.svg b/web/public/onboarding/views.svg
similarity index 100%
rename from apps/app/public/onboarding/views.svg
rename to web/public/onboarding/views.svg
diff --git a/apps/app/public/onboarding/views.webp b/web/public/onboarding/views.webp
similarity index 100%
rename from apps/app/public/onboarding/views.webp
rename to web/public/onboarding/views.webp
diff --git a/web/public/plane-logos/black-horizontal-with-blue-logo.svg b/web/public/plane-logos/black-horizontal-with-blue-logo.svg
new file mode 100644
index 000000000..ae79919fc
--- /dev/null
+++ b/web/public/plane-logos/black-horizontal-with-blue-logo.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/app/public/plane-logos/blue-without-text.png b/web/public/plane-logos/blue-without-text.png
similarity index 100%
rename from apps/app/public/plane-logos/blue-without-text.png
rename to web/public/plane-logos/blue-without-text.png
diff --git a/web/public/plane-logos/white-horizontal-with-blue-logo.svg b/web/public/plane-logos/white-horizontal-with-blue-logo.svg
new file mode 100644
index 000000000..1f09cc34a
--- /dev/null
+++ b/web/public/plane-logos/white-horizontal-with-blue-logo.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/public/plane-logos/white-horizontal.svg b/web/public/plane-logos/white-horizontal.svg
new file mode 100644
index 000000000..13e2dbb9f
--- /dev/null
+++ b/web/public/plane-logos/white-horizontal.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/app/public/services/csv.svg b/web/public/services/csv.svg
similarity index 100%
rename from apps/app/public/services/csv.svg
rename to web/public/services/csv.svg
diff --git a/apps/app/public/services/excel.svg b/web/public/services/excel.svg
similarity index 100%
rename from apps/app/public/services/excel.svg
rename to web/public/services/excel.svg
diff --git a/apps/app/public/services/github.png b/web/public/services/github.png
similarity index 100%
rename from apps/app/public/services/github.png
rename to web/public/services/github.png
diff --git a/apps/app/public/services/jira.png b/web/public/services/jira.png
similarity index 100%
rename from apps/app/public/services/jira.png
rename to web/public/services/jira.png
diff --git a/apps/app/public/services/json.svg b/web/public/services/json.svg
similarity index 100%
rename from apps/app/public/services/json.svg
rename to web/public/services/json.svg
diff --git a/apps/app/public/services/slack.png b/web/public/services/slack.png
similarity index 100%
rename from apps/app/public/services/slack.png
rename to web/public/services/slack.png
diff --git a/apps/app/public/site.webmanifest.json b/web/public/site.webmanifest.json
similarity index 100%
rename from apps/app/public/site.webmanifest.json
rename to web/public/site.webmanifest.json
diff --git a/apps/app/public/sw.js b/web/public/sw.js
similarity index 100%
rename from apps/app/public/sw.js
rename to web/public/sw.js
diff --git a/apps/app/public/sw.js.map b/web/public/sw.js.map
similarity index 100%
rename from apps/app/public/sw.js.map
rename to web/public/sw.js.map
diff --git a/apps/app/public/user.png b/web/public/user.png
similarity index 100%
rename from apps/app/public/user.png
rename to web/public/user.png
diff --git a/apps/app/public/workbox-7805bd61.js b/web/public/workbox-7805bd61.js
similarity index 100%
rename from apps/app/public/workbox-7805bd61.js
rename to web/public/workbox-7805bd61.js
diff --git a/apps/app/public/workbox-7805bd61.js.map b/web/public/workbox-7805bd61.js.map
similarity index 100%
rename from apps/app/public/workbox-7805bd61.js.map
rename to web/public/workbox-7805bd61.js.map
diff --git a/apps/app/sentry.client.config.js b/web/sentry.client.config.js
similarity index 100%
rename from apps/app/sentry.client.config.js
rename to web/sentry.client.config.js
diff --git a/apps/app/sentry.edge.config.js b/web/sentry.edge.config.js
similarity index 100%
rename from apps/app/sentry.edge.config.js
rename to web/sentry.edge.config.js
diff --git a/apps/app/sentry.properties b/web/sentry.properties
similarity index 100%
rename from apps/app/sentry.properties
rename to web/sentry.properties
diff --git a/apps/app/sentry.server.config.js b/web/sentry.server.config.js
similarity index 100%
rename from apps/app/sentry.server.config.js
rename to web/sentry.server.config.js
diff --git a/apps/app/services/ai.service.ts b/web/services/ai.service.ts
similarity index 100%
rename from apps/app/services/ai.service.ts
rename to web/services/ai.service.ts
diff --git a/apps/app/services/analytics.service.ts b/web/services/analytics.service.ts
similarity index 100%
rename from apps/app/services/analytics.service.ts
rename to web/services/analytics.service.ts
diff --git a/apps/app/services/api.service.ts b/web/services/api.service.ts
similarity index 100%
rename from apps/app/services/api.service.ts
rename to web/services/api.service.ts
diff --git a/apps/app/services/app-installations.service.ts b/web/services/app-installations.service.ts
similarity index 77%
rename from apps/app/services/app-installations.service.ts
rename to web/services/app-installations.service.ts
index 8ee04dcfe..dea6fa421 100644
--- a/apps/app/services/app-installations.service.ts
+++ b/web/services/app-installations.service.ts
@@ -17,7 +17,12 @@ class AppInstallationsService extends APIService {
});
}
- async addSlackChannel(workspaceSlug: string, projectId: string, integrationId: string | null | undefined, data: any): Promise {
+ async addSlackChannel(
+ workspaceSlug: string,
+ projectId: string,
+ integrationId: string | null | undefined,
+ data: any
+ ): Promise {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/`,
data
@@ -28,7 +33,11 @@ class AppInstallationsService extends APIService {
});
}
- async getSlackChannelDetail(workspaceSlug: string, projectId: string, integrationId: string | null | undefined): Promise {
+ async getSlackChannelDetail(
+ workspaceSlug: string,
+ projectId: string,
+ integrationId: string | null | undefined
+ ): Promise {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/`
)
@@ -38,7 +47,12 @@ class AppInstallationsService extends APIService {
});
}
- async removeSlackChannel(workspaceSlug: string, projectId: string, integrationId: string | null | undefined, slackSyncId: string | undefined): Promise {
+ async removeSlackChannel(
+ workspaceSlug: string,
+ projectId: string,
+ integrationId: string | null | undefined,
+ slackSyncId: string | undefined
+ ): Promise {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/${slackSyncId}`
)
diff --git a/apps/app/services/authentication.service.ts b/web/services/authentication.service.ts
similarity index 100%
rename from apps/app/services/authentication.service.ts
rename to web/services/authentication.service.ts
diff --git a/apps/app/services/cycles.service.ts b/web/services/cycles.service.ts
similarity index 100%
rename from apps/app/services/cycles.service.ts
rename to web/services/cycles.service.ts
diff --git a/apps/app/services/estimates.service.ts b/web/services/estimates.service.ts
similarity index 100%
rename from apps/app/services/estimates.service.ts
rename to web/services/estimates.service.ts
diff --git a/apps/app/services/file.service.ts b/web/services/file.service.ts
similarity index 100%
rename from apps/app/services/file.service.ts
rename to web/services/file.service.ts
diff --git a/apps/app/services/inbox.service.ts b/web/services/inbox.service.ts
similarity index 100%
rename from apps/app/services/inbox.service.ts
rename to web/services/inbox.service.ts
diff --git a/apps/app/services/integration/csv.services.ts b/web/services/integration/csv.services.ts
similarity index 100%
rename from apps/app/services/integration/csv.services.ts
rename to web/services/integration/csv.services.ts
diff --git a/apps/app/services/integration/github.service.ts b/web/services/integration/github.service.ts
similarity index 100%
rename from apps/app/services/integration/github.service.ts
rename to web/services/integration/github.service.ts
diff --git a/apps/app/services/integration/index.ts b/web/services/integration/index.ts
similarity index 100%
rename from apps/app/services/integration/index.ts
rename to web/services/integration/index.ts
diff --git a/apps/app/services/integration/jira.service.ts b/web/services/integration/jira.service.ts
similarity index 100%
rename from apps/app/services/integration/jira.service.ts
rename to web/services/integration/jira.service.ts
diff --git a/apps/app/services/issues.service.ts b/web/services/issues.service.ts
similarity index 99%
rename from apps/app/services/issues.service.ts
rename to web/services/issues.service.ts
index 53c6c1a2d..b8875e6c5 100644
--- a/apps/app/services/issues.service.ts
+++ b/web/services/issues.service.ts
@@ -182,7 +182,7 @@ class ProjectIssuesServices extends APIService {
workspaceSlug: string,
projectId: string,
issueId: string,
- data: any,
+ data: Partial,
user: ICurrentUserResponse | undefined
): Promise {
return this.post(
@@ -468,20 +468,18 @@ class ProjectIssuesServices extends APIService {
metadata: any;
title: string;
url: string;
- },
-
+ }
): Promise {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/`,
data
)
- .then((response) => response?.data)
- .catch((error) => {
- throw error?.response;
- });
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
}
-
async deleteIssueLink(
workspaceSlug: string,
projectId: string,
diff --git a/apps/app/services/modules.service.ts b/web/services/modules.service.ts
similarity index 98%
rename from apps/app/services/modules.service.ts
rename to web/services/modules.service.ts
index c70066a1e..0e3b5cfe2 100644
--- a/apps/app/services/modules.service.ts
+++ b/web/services/modules.service.ts
@@ -221,17 +221,16 @@ class ProjectIssuesServices extends APIService {
metadata: any;
title: string;
url: string;
- },
-
+ }
): Promise {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
data
)
- .then((response) => response?.data)
- .catch((error) => {
- throw error?.response;
- });
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response;
+ });
}
async deleteModuleLink(
diff --git a/apps/app/services/notifications.service.ts b/web/services/notifications.service.ts
similarity index 92%
rename from apps/app/services/notifications.service.ts
rename to web/services/notifications.service.ts
index a8652b777..01c139b51 100644
--- a/apps/app/services/notifications.service.ts
+++ b/web/services/notifications.service.ts
@@ -9,6 +9,7 @@ import type {
INotificationParams,
NotificationCount,
PaginatedUserNotification,
+ IMarkAllAsReadPayload,
} from "types";
class UserNotificationsServices extends APIService {
@@ -172,6 +173,19 @@ class UserNotificationsServices extends APIService {
throw error?.response?.data;
});
}
+
+ async markAllNotificationsAsRead(
+ workspaceSlug: string,
+ payload: IMarkAllAsReadPayload
+ ): Promise {
+ return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/mark-all-read/`, {
+ ...payload,
+ })
+ .then((response) => response?.data)
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
}
const userNotificationServices = new UserNotificationsServices();
diff --git a/apps/app/services/pages.service.ts b/web/services/pages.service.ts
similarity index 100%
rename from apps/app/services/pages.service.ts
rename to web/services/pages.service.ts
diff --git a/apps/app/services/project-publish.service.ts b/web/services/project-publish.service.ts
similarity index 100%
rename from apps/app/services/project-publish.service.ts
rename to web/services/project-publish.service.ts
diff --git a/apps/app/services/project.service.ts b/web/services/project.service.ts
similarity index 94%
rename from apps/app/services/project.service.ts
rename to web/services/project.service.ts
index 961333bee..0c2712c56 100644
--- a/apps/app/services/project.service.ts
+++ b/web/services/project.service.ts
@@ -21,7 +21,7 @@ const { NEXT_PUBLIC_API_BASE_URL } = process.env;
const trackEvent =
process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1";
-class ProjectServices extends APIService {
+export class ProjectServices extends APIService {
constructor() {
super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
}
@@ -142,6 +142,30 @@ class ProjectServices extends APIService {
});
}
+ async leaveProject(
+ workspaceSlug: string,
+ projectId: string,
+ user: ICurrentUserResponse
+ ): Promise {
+ return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/leave/`)
+ .then((response) => {
+ if (trackEvent)
+ trackEventServices.trackProjectEvent(
+ "PROJECT_MEMBER_LEAVE",
+ {
+ workspaceSlug,
+ projectId,
+ ...response?.data,
+ },
+ user
+ );
+ return response?.data;
+ })
+ .catch((error) => {
+ throw error?.response?.data;
+ });
+ }
+
async joinProjects(data: any): Promise {
return this.post("/api/users/me/invitations/projects/", data)
.then((response) => response?.data)
diff --git a/apps/app/services/reaction.service.ts b/web/services/reaction.service.ts
similarity index 100%
rename from apps/app/services/reaction.service.ts
rename to web/services/reaction.service.ts
diff --git a/apps/app/services/state.service.ts b/web/services/state.service.ts
similarity index 100%
rename from apps/app/services/state.service.ts
rename to web/services/state.service.ts
diff --git a/apps/app/services/track-event.service.ts b/web/services/track-event.service.ts
similarity index 99%
rename from apps/app/services/track-event.service.ts
rename to web/services/track-event.service.ts
index f55a6f366..c59242f50 100644
--- a/apps/app/services/track-event.service.ts
+++ b/web/services/track-event.service.ts
@@ -35,7 +35,8 @@ type ProjectEventType =
| "CREATE_PROJECT"
| "UPDATE_PROJECT"
| "DELETE_PROJECT"
- | "PROJECT_MEMBER_INVITE";
+ | "PROJECT_MEMBER_INVITE"
+ | "PROJECT_MEMBER_LEAVE";
type IssueEventType = "ISSUE_CREATE" | "ISSUE_UPDATE" | "ISSUE_DELETE";
@@ -163,7 +164,11 @@ class TrackEventServices extends APIService {
user: ICurrentUserResponse | undefined
): Promise {
let payload: any;
- if (eventName !== "DELETE_PROJECT" && eventName !== "PROJECT_MEMBER_INVITE")
+ if (
+ eventName !== "DELETE_PROJECT" &&
+ eventName !== "PROJECT_MEMBER_INVITE" &&
+ eventName !== "PROJECT_MEMBER_LEAVE"
+ )
payload = {
workspaceId: data?.workspace_detail?.id,
workspaceName: data?.workspace_detail?.name,
diff --git a/apps/app/services/user.service.ts b/web/services/user.service.ts
similarity index 96%
rename from apps/app/services/user.service.ts
rename to web/services/user.service.ts
index 98eea5278..0e5def647 100644
--- a/apps/app/services/user.service.ts
+++ b/web/services/user.service.ts
@@ -101,8 +101,8 @@ class UserService extends APIService {
});
}
- async getUserActivity(): Promise {
- return this.get("/api/users/activities/")
+ async getUserWorkspaceActivity(workspaceSlug: string): Promise {
+ return this.get(`/api/users/workspaces/${workspaceSlug}/activities/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
diff --git a/apps/app/services/views.service.ts b/web/services/views.service.ts
similarity index 100%
rename from apps/app/services/views.service.ts
rename to web/services/views.service.ts
diff --git a/apps/app/services/web-waitlist.service.ts b/web/services/web-waitlist.service.ts
similarity index 100%
rename from apps/app/services/web-waitlist.service.ts
rename to web/services/web-waitlist.service.ts
diff --git a/apps/app/services/workspace.service.ts b/web/services/workspace.service.ts
similarity index 100%
rename from apps/app/services/workspace.service.ts
rename to web/services/workspace.service.ts
diff --git a/web/store/issues.ts b/web/store/issues.ts
new file mode 100644
index 000000000..286d98534
--- /dev/null
+++ b/web/store/issues.ts
@@ -0,0 +1,173 @@
+// mobx
+import { action, observable, runInAction, makeAutoObservable } from "mobx";
+// services
+import issueService from "services/issues.service";
+// types
+import type { ICurrentUserResponse, IIssue } from "types";
+
+class IssuesStore {
+ issues: { [key: string]: IIssue } = {};
+ isIssuesLoading: boolean = false;
+ rootStore: any | null = null;
+
+ constructor(_rootStore: any | null = null) {
+ makeAutoObservable(this, {
+ issues: observable.ref,
+ loadIssues: action,
+ getIssueById: action,
+ isIssuesLoading: observable,
+ createIssue: action,
+ updateIssue: action,
+ deleteIssue: action,
+ });
+
+ this.rootStore = _rootStore;
+ }
+
+ /**
+ * @description Fetch all issues of a project and hydrate issues field
+ */
+
+ loadIssues = async (workspaceSlug: string, projectId: string) => {
+ this.isIssuesLoading = true;
+ try {
+ const issuesResponse: IIssue[] = (await issueService.getIssuesWithParams(
+ workspaceSlug,
+ projectId
+ )) as IIssue[];
+
+ const issues: { [kye: string]: IIssue } = {};
+ issuesResponse.forEach((issue) => {
+ issues[issue.id] = issue;
+ });
+
+ runInAction(() => {
+ this.issues = issues;
+ this.isIssuesLoading = false;
+ });
+ } catch (error) {
+ this.isIssuesLoading = false;
+ console.error("Fetching issues error", error);
+ }
+ };
+
+ getIssueById = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string
+ ): Promise => {
+ if (this.issues[issueId]) return this.issues[issueId];
+
+ try {
+ const issueResponse: IIssue = await issueService.retrieve(workspaceSlug, projectId, issueId);
+
+ const issues = {
+ ...this.issues,
+ [issueId]: { ...issueResponse },
+ };
+
+ runInAction(() => {
+ this.issues = issues;
+ });
+
+ return issueResponse;
+ } catch (error) {
+ throw error;
+ }
+ };
+
+ createIssue = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueForm: IIssue,
+ user: ICurrentUserResponse
+ ): Promise => {
+ try {
+ const issueResponse = await issueService.createIssues(
+ workspaceSlug,
+ projectId,
+ issueForm,
+ user
+ );
+
+ const issues = {
+ ...this.issues,
+ [issueResponse.id]: { ...issueResponse },
+ };
+
+ runInAction(() => {
+ this.issues = issues;
+ });
+ return issueResponse;
+ } catch (error) {
+ console.error("Creating issue error", error);
+ throw error;
+ }
+ };
+
+ updateIssue = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string,
+ issueForm: Partial,
+ user: ICurrentUserResponse
+ ) => {
+ // keep a copy of the issue in the store
+ const originalIssue = { ...this.issues[issueId] };
+
+ // immediately update the issue in the store
+ const updatedIssue = { ...this.issues[issueId], ...issueForm };
+ if (updatedIssue.assignees_list) updatedIssue.assignees = updatedIssue.assignees_list;
+
+ try {
+ runInAction(() => {
+ this.issues[issueId] = { ...updatedIssue };
+ });
+
+ // make a patch request to update the issue
+ const issueResponse: IIssue = await issueService.patchIssue(
+ workspaceSlug,
+ projectId,
+ issueId,
+ issueForm,
+ user
+ );
+
+ const updatedIssues = { ...this.issues };
+ updatedIssues[issueId] = { ...issueResponse };
+
+ runInAction(() => {
+ this.issues = updatedIssues;
+ });
+ } catch (error) {
+ // if there is an error, revert the changes
+ runInAction(() => {
+ this.issues[issueId] = originalIssue;
+ });
+
+ return error;
+ }
+ };
+
+ deleteIssue = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string,
+ user: ICurrentUserResponse
+ ) => {
+ const issues = { ...this.issues };
+ delete issues[issueId];
+
+ try {
+ runInAction(() => {
+ this.issues = issues;
+ });
+
+ issueService.deleteIssue(workspaceSlug, projectId, issueId, user);
+ } catch (error) {
+ console.error("Deleting issue error", error);
+ }
+ };
+}
+
+export default IssuesStore;
diff --git a/apps/app/store/project-publish.tsx b/web/store/project-publish.tsx
similarity index 84%
rename from apps/app/store/project-publish.tsx
rename to web/store/project-publish.tsx
index 1b27d5fff..b8c6f0dbe 100644
--- a/apps/app/store/project-publish.tsx
+++ b/web/store/project-publish.tsx
@@ -4,21 +4,11 @@ import { RootStore } from "./root";
// services
import ProjectServices from "services/project-publish.service";
-export type IProjectPublishSettingsViewKeys =
- | "list"
- | "gantt"
- | "kanban"
- | "calendar"
- | "spreadsheet"
- | string;
+export type TProjectPublishViews = "list" | "gantt" | "kanban" | "calendar" | "spreadsheet";
-export interface IProjectPublishSettingsViews {
- list: boolean;
- gantt: boolean;
- kanban: boolean;
- calendar: boolean;
- spreadsheet: boolean;
-}
+export type TProjectPublishViewsSettings = {
+ [key in TProjectPublishViews]: boolean;
+};
export interface IProjectPublishSettings {
id?: string;
@@ -26,12 +16,13 @@ export interface IProjectPublishSettings {
comments: boolean;
reactions: boolean;
votes: boolean;
- views: IProjectPublishSettingsViews;
- inbox: null;
+ views: TProjectPublishViewsSettings;
+ inbox: string | null;
}
export interface IProjectPublishStore {
- loader: boolean;
+ generalLoader: boolean;
+ fetchSettingsLoader: boolean;
error: any | null;
projectPublishModal: boolean;
@@ -45,7 +36,7 @@ export interface IProjectPublishStore {
project_slug: string,
user: any
) => Promise;
- createProjectSettingsAsync: (
+ publishProject: (
workspace_slug: string,
project_slug: string,
data: IProjectPublishSettings,
@@ -58,7 +49,7 @@ export interface IProjectPublishStore {
data: IProjectPublishSettings,
user: any
) => Promise;
- deleteProjectSettingsAsync: (
+ unPublishProject: (
workspace_slug: string,
project_slug: string,
project_publish_id: string,
@@ -67,7 +58,8 @@ export interface IProjectPublishStore {
}
class ProjectPublishStore implements IProjectPublishStore {
- loader: boolean = false;
+ generalLoader: boolean = false;
+ fetchSettingsLoader: boolean = false;
error: any | null = null;
projectPublishModal: boolean = false;
@@ -82,7 +74,8 @@ class ProjectPublishStore implements IProjectPublishStore {
constructor(_rootStore: RootStore) {
makeObservable(this, {
// observable
- loader: observable,
+ generalLoader: observable,
+ fetchSettingsLoader: observable,
error: observable,
projectPublishModal: observable,
@@ -90,6 +83,10 @@ class ProjectPublishStore implements IProjectPublishStore {
projectPublishSettings: observable.ref,
// action
handleProjectModal: action,
+ getProjectSettingsAsync: action,
+ publishProject: action,
+ updateProjectSettingsAsync: action,
+ unPublishProject: action,
// computed
});
@@ -110,7 +107,7 @@ class ProjectPublishStore implements IProjectPublishStore {
getProjectSettingsAsync = async (workspace_slug: string, project_slug: string, user: any) => {
try {
- this.loader = true;
+ this.fetchSettingsLoader = true;
this.error = null;
const response = await this.projectPublishService.getProjectSettingsAsync(
@@ -138,30 +135,30 @@ class ProjectPublishStore implements IProjectPublishStore {
runInAction(() => {
this.projectPublishSettings = _projectPublishSettings;
- this.loader = false;
+ this.fetchSettingsLoader = false;
this.error = null;
});
} else {
this.projectPublishSettings = "not-initialized";
- this.loader = false;
+ this.fetchSettingsLoader = false;
this.error = null;
}
return response;
} catch (error) {
- this.loader = false;
+ this.fetchSettingsLoader = false;
this.error = error;
return error;
}
};
- createProjectSettingsAsync = async (
+ publishProject = async (
workspace_slug: string,
project_slug: string,
data: IProjectPublishSettings,
user: any
) => {
try {
- this.loader = true;
+ this.generalLoader = true;
this.error = null;
const response = await this.projectPublishService.createProjectSettingsAsync(
@@ -184,14 +181,14 @@ class ProjectPublishStore implements IProjectPublishStore {
runInAction(() => {
this.projectPublishSettings = _projectPublishSettings;
- this.loader = false;
+ this.generalLoader = false;
this.error = null;
});
return response;
}
} catch (error) {
- this.loader = false;
+ this.generalLoader = false;
this.error = error;
return error;
}
@@ -205,7 +202,7 @@ class ProjectPublishStore implements IProjectPublishStore {
user: any
) => {
try {
- this.loader = true;
+ this.generalLoader = true;
this.error = null;
const response = await this.projectPublishService.updateProjectSettingsAsync(
@@ -229,27 +226,27 @@ class ProjectPublishStore implements IProjectPublishStore {
runInAction(() => {
this.projectPublishSettings = _projectPublishSettings;
- this.loader = false;
+ this.generalLoader = false;
this.error = null;
});
return response;
}
} catch (error) {
- this.loader = false;
+ this.generalLoader = false;
this.error = error;
return error;
}
};
- deleteProjectSettingsAsync = async (
+ unPublishProject = async (
workspace_slug: string,
project_slug: string,
project_publish_id: string,
user: any
) => {
try {
- this.loader = true;
+ this.generalLoader = true;
this.error = null;
const response = await this.projectPublishService.deleteProjectSettingsAsync(
@@ -261,13 +258,13 @@ class ProjectPublishStore implements IProjectPublishStore {
runInAction(() => {
this.projectPublishSettings = "not-initialized";
- this.loader = false;
+ this.generalLoader = false;
this.error = null;
});
return response;
} catch (error) {
- this.loader = false;
+ this.generalLoader = false;
this.error = error;
return error;
}
diff --git a/web/store/project.ts b/web/store/project.ts
new file mode 100644
index 000000000..0fe842dad
--- /dev/null
+++ b/web/store/project.ts
@@ -0,0 +1,86 @@
+import { observable, action, computed, makeObservable, runInAction } from "mobx";
+// types
+import { RootStore } from "./root";
+// services
+import { ProjectServices } from "services/project.service";
+
+export interface IProject {
+ id: string;
+ name: string;
+ workspaceSlug: string;
+}
+
+export interface IProjectStore {
+ loader: boolean;
+ error: any | null;
+
+ projectLeaveModal: boolean;
+ projectLeaveDetails: IProject | any;
+
+ handleProjectLeaveModal: (project: IProject | null) => void;
+
+ leaveProject: (workspace_slug: string, project_slug: string, user: any) => Promise;
+}
+
+class ProjectStore implements IProjectStore {
+ loader: boolean = false;
+ error: any | null = null;
+
+ projectLeaveModal: boolean = false;
+ projectLeaveDetails: IProject | null = null;
+
+ // root store
+ rootStore;
+ // service
+ projectService;
+
+ constructor(_rootStore: RootStore) {
+ makeObservable(this, {
+ // observable
+ loader: observable,
+ error: observable,
+
+ projectLeaveModal: observable,
+ projectLeaveDetails: observable.ref,
+ // action
+ handleProjectLeaveModal: action,
+ leaveProject: action,
+ // computed
+ });
+
+ this.rootStore = _rootStore;
+ this.projectService = new ProjectServices();
+ }
+
+ handleProjectLeaveModal = (project: IProject | null = null) => {
+ if (project && project?.id) {
+ this.projectLeaveModal = !this.projectLeaveModal;
+ this.projectLeaveDetails = project;
+ } else {
+ this.projectLeaveModal = !this.projectLeaveModal;
+ this.projectLeaveDetails = null;
+ }
+ };
+
+ leaveProject = async (workspace_slug: string, project_slug: string, user: any) => {
+ try {
+ this.loader = true;
+ this.error = null;
+
+ const response = await this.projectService.leaveProject(workspace_slug, project_slug, user);
+
+ runInAction(() => {
+ this.loader = false;
+ this.error = null;
+ });
+
+ return response;
+ } catch (error) {
+ this.loader = false;
+ this.error = error;
+ return error;
+ }
+ };
+}
+
+export default ProjectStore;
diff --git a/apps/app/store/root.ts b/web/store/root.ts
similarity index 70%
rename from apps/app/store/root.ts
rename to web/store/root.ts
index 5895637a8..ce0bdfad5 100644
--- a/apps/app/store/root.ts
+++ b/web/store/root.ts
@@ -3,18 +3,24 @@ import { enableStaticRendering } from "mobx-react-lite";
// store imports
import UserStore from "./user";
import ThemeStore from "./theme";
+import ProjectStore, { IProjectStore } from "./project";
import ProjectPublishStore, { IProjectPublishStore } from "./project-publish";
+import IssuesStore from "./issues";
enableStaticRendering(typeof window === "undefined");
export class RootStore {
user;
theme;
+ project: IProjectStore;
projectPublish: IProjectPublishStore;
+ issues: IssuesStore;
constructor() {
this.user = new UserStore(this);
this.theme = new ThemeStore(this);
+ this.project = new ProjectStore(this);
this.projectPublish = new ProjectPublishStore(this);
+ this.issues = new IssuesStore(this);
}
}
diff --git a/apps/app/store/theme.ts b/web/store/theme.ts
similarity index 100%
rename from apps/app/store/theme.ts
rename to web/store/theme.ts
diff --git a/apps/app/store/user.ts b/web/store/user.ts
similarity index 100%
rename from apps/app/store/user.ts
rename to web/store/user.ts
diff --git a/apps/app/styles/command-pallette.css b/web/styles/command-pallette.css
similarity index 100%
rename from apps/app/styles/command-pallette.css
rename to web/styles/command-pallette.css
diff --git a/web/styles/editor.css b/web/styles/editor.css
new file mode 100644
index 000000000..9da250dd1
--- /dev/null
+++ b/web/styles/editor.css
@@ -0,0 +1,231 @@
+.ProseMirror p.is-editor-empty:first-child::before {
+ content: attr(data-placeholder);
+ float: left;
+ color: rgb(var(--color-text-400));
+ pointer-events: none;
+ height: 0;
+}
+
+.ProseMirror .is-empty::before {
+ content: attr(data-placeholder);
+ float: left;
+ color: rgb(var(--color-text-400));
+ pointer-events: none;
+ height: 0;
+}
+
+/* Custom image styles */
+
+.ProseMirror img {
+ transition: filter 0.1s ease-in-out;
+
+ &:hover {
+ cursor: pointer;
+ filter: brightness(90%);
+ }
+
+ &.ProseMirror-selectednode {
+ outline: 3px solid #5abbf7;
+ filter: brightness(90%);
+ }
+}
+
+.ProseMirror-gapcursor:after {
+ border-top: 1px solid rgb(var(--color-text-100)) !important;
+}
+
+/* Custom TODO list checkboxes – shoutout to this awesome tutorial: https://moderncss.dev/pure-css-custom-checkbox-style/ */
+
+ul[data-type="taskList"] li > label {
+ margin-right: 0.2rem;
+ user-select: none;
+}
+
+@media screen and (max-width: 768px) {
+ ul[data-type="taskList"] li > label {
+ margin-right: 0.5rem;
+ }
+}
+
+ul[data-type="taskList"] li > label input[type="checkbox"] {
+ -webkit-appearance: none;
+ appearance: none;
+ background-color: rgb(var(--color-background-100));
+ margin: 0;
+ cursor: pointer;
+ width: 1.2rem;
+ height: 1.2rem;
+ position: relative;
+ border: 2px solid rgb(var(--color-text-100));
+ margin-right: 0.3rem;
+ display: grid;
+ place-content: center;
+
+ &:hover {
+ background-color: rgb(var(--color-background-80));
+ }
+
+ &:active {
+ background-color: rgb(var(--color-background-90));
+ }
+
+ &::before {
+ content: "";
+ width: 0.65em;
+ height: 0.65em;
+ transform: scale(0);
+ transition: 120ms transform ease-in-out;
+ box-shadow: inset 1em 1em;
+ transform-origin: center;
+ clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
+ }
+
+ &:checked::before {
+ transform: scale(1);
+ }
+}
+
+ul[data-type="taskList"] li[data-checked="true"] > div > p {
+ color: rgb(var(--color-text-200));
+ text-decoration: line-through;
+ text-decoration-thickness: 2px;
+}
+
+/* Overwrite tippy-box original max-width */
+
+.tippy-box {
+ max-width: 400px !important;
+}
+
+.ProseMirror {
+ position: relative;
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ -moz-tab-size: 4;
+ tab-size: 4;
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+ outline: none;
+ cursor: text;
+ line-height: 1.2;
+ font-family: inherit;
+ font-size: 14px;
+ color: inherit;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ appearance: textfield;
+ -webkit-appearance: textfield;
+ -moz-appearance: textfield;
+}
+
+.fadeIn {
+ opacity: 1;
+ transition: opacity 0.3s ease-in;
+}
+
+.fadeOut {
+ opacity: 0;
+ transition: opacity 0.2s ease-out;
+}
+
+.img-placeholder {
+ position: relative;
+ width: 35%;
+
+ &:before {
+ content: "";
+ box-sizing: border-box;
+ position: absolute;
+ top: 50%;
+ left: 45%;
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ border: 3px solid rgba(var(--color-text-200));
+ border-top-color: rgba(var(--color-text-800));
+ animation: spinning 0.6s linear infinite;
+ }
+}
+
+@keyframes spinning {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+#tiptap-container {
+ table {
+ border-collapse: collapse;
+ table-layout: fixed;
+ margin: 0;
+ border: 1px solid rgb(var(--color-border-200));
+ width: 100%;
+
+ td,
+ th {
+ min-width: 1em;
+ border: 1px solid rgb(var(--color-border-200));
+ padding: 10px 15px;
+ vertical-align: top;
+ box-sizing: border-box;
+ position: relative;
+ transition: background-color 0.3s ease;
+
+ > * {
+ margin-bottom: 0;
+ }
+ }
+
+ th {
+ font-weight: bold;
+ text-align: left;
+ background-color: rgb(var(--color-primary-100));
+ }
+
+ td:hover {
+ background-color: rgba(var(--color-primary-300), 0.1);
+ }
+
+ .selectedCell:after {
+ z-index: 2;
+ position: absolute;
+ content: "";
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ background-color: rgba(var(--color-primary-300), 0.1);
+ pointer-events: none;
+ }
+
+ .column-resize-handle {
+ position: absolute;
+ right: -2px;
+ top: 0;
+ bottom: -2px;
+ width: 2px;
+ background-color: rgb(var(--color-primary-400));
+ pointer-events: none;
+ }
+ }
+}
+
+.tableWrapper {
+ overflow-x: auto;
+}
+
+.resize-cursor {
+ cursor: ew-resize;
+ cursor: col-resize;
+}
+
+.ProseMirror table * p {
+ padding: 0px 1px;
+ margin: 6px 2px;
+}
+
+.ProseMirror table * .is-empty::before {
+ opacity: 0;
+}
diff --git a/apps/app/styles/globals.css b/web/styles/globals.css
similarity index 77%
rename from apps/app/styles/globals.css
rename to web/styles/globals.css
index b8f662902..3de1e2c57 100644
--- a/apps/app/styles/globals.css
+++ b/web/styles/globals.css
@@ -58,6 +58,25 @@
--color-border-300: 212, 212, 212; /* strong border- 1 */
--color-border-400: 185, 185, 185; /* strong border- 2 */
+ --color-shadow-2xs: 0px 0px 1px 0px rgba(23, 23, 23, 0.06),
+ 0px 1px 2px 0px rgba(23, 23, 23, 0.06), 0px 1px 2px 0px rgba(23, 23, 23, 0.14);
+ --color-shadow-xs: 0px 1px 2px 0px rgba(0, 0, 0, 0.16), 0px 2px 4px 0px rgba(16, 24, 40, 0.12),
+ 0px 1px 8px -1px rgba(16, 24, 40, 0.1);
+ --color-shadow-sm: 0px 1px 4px 0px rgba(0, 0, 0, 0.01), 0px 4px 8px 0px rgba(0, 0, 0, 0.02),
+ 0px 1px 12px 0px rgba(0, 0, 0, 0.12);
+ --color-shadow-rg: 0px 3px 6px 0px rgba(0, 0, 0, 0.1), 0px 4px 4px 0px rgba(16, 24, 40, 0.08),
+ 0px 1px 12px 0px rgba(16, 24, 40, 0.04);
+ --color-shadow-md: 0px 4px 8px 0px rgba(0, 0, 0, 0.12), 0px 6px 12px 0px rgba(16, 24, 40, 0.12),
+ 0px 1px 16px 0px rgba(16, 24, 40, 0.12);
+ --color-shadow-lg: 0px 6px 12px 0px rgba(0, 0, 0, 0.12), 0px 8px 16px 0px rgba(0, 0, 0, 0.12),
+ 0px 1px 24px 0px rgba(16, 24, 40, 0.12);
+ --color-shadow-xl: 0px 0px 18px 0px rgba(0, 0, 0, 0.16), 0px 0px 24px 0px rgba(16, 24, 40, 0.16),
+ 0px 0px 52px 0px rgba(16, 24, 40, 0.16);
+ --color-shadow-2xl: 0px 8px 16px 0px rgba(0, 0, 0, 0.12),
+ 0px 12px 24px 0px rgba(16, 24, 40, 0.12), 0px 1px 32px 0px rgba(16, 24, 40, 0.12);
+ --color-shadow-3xl: 0px 12px 24px 0px rgba(0, 0, 0, 0.12), 0px 16px 32px 0px rgba(0, 0, 0, 0.12),
+ 0px 1px 48px 0px rgba(16, 24, 40, 0.12);
+
--color-sidebar-background-100: var(--color-background-100); /* primary sidebar bg */
--color-sidebar-background-90: var(--color-background-90); /* secondary sidebar bg */
--color-sidebar-background-80: var(--color-background-80); /* tertiary sidebar bg */
@@ -71,6 +90,16 @@
--color-sidebar-border-200: var(--color-border-100); /* subtle sidebar border- 2 */
--color-sidebar-border-300: var(--color-border-100); /* strong sidebar border- 1 */
--color-sidebar-border-400: var(--color-border-100); /* strong sidebar border- 2 */
+
+ --color-sidebar-shadow-2xs: var(--color-shadow-2xs);
+ --color-sidebar-shadow-xs: var(--color-shadow-xs);
+ --color-sidebar-shadow-sm: var(--color-shadow-sm);
+ --color-sidebar-shadow-rg: var(--color-shadow-rg);
+ --color-sidebar-shadow-md: var(--color-shadow-md);
+ --color-sidebar-shadow-lg: var(--color-shadow-lg);
+ --color-sidebar-shadow-xl: var(--color-shadow-xl);
+ --color-sidebar-shadow-2xl: var(--color-shadow-2xl);
+ --color-sidebar-shadow-3xl: var(--color-shadow-3xl);
}
[data-theme="light"],
@@ -113,6 +142,16 @@
--color-background-100: 7, 7, 7; /* primary bg */
--color-background-90: 11, 11, 11; /* secondary bg */
--color-background-80: 23, 23, 23; /* tertiary bg */
+
+ --color-shadow-2xs: 0px 0px 1px 0px rgba(0, 0, 0, 0.15), 0px 1px 3px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-xs: 0px 0px 2px 0px rgba(0, 0, 0, 0.2), 0px 2px 4px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-sm: 0px 0px 4px 0px rgba(0, 0, 0, 0.2), 0px 2px 6px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-rg: 0px 0px 6px 0px rgba(0, 0, 0, 0.2), 0px 4px 6px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-md: 0px 2px 8px 0px rgba(0, 0, 0, 0.2), 0px 4px 8px 0px rgba(0, 0, 0, 0.5);
+ --color-shadow-lg: 0px 4px 12px 0px rgba(0, 0, 0, 0.25), 0px 4px 10px 0px rgba(0, 0, 0, 0.55);
+ --color-shadow-xl: 0px 0px 14px 0px rgba(0, 0, 0, 0.25), 0px 6px 10px 0px rgba(0, 0, 0, 0.55);
+ --color-shadow-2xl: 0px 0px 18px 0px rgba(0, 0, 0, 0.25), 0px 8px 12px 0px rgba(0, 0, 0, 0.6);
+ --color-shadow-3xl: 0px 4px 24px 0px rgba(0, 0, 0, 0.3), 0px 12px 40px 0px rgba(0, 0, 0, 0.65);
}
[data-theme="dark"] {
@@ -316,3 +355,7 @@ body {
.bp4-overlay-content {
z-index: 555 !important;
}
+
+.disable-scroll {
+ overflow: hidden !important;
+}
diff --git a/apps/app/styles/nprogress.css b/web/styles/nprogress.css
similarity index 100%
rename from apps/app/styles/nprogress.css
rename to web/styles/nprogress.css
diff --git a/apps/app/styles/react-datepicker.css b/web/styles/react-datepicker.css
similarity index 100%
rename from apps/app/styles/react-datepicker.css
rename to web/styles/react-datepicker.css
diff --git a/apps/app/tailwind.config.js b/web/tailwind.config.js
similarity index 87%
rename from apps/app/tailwind.config.js
rename to web/tailwind.config.js
index 11e1946a5..0b7b5861a 100644
--- a/apps/app/tailwind.config.js
+++ b/web/tailwind.config.js
@@ -5,6 +5,26 @@ module.exports = {
content: ["./pages/**/*.tsx", "./components/**/*.tsx", "./layouts/**/*.tsx", "./ui/**/*.tsx"],
theme: {
extend: {
+ boxShadow: {
+ "custom-shadow-2xs": "var(--color-shadow-2xs)",
+ "custom-shadow-xs": "var(--color-shadow-xs)",
+ "custom-shadow-sm": "var(--color-shadow-sm)",
+ "custom-shadow-rg": "var(--color-shadow-rg)",
+ "custom-shadow-md": "var(--color-shadow-md)",
+ "custom-shadow-lg": "var(--color-shadow-lg)",
+ "custom-shadow-xl": "var(--color-shadow-xl)",
+ "custom-shadow-2xl": "var(--color-shadow-2xl)",
+ "custom-shadow-3xl": "var(--color-shadow-3xl)",
+ "custom-sidebar-shadow-2xs": "var(--color-sidebar-shadow-2xs)",
+ "custom-sidebar-shadow-xs": "var(--color-sidebar-shadow-xs)",
+ "custom-sidebar-shadow-sm": "var(--color-sidebar-shadow-sm)",
+ "custom-sidebar-shadow-rg": "var(--color-sidebar-shadow-rg)",
+ "custom-sidebar-shadow-md": "var(--color-sidebar-shadow-md)",
+ "custom-sidebar-shadow-lg": "var(--color-sidebar-shadow-lg)",
+ "custom-sidebar-shadow-xl": "var(--color-sidebar-shadow-xl)",
+ "custom-sidebar-shadow-2xl": "var(--color-sidebar-shadow-2xl)",
+ "custom-sidebar-shadow-3xl": "var(--color-sidebar-shadow-3xl)",
+ },
colors: {
custom: {
primary: {
@@ -182,8 +202,5 @@ module.exports = {
custom: ["Inter", "sans-serif"],
},
},
- plugins: [
- require("tailwindcss-animate"),
- require("@tailwindcss/typography")
- ],
+ plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
};
diff --git a/web/tsconfig.json b/web/tsconfig.json
new file mode 100644
index 000000000..63c95575d
--- /dev/null
+++ b/web/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "tsconfig/nextjs.json",
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
+ "exclude": ["node_modules"],
+ "compilerOptions": {
+ "baseUrl": ".",
+ "jsx": "preserve"
+ }
+}
diff --git a/apps/app/types/ai.d.ts b/web/types/ai.d.ts
similarity index 100%
rename from apps/app/types/ai.d.ts
rename to web/types/ai.d.ts
diff --git a/apps/app/types/analytics.d.ts b/web/types/analytics.d.ts
similarity index 100%
rename from apps/app/types/analytics.d.ts
rename to web/types/analytics.d.ts
diff --git a/apps/app/types/calendar.ts b/web/types/calendar.ts
similarity index 100%
rename from apps/app/types/calendar.ts
rename to web/types/calendar.ts
diff --git a/apps/app/types/cycles.d.ts b/web/types/cycles.d.ts
similarity index 100%
rename from apps/app/types/cycles.d.ts
rename to web/types/cycles.d.ts
diff --git a/apps/app/types/estimate.d.ts b/web/types/estimate.d.ts
similarity index 100%
rename from apps/app/types/estimate.d.ts
rename to web/types/estimate.d.ts
diff --git a/apps/app/types/importer/github-importer.d.ts b/web/types/importer/github-importer.d.ts
similarity index 100%
rename from apps/app/types/importer/github-importer.d.ts
rename to web/types/importer/github-importer.d.ts
diff --git a/apps/app/types/importer/index.ts b/web/types/importer/index.ts
similarity index 100%
rename from apps/app/types/importer/index.ts
rename to web/types/importer/index.ts
diff --git a/apps/app/types/importer/jira-importer.d.ts b/web/types/importer/jira-importer.d.ts
similarity index 100%
rename from apps/app/types/importer/jira-importer.d.ts
rename to web/types/importer/jira-importer.d.ts
diff --git a/apps/app/types/inbox.d.ts b/web/types/inbox.d.ts
similarity index 100%
rename from apps/app/types/inbox.d.ts
rename to web/types/inbox.d.ts
diff --git a/apps/app/types/index.d.ts b/web/types/index.d.ts
similarity index 99%
rename from apps/app/types/index.d.ts
rename to web/types/index.d.ts
index 8c9592917..dbd314826 100644
--- a/apps/app/types/index.d.ts
+++ b/web/types/index.d.ts
@@ -19,7 +19,6 @@ export * from "./notifications";
export * from "./waitlist";
export * from "./reaction";
-
export type NestedKeyOf = {
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
? ObjectType[Key] extends { pop: any; push: any }
diff --git a/apps/app/types/integration.d.ts b/web/types/integration.d.ts
similarity index 100%
rename from apps/app/types/integration.d.ts
rename to web/types/integration.d.ts
diff --git a/apps/app/types/issues.d.ts b/web/types/issues.d.ts
similarity index 97%
rename from apps/app/types/issues.d.ts
rename to web/types/issues.d.ts
index 9cbcef847..93e1598f3 100644
--- a/apps/app/types/issues.d.ts
+++ b/web/types/issues.d.ts
@@ -198,6 +198,7 @@ export interface IIssueActivity {
}
export interface IIssueComment extends IIssueActivity {
+ access: "EXTERNAL" | "INTERNAL";
comment_html: string;
comment_json: any;
comment_stripped: string;
@@ -215,6 +216,7 @@ export interface IIssueLite {
export interface IIssueFilterOptions {
type: "active" | "backlog" | null;
assignees: string[] | null;
+ start_date: string[] | null;
target_date: string[] | null;
state: string[] | null;
state_group: TStateGroups[] | null;
@@ -233,6 +235,7 @@ export type TIssueGroupByOptions =
| "created_by"
| "state_detail.group"
| "project"
+ | "assignees"
| null;
export type TIssueOrderByOptions =
@@ -249,7 +252,9 @@ export type TIssueOrderByOptions =
| "target_date"
| "-target_date"
| "estimate__point"
- | "-estimate__point";
+ | "-estimate__point"
+ | "start_date"
+ | "-start_date";
export interface IIssueViewOptions {
group_by: TIssueGroupByOptions;
diff --git a/apps/app/types/modules.d.ts b/web/types/modules.d.ts
similarity index 92%
rename from apps/app/types/modules.d.ts
rename to web/types/modules.d.ts
index e395f6f16..709d1d300 100644
--- a/apps/app/types/modules.d.ts
+++ b/web/types/modules.d.ts
@@ -10,6 +10,14 @@ import type {
linkDetails,
} from "types";
+export type TModuleStatus =
+ | "backlog"
+ | "planned"
+ | "in-progress"
+ | "paused"
+ | "completed"
+ | "cancelled";
+
export interface IModule {
backlog_issues: number;
cancelled_issues: number;
@@ -39,7 +47,7 @@ export interface IModule {
sort_order: number;
start_date: string | null;
started_issues: number;
- status: "backlog" | "planned" | "in-progress" | "paused" | "completed" | "cancelled" | null;
+ status: TModuleStatus;
target_date: string | null;
total_issues: number;
unstarted_issues: number;
diff --git a/apps/app/types/notifications.d.ts b/web/types/notifications.d.ts
similarity index 92%
rename from apps/app/types/notifications.d.ts
rename to web/types/notifications.d.ts
index adb4e469a..8033c19a9 100644
--- a/apps/app/types/notifications.d.ts
+++ b/web/types/notifications.d.ts
@@ -71,3 +71,9 @@ export type NotificationCount = {
my_issues: number;
watching_issues: number;
};
+
+export interface IMarkAllAsReadPayload {
+ archived?: boolean;
+ snoozed?: boolean;
+ type?: NotificationType;
+}
diff --git a/apps/app/types/pages.d.ts b/web/types/pages.d.ts
similarity index 100%
rename from apps/app/types/pages.d.ts
rename to web/types/pages.d.ts
diff --git a/apps/app/types/projects.d.ts b/web/types/projects.d.ts
similarity index 99%
rename from apps/app/types/projects.d.ts
rename to web/types/projects.d.ts
index a3d8b997a..590fe5023 100644
--- a/apps/app/types/projects.d.ts
+++ b/web/types/projects.d.ts
@@ -8,7 +8,7 @@ import type {
TIssueOrderByOptions,
TIssueViewOptions,
TStateGroups,
-} from "./";
+} from ".";
export interface IProject {
archive_in: number;
@@ -39,6 +39,7 @@ export interface IProject {
} | null;
id: string;
identifier: string;
+ is_deployed: boolean;
is_favorite: boolean;
is_member: boolean;
member_role: 5 | 10 | 15 | 20 | null;
@@ -57,7 +58,6 @@ export interface IProject {
updated_by: string;
workspace: IWorkspace | string;
workspace_detail: IWorkspaceLite;
- is_deployed: boolean;
}
export interface IProjectLite {
diff --git a/apps/app/types/reaction.d.ts b/web/types/reaction.d.ts
similarity index 100%
rename from apps/app/types/reaction.d.ts
rename to web/types/reaction.d.ts
diff --git a/apps/app/types/state.d.ts b/web/types/state.d.ts
similarity index 100%
rename from apps/app/types/state.d.ts
rename to web/types/state.d.ts
diff --git a/apps/app/types/users.d.ts b/web/types/users.d.ts
similarity index 99%
rename from apps/app/types/users.d.ts
rename to web/types/users.d.ts
index b41d1f8ef..8440922d1 100644
--- a/apps/app/types/users.d.ts
+++ b/web/types/users.d.ts
@@ -7,7 +7,7 @@ import {
NestedKeyOf,
Properties,
TStateGroups,
-} from "./";
+} from ".";
export interface IUser {
avatar: string;
@@ -36,6 +36,7 @@ export interface IUser {
theme: ICustomTheme;
updated_at: readonly Date;
username: string;
+ user_timezone: string;
[...rest: string]: any;
}
diff --git a/apps/app/types/views.d.ts b/web/types/views.d.ts
similarity index 94%
rename from apps/app/types/views.d.ts
rename to web/types/views.d.ts
index 9bd133600..e1246af5a 100644
--- a/apps/app/types/views.d.ts
+++ b/web/types/views.d.ts
@@ -20,6 +20,7 @@ export interface IQuery {
labels: string[] | null;
priority: string[] | null;
state: string[] | null;
+ start_date: string[] | null;
target_date: string[] | null;
type: "active" | "backlog" | null;
}
diff --git a/apps/app/types/waitlist.d.ts b/web/types/waitlist.d.ts
similarity index 100%
rename from apps/app/types/waitlist.d.ts
rename to web/types/waitlist.d.ts
diff --git a/apps/app/types/workspace.d.ts b/web/types/workspace.d.ts
similarity index 100%
rename from apps/app/types/workspace.d.ts
rename to web/types/workspace.d.ts
diff --git a/yarn.lock b/yarn.lock
index ac134d60f..1aa8e5bde 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -37,37 +37,37 @@
"@babel/highlight" "^7.10.4"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.10", "@babel/code-frame@^7.22.5":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3"
- integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==
+ version "7.22.13"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
+ integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
dependencies:
- "@babel/highlight" "^7.22.10"
+ "@babel/highlight" "^7.22.13"
chalk "^2.4.2"
-"@babel/compat-data@^7.22.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9":
+"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9":
version "7.22.9"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730"
integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==
"@babel/core@^7.11.1":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.10.tgz#aad442c7bcd1582252cb4576747ace35bc122f35"
- integrity sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.11.tgz#8033acaa2aa24c3f814edaaa057f3ce0ba559c24"
+ integrity sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.22.10"
"@babel/generator" "^7.22.10"
"@babel/helper-compilation-targets" "^7.22.10"
"@babel/helper-module-transforms" "^7.22.9"
- "@babel/helpers" "^7.22.10"
- "@babel/parser" "^7.22.10"
+ "@babel/helpers" "^7.22.11"
+ "@babel/parser" "^7.22.11"
"@babel/template" "^7.22.5"
- "@babel/traverse" "^7.22.10"
- "@babel/types" "^7.22.10"
+ "@babel/traverse" "^7.22.11"
+ "@babel/types" "^7.22.11"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
- json5 "^2.2.2"
+ json5 "^2.2.3"
semver "^6.3.1"
"@babel/generator@^7.22.10":
@@ -105,10 +105,10 @@
lru-cache "^5.1.1"
semver "^6.3.1"
-"@babel/helper-create-class-features-plugin@^7.22.5":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.10.tgz#dd2612d59eac45588021ac3d6fa976d08f4e95a3"
- integrity sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA==
+"@babel/helper-create-class-features-plugin@^7.22.11", "@babel/helper-create-class-features-plugin@^7.22.5":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.11.tgz#4078686740459eeb4af3494a273ac09148dfb213"
+ integrity sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ==
dependencies:
"@babel/helper-annotate-as-pure" "^7.22.5"
"@babel/helper-environment-visitor" "^7.22.5"
@@ -260,28 +260,28 @@
"@babel/template" "^7.22.5"
"@babel/types" "^7.22.10"
-"@babel/helpers@^7.22.10":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.10.tgz#ae6005c539dfbcb5cd71fb51bfc8a52ba63bc37a"
- integrity sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==
+"@babel/helpers@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.11.tgz#b02f5d5f2d7abc21ab59eeed80de410ba70b056a"
+ integrity sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==
dependencies:
"@babel/template" "^7.22.5"
- "@babel/traverse" "^7.22.10"
- "@babel/types" "^7.22.10"
+ "@babel/traverse" "^7.22.11"
+ "@babel/types" "^7.22.11"
-"@babel/highlight@^7.10.4", "@babel/highlight@^7.22.10":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7"
- integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==
+"@babel/highlight@^7.10.4", "@babel/highlight@^7.22.13":
+ version "7.22.13"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.13.tgz#9cda839e5d3be9ca9e8c26b6dd69e7548f0cbf16"
+ integrity sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==
dependencies:
"@babel/helper-validator-identifier" "^7.22.5"
chalk "^2.4.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.22.10", "@babel/parser@^7.22.5":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55"
- integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==
+"@babel/parser@^7.22.11", "@babel/parser@^7.22.5":
+ version "7.22.14"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.14.tgz#c7de58e8de106e88efca42ce17f0033209dfd245"
+ integrity sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5":
version "7.22.5"
@@ -438,10 +438,10 @@
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-async-generator-functions@^7.22.10":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.10.tgz#45946cd17f915b10e65c29b8ed18a0a50fc648c8"
- integrity sha512-eueE8lvKVzq5wIObKK/7dvoeKJ+xc6TvRn6aysIjS6pSCeLy7S/eVi7pEQknZqyqvzaNKdDtem8nUNTBgDVR2g==
+"@babel/plugin-transform-async-generator-functions@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.11.tgz#dbe3b1ff5a52e2e5edc4b19a60d325a675ed2649"
+ integrity sha512-0pAlmeRJn6wU84zzZsEOx1JV1Jf8fqO9ok7wofIJwUnplYo247dcd24P+cMJht7ts9xkzdtB0EPHmOb7F+KzXw==
dependencies:
"@babel/helper-environment-visitor" "^7.22.5"
"@babel/helper-plugin-utils" "^7.22.5"
@@ -479,12 +479,12 @@
"@babel/helper-create-class-features-plugin" "^7.22.5"
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-class-static-block@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz#3e40c46f048403472d6f4183116d5e46b1bff5ba"
- integrity sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==
+"@babel/plugin-transform-class-static-block@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz#dc8cc6e498f55692ac6b4b89e56d87cec766c974"
+ integrity sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.22.5"
+ "@babel/helper-create-class-features-plugin" "^7.22.11"
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-class-static-block" "^7.14.5"
@@ -533,10 +533,10 @@
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-dynamic-import@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz#d6908a8916a810468c4edff73b5b75bda6ad393e"
- integrity sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==
+"@babel/plugin-transform-dynamic-import@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz#2c7722d2a5c01839eaf31518c6ff96d408e447aa"
+ integrity sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-dynamic-import" "^7.8.3"
@@ -549,10 +549,10 @@
"@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5"
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-export-namespace-from@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz#57c41cb1d0613d22f548fddd8b288eedb9973a5b"
- integrity sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==
+"@babel/plugin-transform-export-namespace-from@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz#b3c84c8f19880b6c7440108f8929caf6056db26c"
+ integrity sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-export-namespace-from" "^7.8.3"
@@ -573,10 +573,10 @@
"@babel/helper-function-name" "^7.22.5"
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-json-strings@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz#14b64352fdf7e1f737eed68de1a1468bd2a77ec0"
- integrity sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==
+"@babel/plugin-transform-json-strings@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz#689a34e1eed1928a40954e37f74509f48af67835"
+ integrity sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-json-strings" "^7.8.3"
@@ -588,10 +588,10 @@
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-logical-assignment-operators@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz#66ae5f068fd5a9a5dc570df16f56c2a8462a9d6c"
- integrity sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==
+"@babel/plugin-transform-logical-assignment-operators@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz#24c522a61688bde045b7d9bc3c2597a4d948fc9c"
+ integrity sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
@@ -611,22 +611,22 @@
"@babel/helper-module-transforms" "^7.22.5"
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-modules-commonjs@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz#7d9875908d19b8c0536085af7b053fd5bd651bfa"
- integrity sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==
+"@babel/plugin-transform-modules-commonjs@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.11.tgz#d7991d3abad199c03b68ee66a64f216c47ffdfae"
+ integrity sha512-o2+bg7GDS60cJMgz9jWqRUsWkMzLCxp+jFDeDUT5sjRlAxcJWZ2ylNdI7QQ2+CH5hWu7OnN+Cv3htt7AkSf96g==
dependencies:
- "@babel/helper-module-transforms" "^7.22.5"
+ "@babel/helper-module-transforms" "^7.22.9"
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/helper-simple-access" "^7.22.5"
-"@babel/plugin-transform-modules-systemjs@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz#18c31410b5e579a0092638f95c896c2a98a5d496"
- integrity sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==
+"@babel/plugin-transform-modules-systemjs@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz#3386be5875d316493b517207e8f1931d93154bb1"
+ integrity sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==
dependencies:
"@babel/helper-hoist-variables" "^7.22.5"
- "@babel/helper-module-transforms" "^7.22.5"
+ "@babel/helper-module-transforms" "^7.22.9"
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.5"
@@ -653,29 +653,29 @@
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-nullish-coalescing-operator@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz#f8872c65776e0b552e0849d7596cddd416c3e381"
- integrity sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==
+"@babel/plugin-transform-nullish-coalescing-operator@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz#debef6c8ba795f5ac67cd861a81b744c5d38d9fc"
+ integrity sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
-"@babel/plugin-transform-numeric-separator@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz#57226a2ed9e512b9b446517ab6fa2d17abb83f58"
- integrity sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==
+"@babel/plugin-transform-numeric-separator@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz#498d77dc45a6c6db74bb829c02a01c1d719cbfbd"
+ integrity sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-numeric-separator" "^7.10.4"
-"@babel/plugin-transform-object-rest-spread@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz#9686dc3447df4753b0b2a2fae7e8bc33cdc1f2e1"
- integrity sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==
+"@babel/plugin-transform-object-rest-spread@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.11.tgz#dbbb06ce783cd994a8f430d8cefa553e9b42ca62"
+ integrity sha512-nX8cPFa6+UmbepISvlf5jhQyaC7ASs/7UxHmMkuJ/k5xSHvDPPaibMo+v3TXwU/Pjqhep/nFNpd3zn4YR59pnw==
dependencies:
- "@babel/compat-data" "^7.22.5"
- "@babel/helper-compilation-targets" "^7.22.5"
+ "@babel/compat-data" "^7.22.9"
+ "@babel/helper-compilation-targets" "^7.22.10"
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-object-rest-spread" "^7.8.3"
"@babel/plugin-transform-parameters" "^7.22.5"
@@ -688,18 +688,18 @@
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/helper-replace-supers" "^7.22.5"
-"@babel/plugin-transform-optional-catch-binding@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz#842080be3076703be0eaf32ead6ac8174edee333"
- integrity sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==
+"@babel/plugin-transform-optional-catch-binding@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz#461cc4f578a127bb055527b3e77404cad38c08e0"
+ integrity sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
-"@babel/plugin-transform-optional-chaining@^7.22.10", "@babel/plugin-transform-optional-chaining@^7.22.5":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.10.tgz#076d28a7e074392e840d4ae587d83445bac0372a"
- integrity sha512-MMkQqZAZ+MGj+jGTG3OTuhKeBpNcO+0oCEbrGNEaOmiEn+1MzRyQlYsruGiU8RTK3zV6XwrVJTmwiDOyYK6J9g==
+"@babel/plugin-transform-optional-chaining@^7.22.12", "@babel/plugin-transform-optional-chaining@^7.22.5":
+ version "7.22.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.12.tgz#d7ebf6a88cd2f4d307b0e000ab630acd8124b333"
+ integrity sha512-7XXCVqZtyFWqjDsYDY4T45w4mlx1rf7aOgkc/Ww76xkgBiOlmjPkx36PBLHa1k1rwWvVgYMPsbuVnIamx2ZQJw==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/helper-skip-transparent-expression-wrappers" "^7.22.5"
@@ -720,13 +720,13 @@
"@babel/helper-create-class-features-plugin" "^7.22.5"
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-transform-private-property-in-object@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz#07a77f28cbb251546a43d175a1dda4cf3ef83e32"
- integrity sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==
+"@babel/plugin-transform-private-property-in-object@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz#ad45c4fc440e9cb84c718ed0906d96cf40f9a4e1"
+ integrity sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==
dependencies:
"@babel/helper-annotate-as-pure" "^7.22.5"
- "@babel/helper-create-class-features-plugin" "^7.22.5"
+ "@babel/helper-create-class-features-plugin" "^7.22.11"
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
@@ -820,9 +820,9 @@
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/preset-env@^7.11.0":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.10.tgz#3263b9fe2c8823d191d28e61eac60a79f9ce8a0f"
- integrity sha512-riHpLb1drNkpLlocmSyEg4oYJIQFeXAK/d7rI6mbD0XsvoTOOweXDmQPG/ErxsEhWk3rl3Q/3F6RFQlVFS8m0A==
+ version "7.22.14"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.14.tgz#1cbb468d899f64fa71c53446f13b7ff8c0005cc1"
+ integrity sha512-daodMIoVo+ol/g+//c/AH+szBkFj4STQUikvBijRGL72Ph+w+AMTSh55DUETe8KJlPlDT1k/mp7NBfOuiWmoig==
dependencies:
"@babel/compat-data" "^7.22.9"
"@babel/helper-compilation-targets" "^7.22.10"
@@ -850,41 +850,41 @@
"@babel/plugin-syntax-top-level-await" "^7.14.5"
"@babel/plugin-syntax-unicode-sets-regex" "^7.18.6"
"@babel/plugin-transform-arrow-functions" "^7.22.5"
- "@babel/plugin-transform-async-generator-functions" "^7.22.10"
+ "@babel/plugin-transform-async-generator-functions" "^7.22.11"
"@babel/plugin-transform-async-to-generator" "^7.22.5"
"@babel/plugin-transform-block-scoped-functions" "^7.22.5"
"@babel/plugin-transform-block-scoping" "^7.22.10"
"@babel/plugin-transform-class-properties" "^7.22.5"
- "@babel/plugin-transform-class-static-block" "^7.22.5"
+ "@babel/plugin-transform-class-static-block" "^7.22.11"
"@babel/plugin-transform-classes" "^7.22.6"
"@babel/plugin-transform-computed-properties" "^7.22.5"
"@babel/plugin-transform-destructuring" "^7.22.10"
"@babel/plugin-transform-dotall-regex" "^7.22.5"
"@babel/plugin-transform-duplicate-keys" "^7.22.5"
- "@babel/plugin-transform-dynamic-import" "^7.22.5"
+ "@babel/plugin-transform-dynamic-import" "^7.22.11"
"@babel/plugin-transform-exponentiation-operator" "^7.22.5"
- "@babel/plugin-transform-export-namespace-from" "^7.22.5"
+ "@babel/plugin-transform-export-namespace-from" "^7.22.11"
"@babel/plugin-transform-for-of" "^7.22.5"
"@babel/plugin-transform-function-name" "^7.22.5"
- "@babel/plugin-transform-json-strings" "^7.22.5"
+ "@babel/plugin-transform-json-strings" "^7.22.11"
"@babel/plugin-transform-literals" "^7.22.5"
- "@babel/plugin-transform-logical-assignment-operators" "^7.22.5"
+ "@babel/plugin-transform-logical-assignment-operators" "^7.22.11"
"@babel/plugin-transform-member-expression-literals" "^7.22.5"
"@babel/plugin-transform-modules-amd" "^7.22.5"
- "@babel/plugin-transform-modules-commonjs" "^7.22.5"
- "@babel/plugin-transform-modules-systemjs" "^7.22.5"
+ "@babel/plugin-transform-modules-commonjs" "^7.22.11"
+ "@babel/plugin-transform-modules-systemjs" "^7.22.11"
"@babel/plugin-transform-modules-umd" "^7.22.5"
"@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5"
"@babel/plugin-transform-new-target" "^7.22.5"
- "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.5"
- "@babel/plugin-transform-numeric-separator" "^7.22.5"
- "@babel/plugin-transform-object-rest-spread" "^7.22.5"
+ "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.11"
+ "@babel/plugin-transform-numeric-separator" "^7.22.11"
+ "@babel/plugin-transform-object-rest-spread" "^7.22.11"
"@babel/plugin-transform-object-super" "^7.22.5"
- "@babel/plugin-transform-optional-catch-binding" "^7.22.5"
- "@babel/plugin-transform-optional-chaining" "^7.22.10"
+ "@babel/plugin-transform-optional-catch-binding" "^7.22.11"
+ "@babel/plugin-transform-optional-chaining" "^7.22.12"
"@babel/plugin-transform-parameters" "^7.22.5"
"@babel/plugin-transform-private-methods" "^7.22.5"
- "@babel/plugin-transform-private-property-in-object" "^7.22.5"
+ "@babel/plugin-transform-private-property-in-object" "^7.22.11"
"@babel/plugin-transform-property-literals" "^7.22.5"
"@babel/plugin-transform-regenerator" "^7.22.10"
"@babel/plugin-transform-reserved-words" "^7.22.5"
@@ -898,7 +898,7 @@
"@babel/plugin-transform-unicode-regex" "^7.22.5"
"@babel/plugin-transform-unicode-sets-regex" "^7.22.5"
"@babel/preset-modules" "0.1.6-no-external-plugins"
- "@babel/types" "^7.22.10"
+ "@babel/types" "^7.22.11"
babel-plugin-polyfill-corejs2 "^0.4.5"
babel-plugin-polyfill-corejs3 "^0.8.3"
babel-plugin-polyfill-regenerator "^0.5.2"
@@ -919,10 +919,10 @@
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
-"@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682"
- integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==
+"@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.10", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.11.tgz#7a9ba3bbe406ad6f9e8dd4da2ece453eb23a77a4"
+ integrity sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA==
dependencies:
regenerator-runtime "^0.14.0"
@@ -935,10 +935,10 @@
"@babel/parser" "^7.22.5"
"@babel/types" "^7.22.5"
-"@babel/traverse@^7.22.10":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.10.tgz#20252acb240e746d27c2e82b4484f199cf8141aa"
- integrity sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==
+"@babel/traverse@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.11.tgz#71ebb3af7a05ff97280b83f05f8865ac94b2027c"
+ integrity sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==
dependencies:
"@babel/code-frame" "^7.22.10"
"@babel/generator" "^7.22.10"
@@ -946,15 +946,15 @@
"@babel/helper-function-name" "^7.22.5"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
- "@babel/parser" "^7.22.10"
- "@babel/types" "^7.22.10"
+ "@babel/parser" "^7.22.11"
+ "@babel/types" "^7.22.11"
debug "^4.1.0"
globals "^11.1.0"
-"@babel/types@^7.22.10", "@babel/types@^7.22.5", "@babel/types@^7.4.4":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03"
- integrity sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==
+"@babel/types@^7.22.10", "@babel/types@^7.22.11", "@babel/types@^7.22.5", "@babel/types@^7.4.4":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.11.tgz#0e65a6a1d4d9cbaa892b2213f6159485fe632ea2"
+ integrity sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.5"
@@ -1155,9 +1155,9 @@
eslint-visitor-keys "^3.3.0"
"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1":
- version "4.6.2"
- resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8"
- integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==
+ version "4.8.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005"
+ integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
@@ -1204,15 +1204,42 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@eslint/js@^8.47.0":
- version "8.47.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.47.0.tgz#5478fdf443ff8158f9de171c704ae45308696c7d"
- integrity sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==
+"@eslint/js@8.48.0":
+ version "8.48.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.48.0.tgz#642633964e217905436033a2bd08bf322849b7fb"
+ integrity sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==
+
+"@floating-ui/core@^1.4.1":
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.4.1.tgz#0d633f4b76052668afb932492ac452f7ebe97f17"
+ integrity sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==
+ dependencies:
+ "@floating-ui/utils" "^0.1.1"
+
+"@floating-ui/dom@^1.5.1":
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.1.tgz#88b70defd002fe851f17b4a25efb2d3c04d7a8d7"
+ integrity sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==
+ dependencies:
+ "@floating-ui/core" "^1.4.1"
+ "@floating-ui/utils" "^0.1.1"
+
+"@floating-ui/react-dom@^2.0.1":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.2.tgz#fab244d64db08e6bed7be4b5fcce65315ef44d20"
+ integrity sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==
+ dependencies:
+ "@floating-ui/dom" "^1.5.1"
+
+"@floating-ui/utils@^0.1.1":
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.1.tgz#1a5b1959a528e374e8037c4396c3e825d6cf4a83"
+ integrity sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==
"@headlessui/react@^1.7.13", "@headlessui/react@^1.7.3":
- version "1.7.16"
- resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.16.tgz#9c458c9c4dbb708258c9e8da3fe5363f915f7b11"
- integrity sha512-2MphIAZdSUacZBT6EXk8AJkj+EuvaaJbtCyHTJrPsz8inhzCl7qeNPI1uk1AUvCgWylVtdN8cVVmnhUDPxPy3g==
+ version "1.7.17"
+ resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.17.tgz#a0ec23af21b527c030967245fd99776aa7352bc6"
+ integrity sha512-4am+tzvkqDSSgiwrsEpGWqgGo9dz8qU5M3znCkC4PgkpY4HcCZzEDEvozltGGGHIKl9jbXbZPSH5TWn4sWJdow==
dependencies:
client-only "^0.0.1"
@@ -1222,9 +1249,9 @@
integrity sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw==
"@humanwhocodes/config-array@^0.11.10", "@humanwhocodes/config-array@^0.11.8":
- version "0.11.10"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2"
- integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==
+ version "0.11.11"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"
+ integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
@@ -1320,43 +1347,44 @@
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
-"@mui/base@5.0.0-beta.10":
- version "5.0.0-beta.10"
- resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.10.tgz#b9a2de21c7de45aa4275c7ecf5aa803ecc236ba6"
- integrity sha512-moTAhGwFfQffj7hsu61FnqcGqVcd53A1CrOhnskM9TF0Uh2rnLDMCuar4JRUWWpaJofAfQEbQBBFPadFQLI4PA==
+"@mui/base@5.0.0-beta.13":
+ version "5.0.0-beta.13"
+ resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.13.tgz#3bae94c39752546d84a67d4ca73486b7c4923a89"
+ integrity sha512-uC0l97pBspfDAp+iz2cJq8YZ8Sd9i73V77+WzUiOAckIVEyCm5dyVDZCCO2/phmzckVEeZCGcytybkjMQuhPQw==
dependencies:
- "@babel/runtime" "^7.22.6"
+ "@babel/runtime" "^7.22.10"
"@emotion/is-prop-valid" "^1.2.1"
+ "@floating-ui/react-dom" "^2.0.1"
"@mui/types" "^7.2.4"
- "@mui/utils" "^5.14.4"
+ "@mui/utils" "^5.14.7"
"@popperjs/core" "^2.11.8"
clsx "^2.0.0"
prop-types "^15.8.1"
react-is "^18.2.0"
-"@mui/core-downloads-tracker@^5.14.4":
- version "5.14.4"
- resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.4.tgz#a517265647ee9660170107d68905db5e400576c5"
- integrity sha512-pW2XghSi3hpYKX57Wu0SCWMTSpzvXZmmucj3TcOJWaCiFt4xr05w2gcwBZi36dAp9uvd9//9N51qbblmnD+GPg==
+"@mui/core-downloads-tracker@^5.14.7":
+ version "5.14.7"
+ resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.7.tgz#95bed2487bf59632125a13b8eb8f4c21e460afec"
+ integrity sha512-sCWTUNElBPgB30iLvWe3PU7SIlTKZNf6/E/sko85iHVeHCM6WPkDw+y89CrZYjhFNmPqt2fIQM/pZu+rP2lFLA==
-"@mui/icons-material@^5.14.1":
- version "5.14.3"
- resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.3.tgz#26a84d52ab2fceea2856adf7a139527b3a51ae90"
- integrity sha512-XkxWPhageu1OPUm2LWjo5XqeQ0t2xfGe8EiLkRW9oz2LHMMZmijvCxulhgquUVTF1DnoSh+3KoDLSsoAFtVNVw==
+"@mui/icons-material@^5.14.1", "@mui/icons-material@^5.14.7":
+ version "5.14.7"
+ resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.7.tgz#d7f6bd188fe38adf35c89d9343b8a529c2306383"
+ integrity sha512-mWp4DwMa8c1Gx9yOEtPgxM4b+e6hAbtZyzfSubdBwrnEE6G5D2rbAJ5MB+If6kfI48JaYaJ5j8+zAdmZLuZc0A==
dependencies:
- "@babel/runtime" "^7.22.6"
+ "@babel/runtime" "^7.22.10"
"@mui/material@^5.14.1":
- version "5.14.4"
- resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.4.tgz#9d4d1834a929a4acc59e550e34ca64c0fd60b3a6"
- integrity sha512-2XUV3KyRC07BQPPzEgd+ss3x/ezXtHeKtOGCMCNmx3MauZojPYUpSwFkE0fYgYCD9dMQMVG4DY/VF38P0KShsg==
+ version "5.14.7"
+ resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.7.tgz#6c2c0de8a625562f789e1bb33cb4cfc8cf20bdb0"
+ integrity sha512-jIZj9F7zMv6IlyaYDVv5M2Kp20jIX8c0kzuwteySHS/A0IvPVyomQEPtWc51MCbpDNCqzwoZUp3rQtA2lI8k7A==
dependencies:
- "@babel/runtime" "^7.22.6"
- "@mui/base" "5.0.0-beta.10"
- "@mui/core-downloads-tracker" "^5.14.4"
- "@mui/system" "^5.14.4"
+ "@babel/runtime" "^7.22.10"
+ "@mui/base" "5.0.0-beta.13"
+ "@mui/core-downloads-tracker" "^5.14.7"
+ "@mui/system" "^5.14.7"
"@mui/types" "^7.2.4"
- "@mui/utils" "^5.14.4"
+ "@mui/utils" "^5.14.7"
"@types/react-transition-group" "^4.4.6"
clsx "^2.0.0"
csstype "^3.1.2"
@@ -1364,35 +1392,35 @@
react-is "^18.2.0"
react-transition-group "^4.4.5"
-"@mui/private-theming@^5.14.4":
- version "5.14.4"
- resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.14.4.tgz#0ec5510da05047f94984344360c7f457f3a0e19e"
- integrity sha512-ISXsHDiQ3z1XA4IuKn+iXDWvDjcz/UcQBiFZqtdoIsEBt8CB7wgdQf3LwcwqO81dl5ofg/vNQBEnXuKfZHrnYA==
+"@mui/private-theming@^5.14.7":
+ version "5.14.7"
+ resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.14.7.tgz#c9fec31e59bf66b12959e724b0e8ec3bb4a3d923"
+ integrity sha512-Y86+hmDnJab2Ka42PgxKpK3oL7EiacbeeX3X/lG9LGO0wSc45wZjHeTfIlVSkkUCkexiMKEJp5NlSjZhr27NRQ==
dependencies:
- "@babel/runtime" "^7.22.6"
- "@mui/utils" "^5.14.4"
+ "@babel/runtime" "^7.22.10"
+ "@mui/utils" "^5.14.7"
prop-types "^15.8.1"
-"@mui/styled-engine@^5.13.2":
- version "5.13.2"
- resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.13.2.tgz#c87bd61c0ab8086d34828b6defe97c02bcd642ef"
- integrity sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw==
+"@mui/styled-engine@^5.14.7":
+ version "5.14.7"
+ resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.14.7.tgz#aaacec6c87bcc9a180b2da062c613213af10f2e3"
+ integrity sha512-hKBETEDsIAkL8/mBwPiQj/vw28OeIhMXC3Tvj4J2bb9snxAKpiZioR1PwqP+6P41twsC/GKBd0Vr9oaWYaHuMg==
dependencies:
- "@babel/runtime" "^7.21.0"
+ "@babel/runtime" "^7.22.10"
"@emotion/cache" "^11.11.0"
csstype "^3.1.2"
prop-types "^15.8.1"
-"@mui/system@^5.14.4":
- version "5.14.4"
- resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.4.tgz#306a2fdd41ab6f4912ea689316f834db8461bb86"
- integrity sha512-oPgfWS97QNfHcDBapdkZIs4G5i85BJt69Hp6wbXF6s7vi3Evcmhdk8AbCRW6n0sX4vTj8oe0mh0RIm1G2A1KDA==
+"@mui/system@^5.14.7":
+ version "5.14.7"
+ resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.7.tgz#b08e23f9151d38186ab12dd618906abd4d73d203"
+ integrity sha512-jeZtHglc+Pi6qjGoopT6O4RqYXVBMqHVOsjMGP0hxGSSPm1T4gsAu7jU8eqGx9YwwjvvJ0eotTjFqw7iJ6qE2Q==
dependencies:
- "@babel/runtime" "^7.22.6"
- "@mui/private-theming" "^5.14.4"
- "@mui/styled-engine" "^5.13.2"
+ "@babel/runtime" "^7.22.10"
+ "@mui/private-theming" "^5.14.7"
+ "@mui/styled-engine" "^5.14.7"
"@mui/types" "^7.2.4"
- "@mui/utils" "^5.14.4"
+ "@mui/utils" "^5.14.7"
clsx "^2.0.0"
csstype "^3.1.2"
prop-types "^15.8.1"
@@ -1402,12 +1430,12 @@
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328"
integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==
-"@mui/utils@^5.14.4":
- version "5.14.4"
- resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.4.tgz#498cc2b08e46776c1e4327bfd8c23ad2f5890bc6"
- integrity sha512-4ANV0txPD3x0IcTCSEHKDWnsutg1K3m6Vz5IckkbLXVYu17oOZCVUdOKsb/txUmaCd0v0PmSRe5PW+Mlvns5dQ==
+"@mui/utils@^5.14.7":
+ version "5.14.7"
+ resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.7.tgz#3677bcabe032f1185e151f57d8c1a166df3ae0a1"
+ integrity sha512-RtheP/aBoPogVdi8vj8Vo2IFnRa4mZVmnD0RGlVZ49yF60rZs+xP4/KbpIrTr83xVs34QmHQ2aQ+IX7I0a0dDw==
dependencies:
- "@babel/runtime" "^7.22.6"
+ "@babel/runtime" "^7.22.10"
"@types/prop-types" "^15.7.5"
"@types/react-is" "^18.2.1"
prop-types "^15.8.1"
@@ -1418,11 +1446,6 @@
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.3.2.tgz#fb819366771f5721e9438ca3a42ad18684f0949b"
integrity sha512-upwtMaHxlv/udAWGq0kE+rg8huwmcxQPsKZFhS1R5iVO323mvxEBe1YrSXe1awLbg9sTIuEHbgxjLLt7JbeuAQ==
-"@next/env@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/env/-/env-13.4.16.tgz#382b565b35a2a69bd0e6b50f74c7b95f0c4b1097"
- integrity sha512-pCU0sJBqdfKP9mwDadxvZd+eLz3fZrTlmmDHY12Hdpl3DD0vy8ou5HWKVfG0zZS6tqhL4wnQqRbspdY5nqa7MA==
-
"@next/eslint-plugin-next@12.2.2":
version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.2.2.tgz#b4a22c06b6454068b54cc44502168d90fbb29a6d"
@@ -1459,21 +1482,11 @@
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.2.tgz#97c532d35c66ce6b6941ae24b5b8b267b9b0d0d8"
integrity sha512-PTUfe1ZrwjsiuTmr3bOM9lsoy5DCmfYsLOUF9ZVhtbi5MNJVmUTy4VZ06GfrvnCO5hGCr48z3vpFE9QZ0qLcPw==
-"@next/swc-darwin-arm64@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.16.tgz#ed6a342f95e5f21213fdadbceb65b40ae678cee0"
- integrity sha512-Rl6i1uUq0ciRa3VfEpw6GnWAJTSKo9oM2OrkGXPsm7rMxdd2FR5NkKc0C9xzFCI4+QtmBviWBdF2m3ur3Nqstw==
-
"@next/swc-darwin-x64@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.2.tgz#e0cb4ff4b11faaff3a891bd1d18ed72f71e30ebe"
integrity sha512-1HkjmS9awwlaeEY8Y01nRSNkSv3y+qnC/mjMPe/W66hEh3QKa/LQHqHeS7NOdEs19B2mhZ7w+EgMRXdLQ0Su8w==
-"@next/swc-darwin-x64@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.16.tgz#36c16066a1a3ef8211e84a6a5d72bef15826b291"
- integrity sha512-o1vIKYbZORyDmTrPV1hApt9NLyWrS5vr2p5hhLGpOnkBY1cz6DAXjv8Lgan8t6X87+83F0EUDlu7klN8ieZ06A==
-
"@next/swc-freebsd-x64@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.2.tgz#d7b93dd344cb67d1969565d0796c7b7d0217fccf"
@@ -1489,71 +1502,36 @@
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.2.tgz#26df7d7cdc18cf413f12a408179ee4ac315f383a"
integrity sha512-T9GCFyOIb4S3acA9LqflUYD+QZ94iZketHCqKdoO0Nx0OCHIgGJV5rotDe8TDXwh/goYpIfyHU4j1qqw4w4VnA==
-"@next/swc-linux-arm64-gnu@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.16.tgz#a5b5500737f07e3aa7f184014d8df7973420df26"
- integrity sha512-JRyAl8lCfyTng4zoOmE6hNI2f1MFUr7JyTYCHl1RxX42H4a5LMwJhDVQ7a9tmDZ/yj+0hpBn+Aan+d6lA3v0UQ==
-
"@next/swc-linux-arm64-musl@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.2.tgz#fd42232a6b10d9f9a4f71433d59c280a4532d06f"
integrity sha512-hxNVZS6L3c2z3l9EH2GP0MGQ9exu6O8cohYNZyqC9WUl6C03sEn8xzDH1y+NgD3fVurvYkGU5F0PDddJJLfDIw==
-"@next/swc-linux-arm64-musl@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.16.tgz#381b7662c5b10ed5750dce41dd57841aa0713e77"
- integrity sha512-9gqVqNzUMWbUDgDiND18xoUqhwSm2gmksqXgCU0qaOKt6oAjWz8cWYjgpPVD0WICKFylEY/gvPEP1fMZDVFZ/g==
-
"@next/swc-linux-x64-gnu@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.2.tgz#5307579e3d8fbdb03adbe6cfc915b51548e0a103"
integrity sha512-fCPkLuwDwY8/QeXxciJJjDHG09liZym/Bhb4A+RLFQ877wUkwFsNWDUTSdUx0YXlYK/1gf67BKauqKkOKp6CYw==
-"@next/swc-linux-x64-gnu@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.16.tgz#6e0b0eab1c316506950aeb4a09a5ea5c38edabe7"
- integrity sha512-KcQGwchAKmZVPa8i5PLTxvTs1/rcFnSltfpTm803Tr/BtBV3AxCkHLfhtoyVtVzx/kl/oue8oS+DSmbepQKwhw==
-
"@next/swc-linux-x64-musl@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.2.tgz#d5cb920a825a8dc80ffba8a6b797fb845af0b84c"
integrity sha512-o+GifBIQ2K+/MEFxHsxUZoU3bsuVFLXZYWd3idimFHiVdDCVYiKsY6mYMmKDlucX+9xRyOCkKL9Tjf+3tuXJpw==
-"@next/swc-linux-x64-musl@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.16.tgz#36b84e4509168a5cadf9dfd728c239002d4311fe"
- integrity sha512-2RbMZNxYnJmW8EPHVBsGZPq5zqWAyBOc/YFxq/jIQ/Yn3RMFZ1dZVCjtIcsiaKmgh7mjA/W0ApbumutHNxRqqQ==
-
"@next/swc-win32-arm64-msvc@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.2.tgz#2a0d619e5bc0cec17ed093afd1ca6b1c37c2690c"
integrity sha512-crii66irzGGMSUR0L8r9+A06eTv7FTXqw4rgzJ33M79EwQJOdpY7RVKXLQMurUhniEeQEEOfamiEdPIi/qxisw==
-"@next/swc-win32-arm64-msvc@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.16.tgz#52d36f909ccdefa2761617b6d4e9ae65f99880a9"
- integrity sha512-thDcGonELN7edUKzjzlHrdoKkm7y8IAdItQpRvvMxNUXa4d9r0ElofhTZj5emR7AiXft17hpen+QAkcWpqG7Jg==
-
"@next/swc-win32-ia32-msvc@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.2.tgz#769bef60d0d678c3d7606a4dc7fee018d6199227"
integrity sha512-5hRUSvn3MdQ4nVRu1rmKxq5YJzpTtZfaC/NyGw6wa4NSF1noUn/pdQGUr+I5Qz3CZkd1gZzzC0eaXQHlrk0E2g==
-"@next/swc-win32-ia32-msvc@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.16.tgz#a9cb0556d19c33fbb39ac9bef195fd490d6c7673"
- integrity sha512-f7SE1Mo4JAchUWl0LQsbtySR9xCa+x55C0taetjUApKtcLR3AgAjASrrP+oE1inmLmw573qRnE1eZN8YJfEBQw==
-
"@next/swc-win32-x64-msvc@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.2.tgz#45beb4b9d28e6dd6abf63cab1c5b92dc84323a6b"
integrity sha512-tpQJYUH+TzPMIsdVl9fH8uDg47iwiNjKY+8e9da3dXqlkztKzjSw0OwSADoqh3KrifplXeKSta+BBGLdBqg3sg==
-"@next/swc-win32-x64-msvc@13.4.16":
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.16.tgz#79a151d94583e03992c80df3d3e7f7686390ddac"
- integrity sha512-WamDZm1M/OEM4QLce3lOmD1XdLEl37zYZwlmOLhmF7qYJ2G6oYm9+ejZVv+LakQIsIuXhSpVlOvrxIAHqwRkPQ==
-
"@nivo/annotations@0.80.0":
version "0.80.0"
resolved "https://registry.yarnpkg.com/@nivo/annotations/-/annotations-0.80.0.tgz#127e4801fff7370dcfb9acfe1e335781dd65cfd5"
@@ -2011,9 +1989,9 @@
picomatch "^2.2.2"
"@rollup/pluginutils@^5.0.1":
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.3.tgz#183126d69aeb1cfa23401d5a71cb4b8c16c4a4e0"
- integrity sha512-hfllNN4a80rwNQ9QCxhxuHCGHMAvabXqxNdaChUSSadMre7t4iEUI6fFAhBOn/eIYTgYVhBv7vCLsAJ4u3lf3g==
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.4.tgz#74f808f9053d33bafec0cc98e7b835c9667d32ba"
+ integrity sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==
dependencies:
"@types/estree" "^1.0.0"
estree-walker "^2.0.2"
@@ -2046,26 +2024,26 @@
dependencies:
"@daybrush/utils" "^1.4.0"
-"@sentry-internal/tracing@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.63.0.tgz#58903b2205456034611cc5bc1b5b2479275f89c7"
- integrity sha512-Fxpc53p6NGvLSURg3iRvZA0k10K9yfeVhtczvJnpX30POBuV41wxpkLHkb68fjksirjEma1K3Ut1iLOEEDpPQg==
+"@sentry-internal/tracing@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.66.0.tgz#45ea607917d55a5bcaa3229341387ff6ed9b3a2b"
+ integrity sha512-3vCgC2hC3T45pn53yTDVcRpHoJTBxelDPPZVsipAbZnoOVPkj7n6dNfDhj3I3kwWCBPahPkXmE+R4xViR8VqJg==
dependencies:
- "@sentry/core" "7.63.0"
- "@sentry/types" "7.63.0"
- "@sentry/utils" "7.63.0"
+ "@sentry/core" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
tslib "^2.4.1 || ^1.9.3"
-"@sentry/browser@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.63.0.tgz#d7eee4be7bfff015f050bca83cafb111dc13d40d"
- integrity sha512-P1Iw/2281C/7CUCRsN4jgXvjMNKnrwKqxRg7JqN8eVeCDPMpOeEPHNJ6YatEXdVLTKVn0JB7L63Q1prhFr8+SQ==
+"@sentry/browser@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.66.0.tgz#9aa3078f8914d2f8acb4ad9fc7b2011c80e357f5"
+ integrity sha512-rW037rf8jkhyykG38+HUdwkRCKHJEMM5NkCqPIO5zuuxfLKukKdI2rbvgJ93s3/9UfsTuDFcKFL1u43mCn6sDw==
dependencies:
- "@sentry-internal/tracing" "7.63.0"
- "@sentry/core" "7.63.0"
- "@sentry/replay" "7.63.0"
- "@sentry/types" "7.63.0"
- "@sentry/utils" "7.63.0"
+ "@sentry-internal/tracing" "7.66.0"
+ "@sentry/core" "7.66.0"
+ "@sentry/replay" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
tslib "^2.4.1 || ^1.9.3"
"@sentry/cli@^1.74.6":
@@ -2080,88 +2058,88 @@
proxy-from-env "^1.1.0"
which "^2.0.2"
-"@sentry/core@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.63.0.tgz#8c38da6ef3a1de6e364463a09bc703b196ecbba4"
- integrity sha512-13Ljiq8hv6ieCkO+Am99/PljYJO5ynKT/hRQrWgGy9IIEgUr8sV3fW+1W6K4/3MCeOJou0HsiGBjOD1mASItVg==
+"@sentry/core@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.66.0.tgz#8968f2a9e641d33e3750a8e24d1d39953680c4f2"
+ integrity sha512-WMAEPN86NeCJ1IT48Lqiz4MS5gdDjBwP4M63XP4msZn9aujSf2Qb6My5uT87AJr9zBtgk8MyJsuHr35F0P3q1w==
dependencies:
- "@sentry/types" "7.63.0"
- "@sentry/utils" "7.63.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
tslib "^2.4.1 || ^1.9.3"
-"@sentry/integrations@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.63.0.tgz#bf4268b524670fdbc290dc489de0069143b499c6"
- integrity sha512-+P8GNqFZNH/yS/KPbvUfUDERneoRNUrqp9ayvvp8aq4cTtrBdM72CYgI21oG6cti42SSM1VDLYZomTV3ElPzSg==
+"@sentry/integrations@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.66.0.tgz#297d13fd2f567b0eba7faaa3727301db586b398a"
+ integrity sha512-2PNEnihG9e9Rjbz205+A4BYtFcS2XdgwsN6obAU6Yir7VIbskwZXxx87lKZuz6S53sOWPHleC7uvUBjL+Q6vYg==
dependencies:
- "@sentry/types" "7.63.0"
- "@sentry/utils" "7.63.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
localforage "^1.8.1"
tslib "^2.4.1 || ^1.9.3"
"@sentry/nextjs@^7.36.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.63.0.tgz#79bca799d451e1570c7873474e295660218cadea"
- integrity sha512-pf1kEt2oqxe84+DdmGkI6BEe1KMUcUFU4PZKg5GRFY7e2ZqHoS8hTJF5rBkScqVlQoXDTiGpfI+vU8Ie3snUcQ==
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.66.0.tgz#4ee5a8dc99ed930d2957ac7e287918ff3ba31e87"
+ integrity sha512-CJwl3/rIJRR1isqWjGEE8CYiNUndvRksp7l0/75tfe4JoKTk+XS3tXcXVZyyXh34GU5San1c46ctiyodaGGIeg==
dependencies:
"@rollup/plugin-commonjs" "24.0.0"
- "@sentry/core" "7.63.0"
- "@sentry/integrations" "7.63.0"
- "@sentry/node" "7.63.0"
- "@sentry/react" "7.63.0"
- "@sentry/types" "7.63.0"
- "@sentry/utils" "7.63.0"
+ "@sentry/core" "7.66.0"
+ "@sentry/integrations" "7.66.0"
+ "@sentry/node" "7.66.0"
+ "@sentry/react" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
"@sentry/webpack-plugin" "1.20.0"
chalk "3.0.0"
rollup "2.78.0"
stacktrace-parser "^0.1.10"
tslib "^2.4.1 || ^1.9.3"
-"@sentry/node@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.63.0.tgz#38508a440c04c0e98d00f5a1855e5448ee70c8d6"
- integrity sha512-tSMyfQNbfjX1w8vJDZtvWeaD4QQ/Z4zVW/TLXfL/JZFIIksPgDZmqLdF+NJS4bSGTU5JiHiUh4pYhME4mHgNBQ==
+"@sentry/node@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.66.0.tgz#d3e08471e1ecae28d3cd0ba3c18487ecb2449881"
+ integrity sha512-PxqIqLr4Sh5xcDfECiBQ4PuZ7v8yTgLhaRkruWrZPYxQrcJFPkwbFkw/IskzVnhT2VwXUmeWEIlRMQKBJ0t83A==
dependencies:
- "@sentry-internal/tracing" "7.63.0"
- "@sentry/core" "7.63.0"
- "@sentry/types" "7.63.0"
- "@sentry/utils" "7.63.0"
+ "@sentry-internal/tracing" "7.66.0"
+ "@sentry/core" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
cookie "^0.4.1"
https-proxy-agent "^5.0.0"
lru_map "^0.3.3"
tslib "^2.4.1 || ^1.9.3"
-"@sentry/react@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.63.0.tgz#6d318191e13ccf7ebba4897d7258b4ea3bcf6c51"
- integrity sha512-KFRjgADVE4aMI7gJmGnoSz65ZErQlz9xRB3vETWSyNOLprWXuQLPPtcDEn39BROtsDG4pLyYFaSDiD7o0+DyjQ==
+"@sentry/react@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.66.0.tgz#5f4d52a47b97e4daad0a2729ec6c88c0b29f0186"
+ integrity sha512-TC7kCkLoo+Klp9uywdV6tg8DDyn1CrTdndJghO6PoGz6sCa9k+t7K+z4E7MlgDoh3wiZwS2G2zhkT/xVeDRvJA==
dependencies:
- "@sentry/browser" "7.63.0"
- "@sentry/types" "7.63.0"
- "@sentry/utils" "7.63.0"
+ "@sentry/browser" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
hoist-non-react-statics "^3.3.2"
tslib "^2.4.1 || ^1.9.3"
-"@sentry/replay@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.63.0.tgz#989ae32ea028a5eca323786cc07294fedb1f0d45"
- integrity sha512-ikeFVojuP9oDF103blZcj0Vvb4S50dV54BESMrMW2lYBoMMjvOd7AdL+iDHjn1OL05/mv1C6Oc8MovmvdjILVA==
+"@sentry/replay@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.66.0.tgz#5469144192824e7688c475ed29586a8cce6606f6"
+ integrity sha512-5Y2SlVTOFTo3uIycv0mRneBakQtLgWkOnsJaC5LB0Ip0TqVKiMCbQ578vvXp+yvRj4LcS1gNd98xTTNojBoQNg==
dependencies:
- "@sentry/core" "7.63.0"
- "@sentry/types" "7.63.0"
- "@sentry/utils" "7.63.0"
+ "@sentry/core" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
-"@sentry/types@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.63.0.tgz#8032029fee6f70e04b667646626a674b03e2f79b"
- integrity sha512-pZNwJVW7RqNLGuTUAhoygt0c9zmc0js10eANAz0MstygJRhQI1tqPDuiELVdujPrbeL+IFKF+7NvRDAydR2Niw==
+"@sentry/types@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.66.0.tgz#4ec290cc6a3dd2024a61a0bffb468cedb409f7fb"
+ integrity sha512-uUMSoSiar6JhuD8p7ON/Ddp4JYvrVd2RpwXJRPH1A4H4Bd4DVt1mKJy1OLG6HdeQv39XyhB1lPZckKJg4tATPw==
-"@sentry/utils@7.63.0":
- version "7.63.0"
- resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.63.0.tgz#7c598553b4dbb6e3740dc96bc7f112ec32edbe69"
- integrity sha512-7FQv1RYAwnuTuarruP+1+Jd6YQuN7i/Y7KltwPMVEwU7j5mzYQaexLr/Jz1XIdR2KYVdkbXQyP8jj8BmA6u9Jw==
+"@sentry/utils@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.66.0.tgz#2e37c96610f26bc79ac064fca4222ea91fece68d"
+ integrity sha512-9GYUVgXjK66uXXcLXVMXVzlptqMtq1eJENCuDeezQiEFrNA71KkLDg00wESp+LL+bl3wpVTBApArpbF6UEG5hQ==
dependencies:
- "@sentry/types" "7.63.0"
+ "@sentry/types" "7.66.0"
tslib "^2.4.1 || ^1.9.3"
"@sentry/webpack-plugin@1.20.0":
@@ -2189,13 +2167,6 @@
dependencies:
tslib "^2.4.0"
-"@swc/helpers@0.5.1":
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.1.tgz#e9031491aa3f26bfcc974a67f48bd456c8a5357a"
- integrity sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==
- dependencies:
- tslib "^2.4.0"
-
"@tailwindcss/typography@^0.5.9":
version "0.5.9"
resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.9.tgz#027e4b0674929daaf7c921c900beee80dbad93e8"
@@ -2207,177 +2178,197 @@
postcss-selector-parser "6.0.10"
"@tiptap-pro/extension-unique-id@^2.1.0":
- version "2.1.0"
- resolved "https://registry.tiptap.dev/@tiptap-pro%2fextension-unique-id/-/extension-unique-id-2.1.0.tgz#7f5e7cc2d068eff11531e2b8c894ddf13c8d41d8"
- integrity sha512-RdkDqFV0adN/NXJ31I64mD3VmoGhQfNMmOyF5X92fbIymHaonAGzDeoXoindd+6MUUd6e3cm75x5VQLdsddG4Q==
+ version "2.2.1"
+ resolved "https://registry.tiptap.dev/@tiptap-pro%2fextension-unique-id/-/extension-unique-id-2.2.1.tgz#656803254760314d4e1b453dc5b75c86023048a6"
+ integrity sha512-B0GNLrWDVcfhbUOOi/lJfow6I4Y8xwJYXnSlhAENnGgOGERjinY1J5nZaR5dDMu1chcJYqAt3I7vkVLA/UMwmQ==
dependencies:
uuid "^8.3.2"
-"@tiptap/core@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.4.tgz#0a2047150ae537e75f96841a603699526f7b4ec5"
- integrity sha512-2YOMjRqoBGEP4YGgYpuPuBBJHMeqKOhLnS0WVwjVP84zOmMgZ7A8M6ILC9Xr7Q/qHZCvyBGWOSsI7+3HsEzzYQ==
+"@tiptap/core@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.7.tgz#9823a3712d176849cfd281dd8229ad0719c9eb9e"
+ integrity sha512-1pqTwlTnwTKQSNQmmTWhs2lwdvd+hFFNFZnrRAfvZhQZA6qPmPmKMNTcYmK38Tn4axKth6mhBamzTJgMZFI7ng==
-"@tiptap/extension-blockquote@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.4.tgz#1e87f8f157573deec65b54d8a8b5568d79066a86"
- integrity sha512-z5qfuLi04OgCBI6/odzB2vhulT/wpjymYOnON65vLXGZZbUw4cbPloykhqgWvQp+LzKH+HBhl4fz53d5CgnbOA==
+"@tiptap/extension-blockquote@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.7.tgz#fe25ec1dedd1f7e3eb1a851a6ac8738ca4691a17"
+ integrity sha512-oAsUU1c0DDZKHwK7/uCtYpnTUQt0o3w+SsJSv4S2vlSHidiFl9gCQGozUQ/Alzc7GO1Y95rOscL28DJXgXESQg==
-"@tiptap/extension-bold@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.4.tgz#debba8b0d957fe0b6943354834d8f1f0f8c0695c"
- integrity sha512-CWSQy1uWkVsen8HUsqhm+oEIxJrCiCENABUbhaVcJL/MqhnP4Trrh1B6O00Yfoc0XToPRRibDaHMFs4A3MSO0g==
+"@tiptap/extension-bold@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.7.tgz#c5d89284235d75c2e65745b50a5c0681be1cbab6"
+ integrity sha512-GZV2D91WENkWd1W29vM4kyGWObcxOKQrY8MuCvTdxni1kobEc/LPZzQ1XiQmiNTvXTMcBz5ckLpezdjASV1dNg==
-"@tiptap/extension-bubble-menu@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.4.tgz#f9dde09d3984e9879b1fe13d3e8c1859f0779ef5"
- integrity sha512-+cRZwj0YINNNDElSAiX1pvY2K98S2j9MQW2dXV5oLqsJhqGPZsKxVo8I1u7ZtqUla3QE1V18RYPAzVgTiMRkBg==
+"@tiptap/extension-bubble-menu@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.7.tgz#62616c9ee456c8413ad6c120757978266052a1a0"
+ integrity sha512-VcwwUgiG17TEDZda1JBbyKCHLIBTu8B2OAzYrnd4ZqeRs5KTVAB279o/TVjsLVgEfC+c7IWwhhaPPMoXn/lJ3g==
dependencies:
tippy.js "^6.3.7"
-"@tiptap/extension-bullet-list@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.4.tgz#d192767d39e45253c5e9d974e949f271e09c72d7"
- integrity sha512-JSZKBVTaKSuLl5fR4EKE4dOINOrgeRHYA25Vj6cWjgdvpTw5ef7vcUdn9yP4JwTmLRI+VnnMlYL3rqigU3iZNg==
+"@tiptap/extension-bullet-list@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.7.tgz#3a7356824a931122314a6bd73b5f9d8a8a313791"
+ integrity sha512-BReix1wkGNH12DSWGnWPKNu4do92Avh98aLkRS1o1V1Y49/+YGMYtfBXB9obq40o0WqKvk4MoM+rhKbfEc44Gg==
"@tiptap/extension-code-block-lowlight@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.0.4.tgz#e641f08d2ea77271722e848c6efa819b63638b1a"
- integrity sha512-fKM/4MY9R75IJJVt7P+aD+GX3yzzL6oHo1dn4hNFJlYp2x5+yH6kneaqKcTglVicBCGc8Ks6wJLEZTxxG35MOA==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.7.tgz#713dad4324c9ce25c66768fc4cfdb514ecea21c7"
+ integrity sha512-GOmpe3bwjlhMC79vFICInkJwaHx5dTiKQCTzdjZ5qRsvKgk/0YTrmWaN+w+JW5BBUaChj8IrgAPy7VZ20l7GKQ==
-"@tiptap/extension-code-block@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.4.tgz#d551ee7c13fef379bbbad298f1be757d1125cd54"
- integrity sha512-In2tV3rgm/MznVF0N7qYsYugPWSzhZHaCRCWcFKNvllMExpo91bUWvk+hXaIhhPxvuqGIVezjybwrYuU3bJW0g==
+"@tiptap/extension-code-block@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.7.tgz#c087c22c305f3c87645228ad32f32595dde7f2a2"
+ integrity sha512-uiasfWCIQuk34vGoIENqAJOHf9m3hAkcELnb9T6+uNxA3O7PUZQqBVN/27oEipj7j15pqua50D6C1jql9kFe0g==
-"@tiptap/extension-code@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.4.tgz#6952d402e7372dd2d129e962bf9bd54d68ee6183"
- integrity sha512-HuwJSJkipZf4hkns9witv1CABNIPiB9C8lgAQXK4xJKcoUQChcnljEL+PQ2NqeEeMTEeV3nG3A/0QafH0pgTgg==
+"@tiptap/extension-code@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.7.tgz#bad3b1aedc23123a2094f8810801edb0c13acbff"
+ integrity sha512-g0IA6Q6DFZE0AEOMXAV1mktl/XzIO3s1h/haPIKZ8GNes522qhBr9FYc5OUPQCCbgYjL7soTGzxA/W5Jk3f2AQ==
"@tiptap/extension-color@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.0.4.tgz#564265c2bcadd268e6b5745d2a06571744cb4090"
- integrity sha512-7Eb5Gk9v3sj2i1Q8dfqmpnc5aDPC/t0ZEsSLRi4C6SNo1nBeUxteXzpzxWwYjTvK+Um40STR89Z6PY14FIYXSA==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.7.tgz#7f436aed2f41087d8de6af6a4dd4cb7d964354dd"
+ integrity sha512-NLspH5taSpZP60rXJjDKu8AP9VDd+dlqz4guxvijtuPEePw87Fzidxx9w6X0uYQfx1O0xdPFq3UodlDz591scA==
-"@tiptap/extension-document@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.4.tgz#f94e6da23a7d93a8ea34c6767d4e2e31f5ab8849"
- integrity sha512-mCj2fAhnNhIHttPSqfTPSSTGwClGaPYvhT56Ij/Pi4iCrWjPXzC4XnIkIHSS34qS2tJN4XJzr/z7lm3NeLkF1w==
+"@tiptap/extension-document@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.7.tgz#5e1d56e899fdca8ebfad1b7cb358d5ace664b851"
+ integrity sha512-tZyoPPmvzti7PEnyulXomEtINd/Oi2S84uOt6gw7DTCnDq5bF5sn1IfN8Icqp9t4jDwyLXy2TL0Zg/sR0a2Ibg==
-"@tiptap/extension-dropcursor@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.4.tgz#f4a7542866c9100fee8e78eca5eebefff58989ca"
- integrity sha512-1OmKBv/E+nJo2vsosvu8KwFiBB+gZM1pY61qc7JbwEKHSYAxUFHfvLkIA0IQ53Z0DHMrFSKgWmHEcbnqtGevCA==
+"@tiptap/extension-dropcursor@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.7.tgz#a3f79b7453579f36f326852b16e421601e881a28"
+ integrity sha512-hNk2BuLnNSXlGOQphlzdpFKCKo7uHUFjWuBfzF1S9FMAQgcN7eTia+cCClmXABYfVLW4fT14PC1KiuGjxi9MuA==
-"@tiptap/extension-floating-menu@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.4.tgz#82f12c2415b7ddbfd782a03b100f717e9905bab0"
- integrity sha512-0YRE738k+kNKuSHhAb3jj9ZQ7Kda78RYRr+cX2jrQVueIMKebPIY07eBt6JcKmob9V9vcNn9qLtBfmygfcPUQg==
+"@tiptap/extension-floating-menu@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.7.tgz#fe2def740b3136d38101634ae60d2fec5468c57e"
+ integrity sha512-K0bO7JKHAvgLM5MkhNgoYcD6SB0Z2tNIFhZHs5SCTuhg7dwduMSM3pC6QBrJGUk99DGsKuMPYQn3c2oG7MLbyQ==
dependencies:
tippy.js "^6.3.7"
-"@tiptap/extension-gapcursor@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.4.tgz#c100a792fd41535ad6382aa8133d0d9c0b2cb2b8"
- integrity sha512-VxmKfBQjSSu1mNvHlydA4dJW/zawGKyqmnryiFNcUV9s+/HWLR5i9SiUl4wJM/B8sG8cQxClne5/LrCAeGNYuA==
+"@tiptap/extension-gapcursor@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.7.tgz#5c0303ba37b4c066f3a3c5835fd0b298f0d3e919"
+ integrity sha512-7eoInzzk1sssoD3RMkwFC86U15Ja4ANve+8wIC+xhN4R3Oe3PY3lFbp1GQxCmaJj8b3rtjNKIQZ2zO0PH58afA==
-"@tiptap/extension-hard-break@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.4.tgz#a4f70fa9a473270f7ec89f20a14b9122af5657bc"
- integrity sha512-4j8BZa6diuoRytWoIc7j25EYWWut5TZDLbb+OVURdkHnsF8B8zeNTo55W40CdwSaSyTtXtxbTIldV80ShQarGQ==
+"@tiptap/extension-hard-break@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.7.tgz#1cd783adfe2788d41614f8851b8d7a52ec027cce"
+ integrity sha512-6gFXXlCGAdXjy27BW29q4yfCQPAEFd18k7zRTnbd4aE/zIWUtLqdiTfI3kotUMab9Tt9/z1BRmCbEUxRsf1Nww==
-"@tiptap/extension-heading@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.4.tgz#5372e346c5d69cfa0060d7238d1a0bf440442f6f"
- integrity sha512-EfitUbew5ljH3xVlBXAxqqcJ4rjv15b8379LYOV6KQCf+Y1wY0gy9Q8wXSnrsAagqrvqipja4Ihn3OZeyIM+CA==
+"@tiptap/extension-heading@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.7.tgz#26d16227eab95b1f381e977f7aa1685f493c6fb5"
+ integrity sha512-jMeTqtq3kbMFtMvUb3SeIt4FFM3W+b6TAw5H4Qd6z3gYsAU3GahRK67MtbJfPmznUkZfimrqW9VCaBezScfrsQ==
"@tiptap/extension-highlight@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.0.4.tgz#5d54232ac573d0b04c3e705ca38f207fb6cf7270"
- integrity sha512-z1hcpf0eHHdaBE0pewXiNIu+QBodw4IAbZykTXMaY1xCsbYWfOJxeIb5o+CEG5HBsmaoJrCYenQw71xzgV0hKA==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.7.tgz#0f9434eedfdcb95a22ca5b6f601d13f4343a7e5c"
+ integrity sha512-3EXrnf1BQSdOe/iqzcTIr5Tf0NOhPQ+y1B9nMi/40v3MD8WzRBLaqj0lvpwO7xMAdgxm6IiL/XFYU41n9yFl/Q==
-"@tiptap/extension-history@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.4.tgz#761a9c4b2a875817acc73137660552bd49e94fca"
- integrity sha512-3GAUszn1xZx3vniHMiX9BSKmfvb5QOb0oSLXInN+hx80CgJDIHqIFuhx2dyV9I/HWpa0cTxaLWj64kfDzb1JVg==
+"@tiptap/extension-history@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.7.tgz#baa566875ef1278c5dd8821970362d85348b266c"
+ integrity sha512-8SIEKSImrIkqJThym1bPD13sC4/76UrG+piQ30xKQU4B7zUFCbutvrwYuQHSRvaEt8BPdTv2LWIK+wBkIgbWVA==
-"@tiptap/extension-horizontal-rule@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.4.tgz#6988dd63fb00ca144feb1baac84142782e8ebe38"
- integrity sha512-OMx2ImQseKbSUjPbbRCuYGOJshxYedh9giWAqwgWWokhYkH4nGxXn5m7+Laj+1wLre4bnWgHWVY4wMGniEj3aw==
+"@tiptap/extension-horizontal-rule@^2.0.4", "@tiptap/extension-horizontal-rule@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.7.tgz#7c21bc4917e4ced9382e81626e0f0068b224bfbb"
+ integrity sha512-hJupsDxDVmjmKI/Ewl/gtiyUx52Y3wRUhT8dCXNOA5eldmPXN23E2Fa2BC8XB47dyc5pubyNcLuqaLeaZ5hedw==
"@tiptap/extension-image@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.4.tgz#a41d5ca246bd41dd293194e359a80cb97f477ab3"
- integrity sha512-5iQ96pt9xppM8sWzwhGgc99PPoYPQuokTaCXAQKDI0Y1CFCjZ+/duUG3al1VUMpBXsjJw3/RVO1+7CEhRTd3mA==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.7.tgz#597129fb072f6b0014c980892c367a283077f564"
+ integrity sha512-aWa/NPMc1U9Z6xuV0gk1O1nk4H7BAwQMwqXWdvUQCJhmW5+LJPdEiKvt3P6j+ClIN7sdyokZCgr6eGr817qTLA==
-"@tiptap/extension-italic@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.4.tgz#4c6d0938542e4f7276f9dd18db395c040f76dcd8"
- integrity sha512-C/6+qs4Jh8xERRP0wcOopA1+emK8MOkBE4RQx5NbPnT2iCpERP0GlmHBFQIjaYPctZgKFHxsCfRnneS5Xe76+A==
+"@tiptap/extension-italic@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.7.tgz#d077683597d4282ae272c48b313d768d71985b67"
+ integrity sha512-7e37f+OFqisdY19nWIthbSNHMJy4+4dec06rUICPrkiuFaADj5HjUQr0dyWpL/LkZh92Wf/rWgp4V/lEwon3jA==
"@tiptap/extension-link@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.4.tgz#2899f9060ca722f11bd10ceb572ceb5178f111d6"
- integrity sha512-CliImI1hmC+J6wHxqgz9P4wMjoNSSgm3fnNHsx5z0Bn6JRA4Evh2E3KZAdMaE8xCTx89rKxMYNbamZf4VLSoqQ==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.7.tgz#2705c212d105ccf411d505e334ece4a723971ee4"
+ integrity sha512-NDfoMCkThng1B530pMg5y69+eWoghZXK2uCntrJH7Rs8jNeGMyt9wGIOd7N8ZYz0oJ2ZYKzZjS0RANdBDS17DA==
dependencies:
linkifyjs "^4.1.0"
-"@tiptap/extension-list-item@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.4.tgz#8ca7c9959a07bf94602f8957d784d526568f2069"
- integrity sha512-tSkbLgRo1QMNDJttWs9FeRywkuy5T2HdLKKfUcUNzT3s0q5AqIJl7VyimsBL4A6MUfN1qQMZCMHB4pM9Mkluww==
+"@tiptap/extension-list-item@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.7.tgz#dc24045e445d0f91baec9b113f711dc90c6682ac"
+ integrity sha512-hd/E4qQopBXWa6kdFY19qFVgqj4fzdPgAnzdXJ2XW7bC6O2CusmHphRRZ5FBsuspYTN/6/fv0i0jK9rSGlsEyA==
-"@tiptap/extension-ordered-list@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.4.tgz#e3e220e9c15114b07c952c32fa58e96601db6bd7"
- integrity sha512-Kfg+8k9p4iJCUKP/yIa18LfUpl9trURSMP/HX3/yQTz9Ul1vDrjxeFjSE5uWNvupcXRAM24js+aYrCmV7zpU+Q==
+"@tiptap/extension-ordered-list@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.7.tgz#72d9ddc432ecf0fd19c8acd3c6b44f5358d8e0d0"
+ integrity sha512-3XIXqbZmYkNzF+8PQ2jcCOCj0lpC3y9HGM/+joPIunhiUiktrIgpbUDv2E1Gq5lJHYqthIeujniI2dB85tkwJQ==
-"@tiptap/extension-paragraph@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.4.tgz#9cffa3f8a980349ca068b1b3c12596bf5f3aef0f"
- integrity sha512-nDxpopi9WigVqpfi8nU3B0fWYB14EMvKIkutNZo8wJvKGTZufNI8hw66wupIx/jZH1gFxEa5dHerw6aSYuWjgQ==
+"@tiptap/extension-paragraph@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.7.tgz#76408706f0037a510a384b86780bd50c6e8ffeea"
+ integrity sha512-cLqX27hNrXrwZCKrIW8OC3rW2+MT8hhS37+cdqOxZo5hUqQ9EF/puwS0w8uUZ7B3awX9Jm1QZDMjjERLkcmobw==
"@tiptap/extension-placeholder@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.4.tgz#74259783757c59751d78fcdd1aade7e928809187"
- integrity sha512-Y8hjUYBGTbytgrsplSZdHGciqbuVHQX+h0JcuvVaIlAy1kR7hmbxJLqL8tNa7qLtTqo2MfS2942OtSv85JOCzA==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.7.tgz#8477cf5116c89f0f75e8e2e3b8528e146a7f0f24"
+ integrity sha512-IiBoItYYNS7hb/zmPitw3w6Cylmp9qX+zW+QKe3lDkCNPeKxyQr86AnVLcQYOuXg62cLV9dp+4azZzHoz9SOcg==
-"@tiptap/extension-strike@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.4.tgz#13286dcf8780c55610ed65b24238b8395a5be824"
- integrity sha512-Men7LK6N/Dh3/G4/z2Z9WkDHM2Gxx1XyxYix2ZMf5CnqY37SeDNUnGDqit65pdIN3Y/TQnOZTkKSBilSAtXfJA==
+"@tiptap/extension-strike@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.7.tgz#b7b7f49254f1de22416b1415ca88a2a20edd0627"
+ integrity sha512-ONLXYnuZGM2EoGcxkyvJSDMBeAp7K6l83UXkK9TSj+VpEEDdeV7m8mJs8/vACJjJxD5HMN61+EPgU7VTEukQCA==
+
+"@tiptap/extension-table-cell@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.1.7.tgz#87841144b8368c9611ad46f2134b637e2c33c8bc"
+ integrity sha512-p3e4FNdbKVIjOLHDcXrRtlP6FYPoN6hBUFjq6QZbf5g4+ao2Uq4bQCL+eKbYMxUVERl8g/Qu9X+jG99fVsBDjA==
+
+"@tiptap/extension-table-header@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.1.7.tgz#4757834655e2c4edffa65bc6f6807eb59401e0d8"
+ integrity sha512-rolSUQxFJf/CEj2XBJpeMsLiLHASKrVIzZ2A/AZ9pT6WpFqmECi8r9xyutpJpx21n2Hrk46Y+uGFOKhyvbZ5ug==
+
+"@tiptap/extension-table-row@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.1.7.tgz#f736a61035b271423ef18f65a25f8d1e240263a1"
+ integrity sha512-DBCaEMEuCCoOmr4fdDfp2jnmyWPt672rmCZ5WUuenJ47Cy4Ox2dV+qk5vBZ/yDQcq12WvzLMhdSnAo9pMMMa6Q==
+
+"@tiptap/extension-table@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.1.7.tgz#c8a83744f60c76ae1e41438b04d5ac9e984afa66"
+ integrity sha512-nlKs35vTQOFW9lfw76S7kJvqVJAfHUlz1muQgWT0gNUlKJYINMXjUIg4Wcx8LTaITCCkp0lMGrLETGRNI+RyxA==
"@tiptap/extension-task-item@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.0.4.tgz#71f46d35ac629ca10c5c23d4ad170007338a436e"
- integrity sha512-0FfYWrOslDzzN7Ehnt3yBekOSH45tiB/3gzFRvGdLBUv0PiYQolUpyfHGsdNzeKYuWLF1yiacJkCeLgNDgCLDw==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.7.tgz#384a55308f3524f36388560486a2508a4b3c5413"
+ integrity sha512-4wFLZmhYqr87SEI/Qgk3FiH+qfp6IOmuYVhpL5zGLa6p+ytUdmPH3+zOaD1rthn5JiRU9KwYWFvTo2f+/O0NAg==
"@tiptap/extension-task-list@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.0.4.tgz#69b2b23d1e757044c05f3d7dcbd30194c71f9324"
- integrity sha512-3RGoEgGJdWpGf8aWl7O7+jnnvfpF0or2YHYYvJv13t5G4dNIS9E7QXT3/rU9QtHNYkbcJYFjHligIFuBTAhZNg==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.7.tgz#abaad3a7b964e58dac6b96b08000a50a06a071b4"
+ integrity sha512-eerV8pbGuYoFji6arWk+LBsIfURXPWNSLi1ZCuPfXP6N8sAV3fNT+VDm6RlGQwadQNae7rnibNClk67+55h9Zg==
"@tiptap/extension-text-style@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.0.4.tgz#4ba3fd6b204badc43ac6a00285315fe868f07e52"
- integrity sha512-HQk8c7HasDdeAJxlHrztkgprxocZecZVUMlvPvFAhkq8E/5+nfmr/Gm9qudiStEARZrIYBATNA2PbnQuIGMx3A==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.7.tgz#57f5dc5b223a855e782f24e09dc7fc53d9bd4b00"
+ integrity sha512-0QhEMDiDqMpyBGRt6o4GvbN9cUibZe4LT9e0ujarT6ElSe2fbtwGPnXSXApUtgHDDwHw95M5ZVxX/H5cjyjw1g==
-"@tiptap/extension-text@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.4.tgz#318b0105491a5976d220871dccabe6c4d2cbeedd"
- integrity sha512-i8/VFlVZh7TkAI49KKX5JmC0tM8RGwyg5zUpozxYbLdCOv07AkJt+E1fLJty9mqH4Y5HJMNnyNxsuZ9Ol/ySRA==
+"@tiptap/extension-text@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.7.tgz#071053ab0a8804a3bce36d1488a603b7446dff4e"
+ integrity sha512-3xaMMMNydLgoS+o+yOvaZF04ui9spJwJZl8VyYgcJKVGGLGRlWHrireXN5/OqXG2jLb/jWqXVx5idppQjX+PMA==
"@tiptap/extension-underline@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.0.4.tgz#c1e5df75a4c9f2d9e691d48438ee0894f8bb01f1"
- integrity sha512-Hvhy3iV5dWs0SFTww6sIzyQSSgVzcQuiozhDs11iP+gvFjK7ejg86KZ8wAVvyCi9K3bOMhohsw1Q2b8JSnIxcg==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.7.tgz#ab815645770f7d2013ac69327975837b4937c8df"
+ integrity sha512-mL95afyEJvg+C2yrTVn7QltfyE9ja1+94+OUkRBbB8PN3N6HvfSL4K/QSqecOLQ38bSQm/6ZGPkBLDkDGhGPdw==
"@tiptap/pm@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.0.4.tgz#c3df31a29120e1e3334f8f063df23ccb1ace7851"
- integrity sha512-DNgxntpEaiW7ciW0BTNTL0TFqAreZTrAROWakI4XaYRAyi5H9NfZW8jmwGwMBkoZ1KB3pfy+jT/Bisy4okEQGQ==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.7.tgz#91e1b87d4ddbddca3cfe46e3c052b0072e4e1d97"
+ integrity sha512-RBVb/k9OjmClwdVl7fpekFgUsLAm1U+5I4w1qA2tj7L/hSPOuPzaEHwCqDYe0b2PR5dd8h0nylS9qXuXVlfwfQ==
dependencies:
prosemirror-changeset "^2.2.0"
prosemirror-collab "^1.3.0"
@@ -2399,42 +2390,42 @@
prosemirror-view "^1.28.2"
"@tiptap/react@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.0.4.tgz#b879faeabd67859254d594eafe0f8232f5d78116"
- integrity sha512-NcrZL4Tu3+1Xfj/us5AOD7+kJhwYo2XViOB2iRRnfwS80PUtiLWDis6o3ngMGot/jBWzaMn4gofXnMWHtFdIAw==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.7.tgz#0c5a5407bcb398ff75234dd9c7a3f8878d943088"
+ integrity sha512-jCs5z/rXZ7mEOTPcJ+r/OSTtLOGBahS7D3xDu3pRX4P0wtWHlprsdptxxlWjkBHLav01XXJ+OtGZTfhWBio1QQ==
dependencies:
- "@tiptap/extension-bubble-menu" "^2.0.4"
- "@tiptap/extension-floating-menu" "^2.0.4"
+ "@tiptap/extension-bubble-menu" "^2.1.7"
+ "@tiptap/extension-floating-menu" "^2.1.7"
"@tiptap/starter-kit@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.0.4.tgz#20456eb4a4ae0ac8d5bf2ac5e9771b3c617c51a6"
- integrity sha512-9WtVXhujyp5cOlE7qlcQMFr0FEx3Cvo1isvfQGzhKKPzXa3rR7FT8bnOFsten31/Ia/uwvGXAvRDQy24YfHdNA==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.7.tgz#a33a7928b7051ac9cd89d1798745f9855b7b72d9"
+ integrity sha512-z2cmJRSC7ImaTGWrHv+xws9y1wIG0OCPosBYpmpwlEfA3JG3axWFmVRJlWnsQV4eSMi3QY3vaPgBAnrR4IxRhQ==
dependencies:
- "@tiptap/core" "^2.0.4"
- "@tiptap/extension-blockquote" "^2.0.4"
- "@tiptap/extension-bold" "^2.0.4"
- "@tiptap/extension-bullet-list" "^2.0.4"
- "@tiptap/extension-code" "^2.0.4"
- "@tiptap/extension-code-block" "^2.0.4"
- "@tiptap/extension-document" "^2.0.4"
- "@tiptap/extension-dropcursor" "^2.0.4"
- "@tiptap/extension-gapcursor" "^2.0.4"
- "@tiptap/extension-hard-break" "^2.0.4"
- "@tiptap/extension-heading" "^2.0.4"
- "@tiptap/extension-history" "^2.0.4"
- "@tiptap/extension-horizontal-rule" "^2.0.4"
- "@tiptap/extension-italic" "^2.0.4"
- "@tiptap/extension-list-item" "^2.0.4"
- "@tiptap/extension-ordered-list" "^2.0.4"
- "@tiptap/extension-paragraph" "^2.0.4"
- "@tiptap/extension-strike" "^2.0.4"
- "@tiptap/extension-text" "^2.0.4"
+ "@tiptap/core" "^2.1.7"
+ "@tiptap/extension-blockquote" "^2.1.7"
+ "@tiptap/extension-bold" "^2.1.7"
+ "@tiptap/extension-bullet-list" "^2.1.7"
+ "@tiptap/extension-code" "^2.1.7"
+ "@tiptap/extension-code-block" "^2.1.7"
+ "@tiptap/extension-document" "^2.1.7"
+ "@tiptap/extension-dropcursor" "^2.1.7"
+ "@tiptap/extension-gapcursor" "^2.1.7"
+ "@tiptap/extension-hard-break" "^2.1.7"
+ "@tiptap/extension-heading" "^2.1.7"
+ "@tiptap/extension-history" "^2.1.7"
+ "@tiptap/extension-horizontal-rule" "^2.1.7"
+ "@tiptap/extension-italic" "^2.1.7"
+ "@tiptap/extension-list-item" "^2.1.7"
+ "@tiptap/extension-ordered-list" "^2.1.7"
+ "@tiptap/extension-paragraph" "^2.1.7"
+ "@tiptap/extension-strike" "^2.1.7"
+ "@tiptap/extension-text" "^2.1.7"
"@tiptap/suggestion@^2.0.4":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.0.4.tgz#08e6c47a723200d02238d845cb09684c481f0066"
- integrity sha512-C5LGGjH8VFET34V7vKkqlwpSzrPl+7oAcj9h+P3jvJQ076iYpmpnMtz6dNLSFGKpHp5mtyl4RoJzh7lTvlfyiA==
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.7.tgz#ac88deef2ade8d836ca9084c276cc9d64c6e604a"
+ integrity sha512-FKlXFMWf9rCnNJQsUfeX6WpS2VUs2O98ENkyhfV8ehCB7X5+57mkkxJxl/88SMbjZL+FbWPBKLaiOvsXfIUoww==
"@types/debug@^4.0.0":
version "4.1.8"
@@ -2497,9 +2488,9 @@
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
"@types/linkify-it@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9"
- integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.3.tgz#15a0712296c5041733c79efe233ba17ae5a7587b"
+ integrity sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==
"@types/lodash.debounce@^4.0.7":
version "4.0.7"
@@ -2544,9 +2535,9 @@
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
"@types/node@*":
- version "20.5.0"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.0.tgz#7fc8636d5f1aaa3b21e6245e97d56b7f56702313"
- integrity sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==
+ version "20.5.8"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.8.tgz#fb171fd22d37ca6e2ea97fde88e6a13ee14bc327"
+ integrity sha512-eajsR9aeljqNhK028VG0Wuw+OaY5LLxYmxeoXynIoE6jannr9/Ucd1LL0hSSoafk5LTYG+FfqsyGt81Q6Zkybw==
"@types/node@18.0.6":
version "18.0.6"
@@ -2637,9 +2628,9 @@
"@types/react" "*"
"@types/react-redux@^7.1.20":
- version "7.1.25"
- resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.25.tgz#de841631205b24f9dfb4967dd4a7901e048f9a88"
- integrity sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==
+ version "7.1.26"
+ resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.26.tgz#84149f5614e40274bb70fcbe8f7cae6267d548b1"
+ integrity sha512-UKPo7Cm7rswYU6PH6CmTNCRv5NYF3HrgKuHEYTK8g/3czYLrUux50gQ2pkxc9c7ZpQZi+PNhgmI8oNIRoiVIxg==
dependencies:
"@types/hoist-non-react-statics" "^3.3.0"
"@types/react" "*"
@@ -2654,9 +2645,9 @@
"@types/react" "*"
"@types/react@*", "@types/react@^18.0.17":
- version "18.2.20"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2"
- integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==
+ version "18.2.21"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.21.tgz#774c37fd01b522d0b91aed04811b58e4e0514ed9"
+ integrity sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@@ -2700,9 +2691,9 @@
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
"@types/semver@^7.3.12":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a"
- integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==
+ version "7.5.1"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367"
+ integrity sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==
"@types/throttle-debounce@^2.1.0":
version "2.1.0"
@@ -2715,9 +2706,9 @@
integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==
"@types/unist@^2", "@types/unist@^2.0.0":
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.7.tgz#5b06ad6894b236a1d2bd6b2f07850ca5c59cf4d6"
- integrity sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==
+ version "2.0.8"
+ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.8.tgz#bb197b9639aa1a04cf464a617fe800cccd92ad5c"
+ integrity sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==
"@types/uuid@^8.3.4":
version "8.3.4"
@@ -2725,9 +2716,9 @@
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
"@types/uuid@^9.0.1":
- version "9.0.2"
- resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.2.tgz#ede1d1b1e451548d44919dc226253e32a6952c4b"
- integrity sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==
+ version "9.0.3"
+ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.3.tgz#6cdd939b4316b4f81625de9f06028d848c4a1533"
+ integrity sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==
"@typescript-eslint/eslint-plugin@^5.48.2", "@typescript-eslint/eslint-plugin@^5.51.0":
version "5.62.0"
@@ -2965,15 +2956,15 @@ array-uniq@^1.0.1:
integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==
array.prototype.findlastindex@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz#bc229aef98f6bd0533a2bc61ff95209875526c9b"
- integrity sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207"
+ integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==
dependencies:
call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
es-shim-unscopables "^1.0.0"
- get-intrinsic "^1.1.3"
+ get-intrinsic "^1.2.1"
array.prototype.flat@^1.3.1:
version "1.3.1"
@@ -3033,6 +3024,13 @@ async@^3.2.3:
resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
+asynciterator.prototype@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62"
+ integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==
+ dependencies:
+ has-symbols "^1.0.3"
+
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -3071,9 +3069,9 @@ axe-core@^4.6.2:
integrity sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==
axios@^1.1.3, axios@^1.3.4:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f"
- integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267"
+ integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
@@ -3218,13 +3216,6 @@ builtin-modules@^3.1.0:
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
-busboy@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
- integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
- dependencies:
- streamsearch "^1.1.0"
-
call-bind@^1.0.0, call-bind@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
@@ -3252,9 +3243,9 @@ camelcase-css@^2.0.1:
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001520:
- version "1.0.30001520"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz#62e2b7a1c7b35269594cf296a80bdf8cb9565006"
- integrity sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==
+ version "1.0.30001525"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001525.tgz#d2e8fdec6116ffa36284ca2c33ef6d53612fe1c8"
+ integrity sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q==
capital-case@^1.0.4:
version "1.0.4"
@@ -3350,7 +3341,7 @@ clean-webpack-plugin@^4.0.0:
dependencies:
del "^4.1.1"
-client-only@0.0.1, client-only@^0.0.1:
+client-only@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
@@ -3475,11 +3466,11 @@ cookie@^0.5.0:
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
core-js-compat@^3.31.0:
- version "3.32.0"
- resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.0.tgz#f41574b6893ab15ddb0ac1693681bd56c8550a90"
- integrity sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw==
+ version "3.32.1"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.1.tgz#55f9a7d297c0761a8eb1d31b593e0f5b6ffae964"
+ integrity sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==
dependencies:
- browserslist "^4.21.9"
+ browserslist "^4.21.10"
cosmiconfig@^7.0.0:
version "7.1.0"
@@ -3822,9 +3813,9 @@ ejs@^3.1.6:
jake "^10.8.5"
electron-to-chromium@^1.4.477:
- version "1.4.490"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz#d99286f6e915667fa18ea4554def1aa60eb4d5f1"
- integrity sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A==
+ version "1.4.508"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz#5641ff2f5ba11df4bd960fe6a2f9f70aa8b9af96"
+ integrity sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==
emoji-regex@^8.0.0:
version "8.0.0"
@@ -3876,7 +3867,7 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.2:
+es-abstract@^1.20.4, es-abstract@^1.22.1:
version "1.22.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc"
integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==
@@ -3921,6 +3912,26 @@ es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.2:
unbox-primitive "^1.0.2"
which-typed-array "^1.1.10"
+es-iterator-helpers@^1.0.12:
+ version "1.0.14"
+ resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz#19cd7903697d97e21198f3293b55e8985791c365"
+ integrity sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw==
+ dependencies:
+ asynciterator.prototype "^1.0.0"
+ call-bind "^1.0.2"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
+ es-set-tostringtag "^2.0.1"
+ function-bind "^1.1.1"
+ get-intrinsic "^1.2.1"
+ globalthis "^1.0.3"
+ has-property-descriptors "^1.0.0"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ internal-slot "^1.0.5"
+ iterator.prototype "^1.1.0"
+ safe-array-concat "^1.0.0"
+
es-set-tostringtag@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8"
@@ -4012,11 +4023,11 @@ eslint-config-prettier@^8.3.0:
integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==
eslint-config-turbo@latest:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/eslint-config-turbo/-/eslint-config-turbo-1.10.12.tgz#5868252d6833dd2b5cab4414751ed31ebe2177c3"
- integrity sha512-z3jfh+D7UGYlzMWGh+Kqz++hf8LOE96q3o5R8X4HTjmxaBWlLAWG+0Ounr38h+JLR2TJno0hU9zfzoPNkR9BdA==
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/eslint-config-turbo/-/eslint-config-turbo-1.10.13.tgz#3743def3c76e27c3969c16222137f5bd913a10e2"
+ integrity sha512-Ffa0SxkRCPMtfUX/HDanEqsWoLwZTQTAXO9W4IsOtycb2MzJDrVcLmoFW5sMwCrg7gjqbrC4ZJoD+1SPPzIVqg==
dependencies:
- eslint-plugin-turbo "1.10.12"
+ eslint-plugin-turbo "1.10.13"
eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.7:
version "0.3.9"
@@ -4059,9 +4070,9 @@ eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0:
debug "^3.2.7"
eslint-plugin-import@^2.26.0:
- version "2.28.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz#8d66d6925117b06c4018d491ae84469eb3cb1005"
- integrity sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==
+ version "2.28.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4"
+ integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==
dependencies:
array-includes "^3.1.6"
array.prototype.findlastindex "^1.2.2"
@@ -4072,13 +4083,12 @@ eslint-plugin-import@^2.26.0:
eslint-import-resolver-node "^0.3.7"
eslint-module-utils "^2.8.0"
has "^1.0.3"
- is-core-module "^2.12.1"
+ is-core-module "^2.13.0"
is-glob "^4.0.3"
minimatch "^3.1.2"
object.fromentries "^2.0.6"
object.groupby "^1.0.0"
object.values "^1.1.6"
- resolve "^1.22.3"
semver "^6.3.1"
tsconfig-paths "^3.14.2"
@@ -4130,14 +4140,15 @@ eslint-plugin-react@7.31.8:
string.prototype.matchall "^4.0.7"
eslint-plugin-react@^7.29.4, eslint-plugin-react@^7.31.7:
- version "7.33.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.1.tgz#bc27cccf860ae45413a4a4150bf0977345c1ceab"
- integrity sha512-L093k0WAMvr6VhNwReB8VgOq5s2LesZmrpPdKz/kZElQDzqS7G7+DnKoqT+w4JwuiGeAhAvHO0fvy0Eyk4ejDA==
+ version "7.33.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608"
+ integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==
dependencies:
array-includes "^3.1.6"
array.prototype.flatmap "^1.3.1"
array.prototype.tosorted "^1.1.1"
doctrine "^2.1.0"
+ es-iterator-helpers "^1.0.12"
estraverse "^5.3.0"
jsx-ast-utils "^2.4.1 || ^3.0.0"
minimatch "^3.1.2"
@@ -4150,10 +4161,10 @@ eslint-plugin-react@^7.29.4, eslint-plugin-react@^7.31.7:
semver "^6.3.1"
string.prototype.matchall "^4.0.8"
-eslint-plugin-turbo@1.10.12:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/eslint-plugin-turbo/-/eslint-plugin-turbo-1.10.12.tgz#3f95884faf35b56e0855d939585fa6cd457bb128"
- integrity sha512-uNbdj+ohZaYo4tFJ6dStRXu2FZigwulR1b3URPXe0Q8YaE7thuekKNP+54CHtZPH9Zey9dmDx5btAQl9mfzGOw==
+eslint-plugin-turbo@1.10.13:
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-turbo/-/eslint-plugin-turbo-1.10.13.tgz#d2c14c7e733ee1462c94d79dce29d75f42ced275"
+ integrity sha512-el4AAmn0zXmvHEyp1h0IQMfse10Vy8g5Vbg4IU3+vD9CSj5sDbX07iFVt8sCKg7og9Q5FAa9mXzlCf7t4vYgzg==
dependencies:
dotenv "16.0.3"
@@ -4294,14 +4305,14 @@ eslint@^7.23.0, eslint@^7.32.0:
v8-compile-cache "^2.0.3"
eslint@^8.31.0:
- version "8.47.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.47.0.tgz#c95f9b935463fb4fad7005e626c7621052e90806"
- integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==
+ version "8.48.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.48.0.tgz#bf9998ba520063907ba7bfe4c480dc8be03c2155"
+ integrity sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.6.1"
"@eslint/eslintrc" "^2.1.2"
- "@eslint/js" "^8.47.0"
+ "@eslint/js" "8.48.0"
"@humanwhocodes/config-array" "^0.11.10"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
@@ -4414,9 +4425,9 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-fifo@^1.1.0, fast-fifo@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.0.tgz#03e381bcbfb29932d7c3afde6e15e83e05ab4d8b"
- integrity sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c"
+ integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==
fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.1:
version "3.3.1"
@@ -4460,6 +4471,14 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
+file-loader@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d"
+ integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==
+ dependencies:
+ loader-utils "^2.0.0"
+ schema-utils "^3.0.0"
+
file-selector@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.6.0.tgz#fa0a8d9007b829504db4d07dd4de0310b65287dc"
@@ -4512,14 +4531,15 @@ find-up@^5.0.0:
path-exists "^4.0.0"
flat-cache@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
- integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.0.tgz#0e54ab4a1a60fe87e2946b6b00657f1c99e1af3f"
+ integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==
dependencies:
- flatted "^3.1.0"
+ flatted "^3.2.7"
+ keyv "^4.5.3"
rimraf "^3.0.2"
-flatted@^3.1.0:
+flatted@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
@@ -4551,9 +4571,9 @@ format@^0.2.0:
integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==
fraction.js@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
- integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
+ version "4.3.6"
+ resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d"
+ integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==
framework-utils@^1.1.0:
version "1.1.0"
@@ -4581,9 +4601,9 @@ fs.realpath@^1.0.0:
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fsevents@~2.3.2:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
- integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.1:
version "1.1.1"
@@ -4591,21 +4611,21 @@ function-bind@^1.1.1:
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
function.prototype.name@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
- integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd"
+ integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==
dependencies:
call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.0"
- functions-have-names "^1.2.2"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
+ functions-have-names "^1.2.3"
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==
-functions-have-names@^1.2.2, functions-have-names@^1.2.3:
+functions-have-names@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
@@ -4677,11 +4697,6 @@ glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
-glob-to-regexp@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
- integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
-
glob@7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
@@ -4778,7 +4793,7 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
-graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
+graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -4877,6 +4892,11 @@ https-proxy-agent@^5.0.0:
agent-base "6"
debug "4"
+husky@^8.0.3:
+ version "8.0.3"
+ resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184"
+ integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==
+
idb@^7.0.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b"
@@ -4938,7 +4958,7 @@ inline-style-parser@0.1.1:
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
-internal-slot@^1.0.3, internal-slot@^1.0.5:
+internal-slot@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986"
integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==
@@ -4986,6 +5006,13 @@ is-arrayish@^0.3.1:
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+is-async-function@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646"
+ integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
is-bigint@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
@@ -5018,14 +5045,14 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
-is-core-module@^2.11.0, is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.9.0:
+is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.9.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
dependencies:
has "^1.0.3"
-is-date-object@^1.0.1:
+is-date-object@^1.0.1, is-date-object@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
@@ -5044,11 +5071,25 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+is-finalizationregistry@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6"
+ integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==
+ dependencies:
+ call-bind "^1.0.2"
+
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+is-generator-function@^1.0.10:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
+ integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
@@ -5056,6 +5097,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"
+is-map@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127"
+ integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==
+
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
@@ -5139,6 +5185,11 @@ is-regexp@^1.0.0:
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==
+is-set@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec"
+ integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==
+
is-shared-array-buffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
@@ -5172,6 +5223,11 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.9:
dependencies:
which-typed-array "^1.1.11"
+is-weakmap@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2"
+ integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==
+
is-weakref@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
@@ -5179,6 +5235,14 @@ is-weakref@^1.0.2:
dependencies:
call-bind "^1.0.2"
+is-weakset@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d"
+ integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.1"
+
isarray@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
@@ -5194,6 +5258,16 @@ isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
+iterator.prototype@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.1.tgz#ab5b790e23ec00658f5974e032a2b05188bd3a5c"
+ integrity sha512-9E+nePc8C9cnQldmNl6bgpTY6zI4OPRZd97fhJ/iVZ1GifIUDVV5F6x1nEDqpe8KaMEZGT4xgrwKQDxXnjOIZQ==
+ dependencies:
+ define-properties "^1.2.0"
+ get-intrinsic "^1.2.1"
+ has-symbols "^1.0.3"
+ reflect.getprototypeof "^1.0.3"
+
jake@^10.8.5:
version "10.8.7"
resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f"
@@ -5223,9 +5297,9 @@ jest-worker@^27.4.5:
supports-color "^8.0.0"
jiti@^1.18.2:
- version "1.19.1"
- resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1"
- integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==
+ version "1.19.3"
+ resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.3.tgz#ef554f76465b3c2b222dc077834a71f0d4a37569"
+ integrity sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==
js-cookie@^3.0.1:
version "3.0.5"
@@ -5267,6 +5341,11 @@ jsesc@~0.5.0:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
json-parse-even-better-errors@^2.3.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
@@ -5299,7 +5378,7 @@ json5@^1.0.2:
dependencies:
minimist "^1.2.0"
-json5@^2.1.2, json5@^2.2.0, json5@^2.2.2:
+json5@^2.1.2, json5@^2.2.0, json5@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
@@ -5343,6 +5422,13 @@ keycon@^1.2.0:
"@scena/event-emitter" "^1.0.2"
keycode "^2.2.0"
+keyv@^4.5.3:
+ version "4.5.3"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25"
+ integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==
+ dependencies:
+ json-buffer "3.0.1"
+
kleur@^4.0.3:
version "4.1.5"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
@@ -5841,7 +5927,7 @@ mime-db@1.52.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
-mime-types@^2.1.12:
+mime-types@^2.1.12, mime-types@^2.1.27:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
@@ -5885,16 +5971,16 @@ mkdirp@^0.5.5:
minimist "^1.2.6"
mobx-react-lite@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-4.0.3.tgz#f7aa5ac3be558ca19a53b2929d9599679769c2a8"
- integrity sha512-wEE1oT5zvDdvplG4HnRrFgPwg5GFVVrEtl42Er85k23zeu3om8H8wbDPgdbQP88zAihVsik6xJfw6VnzUl8fQw==
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-4.0.4.tgz#eee3c55dfa6841365d5a7764971c456db12570fb"
+ integrity sha512-68uNYvQC/5Dazs3sIBv+bnpzRwcWde8y4ujHiLizhq8yeQtJ2tlNUGSh4r40gyE5M0utACIofBDsAj2hplcovQ==
dependencies:
use-sync-external-store "^1.2.0"
mobx@^6.10.0:
- version "6.10.0"
- resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.10.0.tgz#3537680fe98d45232cc19cc8f76280bd8bb6b0b7"
- integrity sha512-WMbVpCMFtolbB8swQ5E2YRrU+Yu8iLozCVx3CdGjbBKlP7dFiCSuiG06uea3JCFN5DnvtAX7+G5Bp82e2xu0ww==
+ version "6.10.2"
+ resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.10.2.tgz#96e123deef140750360ca9a5b02a8b91fbffd4d9"
+ integrity sha512-B1UGC3ieK3boCjnMEcZSwxqRDMdzX65H/8zOHbuTY8ZhvrIjTUoLRR2TP2bPqIgYRfb3+dUigu8yMZufNjn0LQ==
mri@^1.1.0:
version "1.2.0"
@@ -5940,6 +6026,14 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+next-images@^1.8.5:
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/next-images/-/next-images-1.8.5.tgz#2eb5535bb1d6c58a5c4e03bc3be6c72c8a053a45"
+ integrity sha512-YLBERp92v+Nu2EVxI9+wa32KRuxyxTC8ItbiHUWVPlatUoTl0yRqsNtP39c2vYv27VRvY4LlYcUGjNRBSMUIZA==
+ dependencies:
+ file-loader "^6.2.0"
+ url-loader "^4.1.0"
+
next-pwa@^5.6.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/next-pwa/-/next-pwa-5.6.0.tgz#f7b1960c4fdd7be4253eb9b41b612ac773392bf4"
@@ -5952,6 +6046,11 @@ next-pwa@^5.6.0:
workbox-webpack-plugin "^6.5.4"
workbox-window "^6.5.4"
+next-theme@^0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/next-theme/-/next-theme-0.1.5.tgz#aa6655c516892925e577349d7715a8ed54bad727"
+ integrity sha512-WR8UCLEFjWvRl+UO2lTM4pGo7R4jzGZqQ6YL3hiL1Ns587Qb91GhJZLPu/Aa4ExtGQ/5wlcDX8zDYZoCN9oDPw==
+
next-themes@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.2.1.tgz#0c9f128e847979daf6c67f70b38e6b6567856e45"
@@ -5983,30 +6082,6 @@ next@12.3.2:
"@next/swc-win32-ia32-msvc" "12.3.2"
"@next/swc-win32-x64-msvc" "12.3.2"
-next@^13.4.16:
- version "13.4.16"
- resolved "https://registry.yarnpkg.com/next/-/next-13.4.16.tgz#327ef6885b22161ed001cd5943c20b5e409a9406"
- integrity sha512-1xaA/5DrfpPu0eV31Iro7JfPeqO8uxQWb1zYNTe+KDKdzqkAGapLcDYHMLNKXKB7lHjZ7LfKUOf9dyuzcibrhA==
- dependencies:
- "@next/env" "13.4.16"
- "@swc/helpers" "0.5.1"
- busboy "1.6.0"
- caniuse-lite "^1.0.30001406"
- postcss "8.4.14"
- styled-jsx "5.1.1"
- watchpack "2.4.0"
- zod "3.21.4"
- optionalDependencies:
- "@next/swc-darwin-arm64" "13.4.16"
- "@next/swc-darwin-x64" "13.4.16"
- "@next/swc-linux-arm64-gnu" "13.4.16"
- "@next/swc-linux-arm64-musl" "13.4.16"
- "@next/swc-linux-x64-gnu" "13.4.16"
- "@next/swc-linux-x64-musl" "13.4.16"
- "@next/swc-win32-arm64-msvc" "13.4.16"
- "@next/swc-win32-ia32-msvc" "13.4.16"
- "@next/swc-win32-x64-msvc" "13.4.16"
-
no-case@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
@@ -6016,9 +6091,9 @@ no-case@^3.0.4:
tslib "^2.0.3"
node-abi@^3.3.0:
- version "3.45.0"
- resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.45.0.tgz#f568f163a3bfca5aacfce1fbeee1fa2cc98441f5"
- integrity sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==
+ version "3.47.0"
+ resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.47.0.tgz#6cbfa2916805ae25c2b7156ca640131632eb05e8"
+ integrity sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==
dependencies:
semver "^7.3.5"
@@ -6028,9 +6103,9 @@ node-addon-api@^6.1.0:
integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==
node-fetch@^2.6.7:
- version "2.6.12"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba"
- integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
+ integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
dependencies:
whatwg-url "^5.0.0"
@@ -6098,40 +6173,40 @@ object.assign@^4.1.4:
object-keys "^1.1.1"
object.entries@^1.1.5, object.entries@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23"
- integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
-
-object.fromentries@^2.0.5, object.fromentries@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73"
- integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
-
-object.groupby@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.0.tgz#cb29259cf90f37e7bac6437686c1ea8c916d12a9"
- integrity sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131"
+ integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==
dependencies:
call-bind "^1.0.2"
define-properties "^1.2.0"
- es-abstract "^1.21.2"
+ es-abstract "^1.22.1"
+
+object.fromentries@^2.0.5, object.fromentries@^2.0.6:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616"
+ integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
+
+object.groupby@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee"
+ integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
get-intrinsic "^1.2.1"
object.hasown@^1.1.1, object.hasown@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92"
- integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.3.tgz#6a5f2897bb4d3668b8e79364f98ccf971bda55ae"
+ integrity sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==
dependencies:
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
object.omit@^3.0.0:
version "3.0.0"
@@ -6148,13 +6223,13 @@ object.pick@^1.3.0:
isobject "^3.0.1"
object.values@^1.1.5, object.values@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d"
- integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a"
+ integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==
dependencies:
call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
@@ -6407,9 +6482,9 @@ postcss@8.4.14:
source-map-js "^1.0.2"
postcss@^8.4.14, postcss@^8.4.21, postcss@^8.4.23:
- version "8.4.27"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057"
- integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==
+ version "8.4.29"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd"
+ integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
@@ -6444,9 +6519,9 @@ prettier@^2.8.7:
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
prettier@latest:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.1.tgz#65271fc9320ce4913c57747a70ce635b30beaa40"
- integrity sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
+ integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
version "5.6.0"
@@ -6468,9 +6543,9 @@ prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2,
react-is "^16.13.1"
property-information@^6.0.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.2.0.tgz#b74f522c31c097b5149e3c3cb8d7f3defd986a1d"
- integrity sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.3.0.tgz#ba4a06ec6b4e1e90577df9931286953cdf4282c3"
+ integrity sha512-gVNZ74nqhRMiIUYWGQdosYetaKc83x8oT41a0LlV3AAFCAZwCpg4vmGkq8t34+cUhp3cnM4XDiU/7xlgK7HGrg==
prosemirror-changeset@^2.2.0:
version "2.2.1"
@@ -6549,23 +6624,16 @@ prosemirror-markdown@^1.10.1, prosemirror-markdown@^1.11.1:
prosemirror-model "^1.0.0"
prosemirror-menu@^1.2.1:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.2.tgz#c545a2de0b8cb79babc07682b1d93de0f273aa33"
- integrity sha512-437HIWTq4F9cTX+kPfqZWWm+luJm95Aut/mLUy+9OMrOml0bmWDS26ceC6SNfb2/S94et1sZ186vLO7pDHzxSw==
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz#3cfdc7c06d10f9fbd1bce29082c498bd11a0a79a"
+ integrity sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==
dependencies:
crelt "^1.0.0"
prosemirror-commands "^1.0.0"
prosemirror-history "^1.0.0"
prosemirror-state "^1.0.0"
-prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.8.1:
- version "1.18.1"
- resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.18.1.tgz#1d5d6b6de7b983ee67a479dc607165fdef3935bd"
- integrity sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw==
- dependencies:
- orderedmap "^2.0.0"
-
-prosemirror-model@^1.19.0:
+prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.19.0, prosemirror-model@^1.8.1:
version "1.19.3"
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.19.3.tgz#f0d55285487fefd962d0ac695f716f4ec6705006"
integrity sha512-tgSnwN7BS7/UM0sSARcW+IQryx2vODKX4MI7xpqY2X+iaepJdKBPc7I4aACIsDV/LTaTjt12Z56MhDr9LsyuZQ==
@@ -6618,9 +6686,9 @@ prosemirror-trailing-node@^2.0.2:
escape-string-regexp "^4.0.0"
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.7.0, prosemirror-transform@^1.7.3:
- version "1.7.4"
- resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.7.4.tgz#ea878c90563f3586064dd5ccf6cabb50b2753fd9"
- integrity sha512-GO38mvqJ2yeI0BbL5E1CdHcly032Dlfn9nHqlnCHqlNf9e9jZwJixxp6VRtOeDZ1uTDpDIziezMKbA41LpAx3A==
+ version "1.7.5"
+ resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.7.5.tgz#c62aac8645bd4f8cf447d6d53dda80abe8489f03"
+ integrity sha512-U/fWB6frEzY7dzwJUo+ir8dU1JEanaI/RwL12Imy9js/527N0v/IRUKewocP1kTq998JNT18IGtThaDLwLOBxQ==
dependencies:
prosemirror-model "^1.0.0"
@@ -6943,6 +7011,18 @@ redux@^4.0.0, redux@^4.0.4:
dependencies:
"@babel/runtime" "^7.9.2"
+reflect.getprototypeof@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3"
+ integrity sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
+ get-intrinsic "^1.2.1"
+ globalthis "^1.0.3"
+ which-builtin-type "^1.1.3"
+
regenerate-unicode-properties@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c"
@@ -6967,7 +7047,7 @@ regenerator-transform@^0.15.2:
dependencies:
"@babel/runtime" "^7.8.4"
-regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0:
+regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb"
integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==
@@ -7034,7 +7114,7 @@ resolve-pkg-maps@^1.0.0:
resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f"
integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==
-resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.0, resolve@^1.22.2, resolve@^1.22.3, resolve@^1.22.4:
+resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.0, resolve@^1.22.2, resolve@^1.22.4:
version "1.22.4"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34"
integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==
@@ -7154,7 +7234,7 @@ schema-utils@^2.6.5:
ajv "^6.12.4"
ajv-keywords "^3.5.2"
-schema-utils@^3.1.1:
+schema-utils@^3.0.0, schema-utils@^3.1.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
@@ -7215,9 +7295,9 @@ serialize-javascript@^6.0.1:
randombytes "^2.1.0"
sharp@^0.32.1:
- version "0.32.4"
- resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.4.tgz#0354653b7924f2520b2264ac9bcd10a58bf411b6"
- integrity sha512-exUnZewqVZC6UXqXuQ8fyJJv0M968feBi04jb9GcUHrWtkRoAKnbJt8IfwT4NJs7FskArbJ14JAFGVuooszoGg==
+ version "0.32.5"
+ resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.5.tgz#9ddc78ead6446094f51e50355a2d4ec6e7220cd4"
+ integrity sha512-0dap3iysgDkNaPOaOL4X/0akdu0ma62GcdC2NBQ+93eqpePdDdr2/LM0sFdDSMmN7yS+odyZtPsb7tx/cYBKnQ==
dependencies:
color "^4.2.3"
detect-libc "^2.0.2"
@@ -7354,11 +7434,6 @@ stacktrace-parser@^0.1.10:
dependencies:
type-fest "^0.7.1"
-streamsearch@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
- integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
-
streamx@^2.15.0:
version "2.15.1"
resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6"
@@ -7377,17 +7452,17 @@ string-width@^4.2.3:
strip-ansi "^6.0.1"
string.prototype.matchall@^4.0.6, string.prototype.matchall@^4.0.7, string.prototype.matchall@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3"
- integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==
+ version "4.0.9"
+ resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.9.tgz#148779de0f75d36b13b15885fec5cadde994520d"
+ integrity sha512-6i5hL3MqG/K2G43mWXWgP+qizFW/QH/7kCNN13JrJS5q48FN5IKksLDscexKP3dnmB6cdm9jlNgAsWNLpSykmA==
dependencies:
call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
- get-intrinsic "^1.1.3"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
+ get-intrinsic "^1.2.1"
has-symbols "^1.0.3"
- internal-slot "^1.0.3"
- regexp.prototype.flags "^1.4.3"
+ internal-slot "^1.0.5"
+ regexp.prototype.flags "^1.5.0"
side-channel "^1.0.4"
string.prototype.trim@^1.2.7:
@@ -7472,13 +7547,6 @@ styled-jsx@5.0.7:
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.7.tgz#be44afc53771b983769ac654d355ca8d019dff48"
integrity sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==
-styled-jsx@5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
- integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
- dependencies:
- client-only "0.0.1"
-
stylis@4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51"
@@ -7523,10 +7591,10 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-swr@^2.1.3:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/swr/-/swr-2.2.1.tgz#19b89a9034a62a73c30dbf06857a0a31981cd60a"
- integrity sha512-KJVA7dGtOBeZ+2sycEuzUfVIP5lZ/cd0xjevv85n2YG0x1uHJQicjAtahVZL6xG3+TjqhbBqimwYzVo3saeVXQ==
+swr@^2.1.3, swr@^2.2.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/swr/-/swr-2.2.2.tgz#abcb1f9c97e10527789884169d58b878472d4c98"
+ integrity sha512-CbR41AoMD4TQBQw9ic3GTXspgfM9Y8Mdhb5Ob4uIKXhWqnRLItwA5fpGvB7SmSw3+zEjb0PdhiEumtUvYoQ+bQ==
dependencies:
client-only "^0.0.1"
use-sync-external-store "^1.2.0"
@@ -7548,9 +7616,9 @@ tailwind-merge@^1.14.0:
integrity sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==
tailwindcss-animate@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/tailwindcss-animate/-/tailwindcss-animate-1.0.6.tgz#c7195037481552cc47962ea50113830360fd0c28"
- integrity sha512-4WigSGMvbl3gCCact62ZvOngA+PRqhAn7si3TQ3/ZuPuQZcIEtVap+ENSXbzWhpojKB8CpvnIsrwBu8/RnHtuw==
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz#318b692c4c42676cc9e67b19b78775742388bef4"
+ integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==
tailwindcss@^3.1.6, tailwindcss@^3.2.7:
version "3.3.3"
@@ -7651,9 +7719,9 @@ terser-webpack-plugin@^5.3.3:
terser "^5.16.8"
terser@^5.0.0, terser@^5.16.8:
- version "5.19.2"
- resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.2.tgz#bdb8017a9a4a8de4663a7983f45c506534f9234e"
- integrity sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==
+ version "5.19.3"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.3.tgz#359baeba615aef13db4b8c4d77a2aa0d8814aa9e"
+ integrity sha512-pQzJ9UJzM0IgmT4FAtYI6+VqFf0lj/to58AV0Xfgg0Up37RyPG7Al+1cepC6/BVuAxR9oNb41/DL4DEoHJvTdg==
dependencies:
"@jridgewell/source-map" "^0.3.3"
acorn "^8.8.2"
@@ -7771,9 +7839,9 @@ tslib@^1.8.1:
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, "tslib@^2.4.1 || ^1.9.3":
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410"
- integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
+ integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
tslib@~2.5.0:
version "2.5.3"
@@ -7794,47 +7862,47 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
-turbo-darwin-64@1.10.12:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.10.12.tgz#a3d9d6bd3436e795254865bc3d76a9c79aff8085"
- integrity sha512-vmDfGVPl5/aFenAbOj3eOx3ePNcWVUyZwYr7taRl0ZBbmv2TzjRiFotO4vrKCiTVnbqjQqAFQWY2ugbqCI1kOQ==
+turbo-darwin-64@1.10.13:
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.10.13.tgz#7abc33838bf74c7e7ba2955cb6acc40342d6964c"
+ integrity sha512-vmngGfa2dlYvX7UFVncsNDMuT4X2KPyPJ2Jj+xvf5nvQnZR/3IeDEGleGVuMi/hRzdinoxwXqgk9flEmAYp0Xw==
-turbo-darwin-arm64@1.10.12:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.10.12.tgz#ff1d9466935687ca68c0dee88a909c34cc654357"
- integrity sha512-3JliEESLNX2s7g54SOBqqkqJ7UhcOGkS0ywMr5SNuvF6kWVTbuUq7uBU/sVbGq8RwvK1ONlhPvJne5MUqBCTCQ==
+turbo-darwin-arm64@1.10.13:
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.10.13.tgz#89f2d14a28789e5eaf276a17fecd4116d61fd16d"
+ integrity sha512-eMoJC+k7gIS4i2qL6rKmrIQGP6Wr9nN4odzzgHFngLTMimok2cGLK3qbJs5O5F/XAtEeRAmuxeRnzQwTl/iuAw==
-turbo-linux-64@1.10.12:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.10.12.tgz#d184a491cc67c07672d339e36427378d0fc6b82e"
- integrity sha512-siYhgeX0DidIfHSgCR95b8xPee9enKSOjCzx7EjTLmPqPaCiVebRYvbOIYdQWRqiaKh9yfhUtFmtMOMScUf1gg==
+turbo-linux-64@1.10.13:
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.10.13.tgz#803e2b351984ec81034dc4b6935cdfb0a7d7d572"
+ integrity sha512-0CyYmnKTs6kcx7+JRH3nPEqCnzWduM0hj8GP/aodhaIkLNSAGAa+RiYZz6C7IXN+xUVh5rrWTnU2f1SkIy7Gdg==
-turbo-linux-arm64@1.10.12:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.10.12.tgz#44e6ca10b20fd4c59f8c85acf8366c7c09ebca81"
- integrity sha512-K/ZhvD9l4SslclaMkTiIrnfcACgos79YcAo4kwc8bnMQaKuUeRpM15sxLpZp3xDjDg8EY93vsKyjaOhdFG2UbA==
+turbo-linux-arm64@1.10.13:
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.10.13.tgz#92439a927ec98801be1be266016736be5730e40c"
+ integrity sha512-0iBKviSGQQlh2OjZgBsGjkPXoxvRIxrrLLbLObwJo3sOjIH0loGmVIimGS5E323soMfi/o+sidjk2wU1kFfD7Q==
-turbo-windows-64@1.10.12:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.10.12.tgz#36380eca8e7b0505d08b87a084efab1500b2a80e"
- integrity sha512-7FSgSwvktWDNOqV65l9AbZwcoueAILeE4L7JvjauNASAjjbuzXGCEq5uN8AQU3U5BOFj4TdXrVmO2dX+lLu8Zg==
+turbo-windows-64@1.10.13:
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.10.13.tgz#870815cdcb20f2480296c208778f9127be61eec6"
+ integrity sha512-S5XySRfW2AmnTeY1IT+Jdr6Goq7mxWganVFfrmqU+qqq3Om/nr0GkcUX+KTIo9mPrN0D3p5QViBRzulwB5iuUQ==
-turbo-windows-arm64@1.10.12:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.10.12.tgz#757ad59b9abf1949f22280bee6e8aad253743ba5"
- integrity sha512-gCNXF52dwom1HLY9ry/cneBPOKTBHhzpqhMylcyvJP0vp9zeMQQkt6yjYv+6QdnmELC92CtKNp2FsNZo+z0pyw==
+turbo-windows-arm64@1.10.13:
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.10.13.tgz#2da38b71b1716732541dfc5bd7475dc0903921f8"
+ integrity sha512-nKol6+CyiExJIuoIc3exUQPIBjP9nIq5SkMJgJuxsot2hkgGrafAg/izVDRDrRduQcXj2s8LdtxJHvvnbI8hEQ==
turbo@latest:
- version "1.10.12"
- resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.10.12.tgz#cd6f56b92da0600dae9fd94230483556a5c83187"
- integrity sha512-WM3+jTfQWnB9W208pmP4oeehZcC6JQNlydb/ZHMRrhmQa+htGhWLCzd6Q9rLe0MwZLPpSPFV2/bN5egCLyoKjQ==
+ version "1.10.13"
+ resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.10.13.tgz#8050bcd09f8a20d5a626f41e86cd8760e49a0df6"
+ integrity sha512-vOF5IPytgQPIsgGtT0n2uGZizR2N3kKuPIn4b5p5DdeLoI0BV7uNiydT7eSzdkPRpdXNnO8UwS658VaI4+YSzQ==
optionalDependencies:
- turbo-darwin-64 "1.10.12"
- turbo-darwin-arm64 "1.10.12"
- turbo-linux-64 "1.10.12"
- turbo-linux-arm64 "1.10.12"
- turbo-windows-64 "1.10.12"
- turbo-windows-arm64 "1.10.12"
+ turbo-darwin-64 "1.10.13"
+ turbo-darwin-arm64 "1.10.13"
+ turbo-linux-64 "1.10.13"
+ turbo-linux-arm64 "1.10.13"
+ turbo-windows-64 "1.10.13"
+ turbo-windows-arm64 "1.10.13"
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
@@ -8057,6 +8125,15 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
+url-loader@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2"
+ integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==
+ dependencies:
+ loader-utils "^2.0.0"
+ mime-types "^2.1.27"
+ schema-utils "^3.0.0"
+
use-callback-ref@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5"
@@ -8113,9 +8190,9 @@ uvu@^0.5.0:
sade "^1.7.3"
v8-compile-cache@^2.0.3:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
- integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128"
+ integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==
vfile-message@^3.0.0:
version "3.1.4"
@@ -8147,14 +8224,6 @@ warning@^4.0.2, warning@^4.0.3:
dependencies:
loose-envify "^1.0.0"
-watchpack@2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
- integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
- dependencies:
- glob-to-regexp "^0.4.1"
- graceful-fs "^4.1.2"
-
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
@@ -8206,7 +8275,35 @@ which-boxed-primitive@^1.0.2:
is-string "^1.0.5"
is-symbol "^1.0.3"
-which-typed-array@^1.1.10, which-typed-array@^1.1.11:
+which-builtin-type@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b"
+ integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==
+ dependencies:
+ function.prototype.name "^1.1.5"
+ has-tostringtag "^1.0.0"
+ is-async-function "^2.0.0"
+ is-date-object "^1.0.5"
+ is-finalizationregistry "^1.0.2"
+ is-generator-function "^1.0.10"
+ is-regex "^1.1.4"
+ is-weakref "^1.0.2"
+ isarray "^2.0.5"
+ which-boxed-primitive "^1.0.2"
+ which-collection "^1.0.1"
+ which-typed-array "^1.1.9"
+
+which-collection@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906"
+ integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==
+ dependencies:
+ is-map "^2.0.1"
+ is-set "^2.0.1"
+ is-weakmap "^2.0.1"
+ is-weakset "^2.0.1"
+
+which-typed-array@^1.1.10, which-typed-array@^1.1.11, which-typed-array@^1.1.9:
version "1.1.11"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a"
integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==
@@ -8414,16 +8511,11 @@ yaml@^1.10.0:
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yaml@^2.1.1:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
- integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144"
+ integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-
-zod@3.21.4:
- version "3.21.4"
- resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db"
- integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==