From ad558833afa66cbcffb5695dbf991b680f308a22 Mon Sep 17 00:00:00 2001 From: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com> Date: Fri, 3 Nov 2023 20:20:05 +0530 Subject: [PATCH] refactor: archive issue (#2628) * dev: archived issue store * dev: archived issue layouts and store binding * dev: archived issue detail store * dev: is read only * fix: archived issue delete * fix: build error --- .../headers/project-archived-issues.tsx | 93 +++- .../issues/delete-archived-issue-modal.tsx | 131 ++++++ web/components/issues/index.ts | 3 + .../applied-filters/roots/archived-issue.tsx | 81 ++++ .../filters/applied-filters/roots/index.ts | 1 + .../issues/issue-layouts/list/block.tsx | 5 +- .../issues/issue-layouts/list/blocks-list.tsx | 4 +- .../issues/issue-layouts/list/default.tsx | 13 + .../issues/issue-layouts/list/properties.tsx | 14 +- .../list/roots/archived-issue-root.tsx | 73 +++ .../issues/issue-layouts/list/roots/index.ts | 1 + .../quick-action-dropdowns/archived-issue.tsx | 76 +++ .../quick-action-dropdowns/index.ts | 1 + .../roots/archived-issue-layout-root.tsx | 31 ++ .../issues/issue-layouts/roots/index.ts | 1 + .../issues/issue-peek-overview/root.tsx | 82 +++- .../issues/issue-peek-overview/view.tsx | 98 ++-- .../[projectId]/archived-issues/index.tsx | 3 +- web/store/archived-issues/index.ts | 1 + web/store/archived-issues/issue.store.ts | 100 ++-- .../archived-issues/issue_detail.store.ts | 198 ++++++++ .../archived-issues/issue_filters.store.ts | 149 +++++- web/store/root.ts | 4 + yarn.lock | 439 +++++++++--------- 24 files changed, 1274 insertions(+), 328 deletions(-) create mode 100644 web/components/issues/delete-archived-issue-modal.tsx create mode 100644 web/components/issues/issue-layouts/filters/applied-filters/roots/archived-issue.tsx create mode 100644 web/components/issues/issue-layouts/list/roots/archived-issue-root.tsx create mode 100644 web/components/issues/issue-layouts/quick-action-dropdowns/archived-issue.tsx create mode 100644 web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx create mode 100644 web/store/archived-issues/issue_detail.store.ts diff --git a/web/components/headers/project-archived-issues.tsx b/web/components/headers/project-archived-issues.tsx index 82dffa2c3..e68f4ce84 100644 --- a/web/components/headers/project-archived-issues.tsx +++ b/web/components/headers/project-archived-issues.tsx @@ -3,22 +3,82 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; +// constants +import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; +// helper +import { truncateText } from "helpers/string.helper"; // ui -import { Breadcrumbs, LayersIcon } from "@plane/ui"; +import { Breadcrumbs, BreadcrumbItem, LayersIcon } from "@plane/ui"; +// icons +import { ArrowLeft } from "lucide-react"; +// components +import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "components/issues"; +// types +import type { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "types"; // helper import { renderEmoji } from "helpers/emoji.helper"; export const ProjectArchivedIssuesHeader: FC = observer(() => { const router = useRouter(); - const { workspaceSlug } = router.query; + const { workspaceSlug, projectId } = router.query; - const { project: projectStore } = useMobxStore(); + const { project: projectStore, archivedIssueFilters: archivedIssueFiltersStore } = useMobxStore(); const { currentProjectDetails } = projectStore; + // for archived issues list layout is the only option + const activeLayout = "list"; + + const handleFiltersUpdate = (key: keyof IIssueFilterOptions, value: string | string[]) => { + if (!workspaceSlug || !projectId) return; + + const newValues = archivedIssueFiltersStore.userFilters?.[key] ?? []; + + if (Array.isArray(value)) { + value.forEach((val) => { + if (!newValues.includes(val)) newValues.push(val); + }); + } else { + if (archivedIssueFiltersStore.userFilters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1); + else newValues.push(value); + } + + archivedIssueFiltersStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), { + filters: { + [key]: newValues, + }, + }); + }; + + const handleDisplayFiltersUpdate = (updatedDisplayFilter: Partial) => { + if (!workspaceSlug || !projectId) return; + + archivedIssueFiltersStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), { + display_filters: { + ...archivedIssueFiltersStore.userDisplayFilters, + ...updatedDisplayFilter, + }, + }); + }; + + const handleDisplayPropertiesUpdate = (property: Partial) => { + if (!workspaceSlug || !projectId) return; + + archivedIssueFiltersStore.updateDisplayProperties(workspaceSlug.toString(), projectId.toString(), property); + }; + return (
+
+ +
{
+ + {/* filter options */} +
+ + m.member)} + states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined} + /> + + + + +
); }); diff --git a/web/components/issues/delete-archived-issue-modal.tsx b/web/components/issues/delete-archived-issue-modal.tsx new file mode 100644 index 000000000..fd9c9b3fd --- /dev/null +++ b/web/components/issues/delete-archived-issue-modal.tsx @@ -0,0 +1,131 @@ +import { useEffect, useState, Fragment } from "react"; +import { useRouter } from "next/router"; +import { observer } from "mobx-react-lite"; +import { Dialog, Transition } from "@headlessui/react"; +import { AlertTriangle } from "lucide-react"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +// hooks +import useToast from "hooks/use-toast"; +// ui +import { Button } from "@plane/ui"; +// types +import type { IIssue } from "types"; + +type Props = { + isOpen: boolean; + handleClose: () => void; + data: IIssue; + onSubmit?: () => Promise; +}; + +export const DeleteArchivedIssueModal: React.FC = observer((props) => { + const { data, isOpen, handleClose, onSubmit } = props; + + const router = useRouter(); + const { workspaceSlug } = router.query; + + const { setToastAlert } = useToast(); + + const { archivedIssueDetail: archivedIssueDetailStore } = useMobxStore(); + + const [isDeleteLoading, setIsDeleteLoading] = useState(false); + + useEffect(() => { + setIsDeleteLoading(false); + }, [isOpen]); + + const onClose = () => { + setIsDeleteLoading(false); + handleClose(); + }; + + const handleIssueDelete = async () => { + if (!workspaceSlug) return; + + setIsDeleteLoading(true); + + await archivedIssueDetailStore + .deleteArchivedIssue(workspaceSlug.toString(), data.project, data.id) + .then(() => { + if (onSubmit) onSubmit(); + }) + .catch((err) => { + const error = err?.detail; + const errorString = Array.isArray(error) ? error[0] : error; + + setToastAlert({ + title: "Error", + type: "error", + message: errorString || "Something went wrong.", + }); + }) + .finally(() => { + setIsDeleteLoading(false); + onClose(); + }); + }; + + return ( + + + +
+ + +
+
+ + +
+
+ + + +

Delete Archived Issue

+
+
+ +

+ Are you sure you want to delete issue{" "} + + {data?.project_detail.identifier}-{data?.sequence_id} + + {""}? All of the data related to the archived issue will be permanently removed. This action + cannot be undone. +

+
+
+ + +
+
+
+
+
+
+
+
+ ); +}); diff --git a/web/components/issues/index.ts b/web/components/issues/index.ts index f48bb3894..3768d66cd 100644 --- a/web/components/issues/index.ts +++ b/web/components/issues/index.ts @@ -20,3 +20,6 @@ export * from "./confirm-issue-discard"; export * from "./draft-issue-form"; export * from "./draft-issue-modal"; export * from "./delete-draft-issue-modal"; + +// archived issue +export * from "./delete-archived-issue-modal"; diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/archived-issue.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/archived-issue.tsx new file mode 100644 index 000000000..20e20d34e --- /dev/null +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/archived-issue.tsx @@ -0,0 +1,81 @@ +import { useRouter } from "next/router"; +import { observer } from "mobx-react-lite"; + +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +// components +import { AppliedFiltersList } from "components/issues"; +// types +import { IIssueFilterOptions } from "types"; + +export const ArchivedIssueAppliedFiltersRoot: React.FC = observer(() => { + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { archivedIssueFilters: archivedIssueFiltersStore, project: projectStore } = useMobxStore(); + + const userFilters = archivedIssueFiltersStore.userFilters; + + // filters whose value not null or empty array + const appliedFilters: IIssueFilterOptions = {}; + Object.entries(userFilters).forEach(([key, value]) => { + if (!value) return; + + if (Array.isArray(value) && value.length === 0) return; + + appliedFilters[key as keyof IIssueFilterOptions] = value; + }); + + const handleRemoveFilter = (key: keyof IIssueFilterOptions, value: string | null) => { + if (!workspaceSlug || !projectId) return; + + // remove all values of the key if value is null + if (!value) { + archivedIssueFiltersStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), { + filters: { + [key]: null, + }, + }); + return; + } + + // remove the passed value from the key + let newValues = archivedIssueFiltersStore.userFilters?.[key] ?? []; + newValues = newValues.filter((val) => val !== value); + + archivedIssueFiltersStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), { + filters: { + [key]: newValues, + }, + }); + }; + + const handleClearAllFilters = () => { + if (!workspaceSlug || !projectId) return; + + const newFilters: IIssueFilterOptions = {}; + Object.keys(userFilters).forEach((key) => { + newFilters[key as keyof IIssueFilterOptions] = null; + }); + + archivedIssueFiltersStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), { + filters: { ...newFilters }, + }); + }; + + // return if no filters are applied + if (Object.keys(appliedFilters).length === 0) return null; + + return ( +
+ m.member)} + states={projectStore.states?.[projectId?.toString() ?? ""]} + /> +
+ ); +}); diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/index.ts b/web/components/issues/issue-layouts/filters/applied-filters/roots/index.ts index c7280e470..e5030d7c4 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/index.ts +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/index.ts @@ -3,3 +3,4 @@ export * from "./global-view-root"; export * from "./module-root"; export * from "./project-view-root"; export * from "./project-root"; +export * from "./archived-issue"; diff --git a/web/components/issues/issue-layouts/list/block.tsx b/web/components/issues/issue-layouts/list/block.tsx index 41dbe1acb..52410756a 100644 --- a/web/components/issues/issue-layouts/list/block.tsx +++ b/web/components/issues/issue-layouts/list/block.tsx @@ -12,11 +12,12 @@ interface IssueBlockProps { handleIssues: (group_by: string | null, issue: IIssue, action: "update" | "delete") => void; quickActions: (group_by: string | null, issue: IIssue) => React.ReactNode; display_properties: any; + isReadonly?: boolean; showEmptyGroup?: boolean; } export const IssueBlock: React.FC = (props) => { - const { columnId, issue, handleIssues, quickActions, display_properties, showEmptyGroup } = props; + const { columnId, issue, handleIssues, quickActions, display_properties, showEmptyGroup, isReadonly } = props; const updateIssue = (group_by: string | null, issueToUpdate: IIssue) => { handleIssues(group_by, issueToUpdate, "update"); @@ -37,6 +38,7 @@ export const IssueBlock: React.FC = (props) => { workspaceSlug={issue?.workspace_detail?.slug} projectId={issue?.project_detail?.id} issueId={issue?.id} + isArchived={issue?.archived_at !== null} handleIssue={(issueToUpdate) => { handleIssues(!columnId && columnId === "null" ? null : columnId, issueToUpdate as IIssue, "update"); }} @@ -50,6 +52,7 @@ export const IssueBlock: React.FC = (props) => { void; quickActions: (group_by: string | null, issue: IIssue) => React.ReactNode; display_properties: any; @@ -14,7 +15,7 @@ interface Props { } export const IssueBlocksList: FC = (props) => { - const { columnId, issues, handleIssues, quickActions, display_properties, showEmptyGroup } = props; + const { columnId, issues, handleIssues, quickActions, display_properties, showEmptyGroup, isReadonly } = props; return (
@@ -26,6 +27,7 @@ export const IssueBlocksList: FC = (props) => { issue={issue} handleIssues={handleIssues} quickActions={quickActions} + isReadonly={isReadonly} display_properties={display_properties} showEmptyGroup={showEmptyGroup} /> diff --git a/web/components/issues/issue-layouts/list/default.tsx b/web/components/issues/issue-layouts/list/default.tsx index 54d847f71..57cdeb34b 100644 --- a/web/components/issues/issue-layouts/list/default.tsx +++ b/web/components/issues/issue-layouts/list/default.tsx @@ -12,6 +12,7 @@ export interface IGroupByList { issues: any; group_by: string | null; list: any; + isReadonly?: boolean; listKey: string; handleIssues: (group_by: string | null, issue: IIssue, action: "update" | "delete") => void; quickActions: (group_by: string | null, issue: IIssue) => React.ReactNode; @@ -26,6 +27,7 @@ const GroupByList: React.FC = observer((props) => { issues, group_by, list, + isReadonly, listKey, handleIssues, quickActions, @@ -58,6 +60,7 @@ const GroupByList: React.FC = observer((props) => { handleIssues={handleIssues} quickActions={quickActions} display_properties={display_properties} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} @@ -79,6 +82,7 @@ const GroupByList: React.FC = observer((props) => { export interface IList { issues: any; group_by: string | null; + isReadonly?: boolean; handleDragDrop?: (result: any) => void | undefined; handleIssues: (group_by: string | null, issue: IIssue, action: "update" | "delete") => void; quickActions: (group_by: string | null, issue: IIssue) => React.ReactNode; @@ -98,6 +102,7 @@ export const List: React.FC = observer((props) => { const { issues, group_by, + isReadonly, handleIssues, quickActions, display_properties, @@ -124,6 +129,7 @@ export const List: React.FC = observer((props) => { display_properties={display_properties} is_list enableQuickIssueCreate={enableQuickIssueCreate} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} @@ -138,6 +144,7 @@ export const List: React.FC = observer((props) => { quickActions={quickActions} display_properties={display_properties} enableQuickIssueCreate={enableQuickIssueCreate} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} @@ -152,6 +159,7 @@ export const List: React.FC = observer((props) => { quickActions={quickActions} display_properties={display_properties} enableQuickIssueCreate={enableQuickIssueCreate} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} @@ -166,6 +174,7 @@ export const List: React.FC = observer((props) => { quickActions={quickActions} display_properties={display_properties} enableQuickIssueCreate={enableQuickIssueCreate} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} @@ -180,6 +189,7 @@ export const List: React.FC = observer((props) => { quickActions={quickActions} display_properties={display_properties} enableQuickIssueCreate={enableQuickIssueCreate} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} @@ -194,6 +204,7 @@ export const List: React.FC = observer((props) => { quickActions={quickActions} display_properties={display_properties} enableQuickIssueCreate={enableQuickIssueCreate} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} @@ -208,6 +219,7 @@ export const List: React.FC = observer((props) => { quickActions={quickActions} display_properties={display_properties} enableQuickIssueCreate={enableQuickIssueCreate} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} @@ -222,6 +234,7 @@ export const List: React.FC = observer((props) => { quickActions={quickActions} display_properties={display_properties} enableQuickIssueCreate={enableQuickIssueCreate} + isReadonly={isReadonly} showEmptyGroup={showEmptyGroup} /> )} diff --git a/web/components/issues/issue-layouts/list/properties.tsx b/web/components/issues/issue-layouts/list/properties.tsx index a354ab672..c304867ac 100644 --- a/web/components/issues/issue-layouts/list/properties.tsx +++ b/web/components/issues/issue-layouts/list/properties.tsx @@ -63,7 +63,7 @@ export const KanBanProperties: FC = observer((props) => { value={issue?.state_detail || null} hideDropdownArrow onChange={handleState} - disabled={false} + disabled={isReadonly} /> )} @@ -72,7 +72,7 @@ export const KanBanProperties: FC = observer((props) => { )} @@ -83,7 +83,7 @@ export const KanBanProperties: FC = observer((props) => { projectId={issue?.project_detail?.id || null} value={issue?.labels || null} onChange={handleLabel} - disabled={false} + disabled={isReadonly} hideDropdownArrow /> )} @@ -95,7 +95,7 @@ export const KanBanProperties: FC = observer((props) => { value={issue?.assignees || null} hideDropdownArrow onChange={handleAssignee} - disabled={false} + disabled={isReadonly} multiple /> )} @@ -105,7 +105,7 @@ export const KanBanProperties: FC = observer((props) => { handleStartDate(date)} - disabled={false} + disabled={isReadonly} placeHolder="Start date" /> )} @@ -115,7 +115,7 @@ export const KanBanProperties: FC = observer((props) => { handleTargetDate(date)} - disabled={false} + disabled={isReadonly} placeHolder="Target date" /> )} @@ -127,7 +127,7 @@ export const KanBanProperties: FC = observer((props) => { value={issue?.estimate_point || null} hideDropdownArrow onChange={handleEstimate} - disabled={false} + disabled={isReadonly} /> )} diff --git a/web/components/issues/issue-layouts/list/roots/archived-issue-root.tsx b/web/components/issues/issue-layouts/list/roots/archived-issue-root.tsx new file mode 100644 index 000000000..63c2f1281 --- /dev/null +++ b/web/components/issues/issue-layouts/list/roots/archived-issue-root.tsx @@ -0,0 +1,73 @@ +import { FC } from "react"; +import { useRouter } from "next/router"; +import { observer } from "mobx-react-lite"; +// hooks +import { useMobxStore } from "lib/mobx/store-provider"; +// components +import { List } from "../default"; +import { ArchivedIssueQuickActions } from "components/issues"; +// helpers +import { orderArrayBy } from "helpers/array.helper"; +// types +import { IIssue } from "types"; +// constants +import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue"; + +export const ArchivedIssueListLayout: FC = observer(() => { + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { + project: projectStore, + archivedIssues: archivedIssueStore, + archivedIssueFilters: archivedIssueFiltersStore, + } = useMobxStore(); + + // derived values + const issues = archivedIssueStore.getIssues; + const display_properties = archivedIssueFiltersStore?.userDisplayProperties || null; + const group_by: string | null = archivedIssueFiltersStore?.userDisplayFilters?.group_by || null; + + const handleIssues = (group_by: string | null, issue: IIssue, action: "delete" | "update") => { + if (!workspaceSlug || !projectId) return; + + if (action === "delete") { + archivedIssueStore.deleteArchivedIssue(group_by, null, issue); + } + }; + + const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : null; + + const states = projectStore?.projectStates || null; + const priorities = ISSUE_PRIORITIES || null; + const labels = projectStore?.projectLabels || null; + const members = projectStore?.projectMembers || null; + const stateGroups = ISSUE_STATE_GROUPS || null; + const projects = workspaceSlug ? projectStore?.projects[workspaceSlug.toString()] || null : null; + const estimates = + projectDetails?.estimate !== null + ? projectStore.projectEstimates?.find((e) => e.id === projectDetails?.estimate) || null + : null; + + return ( +
+ ( + handleIssues(group_by, issue, "delete")} /> + )} + display_properties={display_properties} + states={states} + stateGroups={stateGroups} + priorities={priorities} + labels={labels} + members={members?.map((m) => m.member) ?? null} + projects={projects} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} + /> +
+ ); +}); diff --git a/web/components/issues/issue-layouts/list/roots/index.ts b/web/components/issues/issue-layouts/list/roots/index.ts index 139c09a7a..aae6f833c 100644 --- a/web/components/issues/issue-layouts/list/roots/index.ts +++ b/web/components/issues/issue-layouts/list/roots/index.ts @@ -3,3 +3,4 @@ export * from "./module-root"; export * from "./profile-issues-root"; export * from "./project-root"; export * from "./project-view-root"; +export * from "./archived-issue-root"; diff --git a/web/components/issues/issue-layouts/quick-action-dropdowns/archived-issue.tsx b/web/components/issues/issue-layouts/quick-action-dropdowns/archived-issue.tsx new file mode 100644 index 000000000..428fca5d4 --- /dev/null +++ b/web/components/issues/issue-layouts/quick-action-dropdowns/archived-issue.tsx @@ -0,0 +1,76 @@ +import { useState } from "react"; +import { useRouter } from "next/router"; +import { CustomMenu } from "@plane/ui"; +import { Link, Trash2 } from "lucide-react"; +// hooks +import useToast from "hooks/use-toast"; +// components +import { DeleteArchivedIssueModal } from "components/issues"; +// helpers +import { copyUrlToClipboard } from "helpers/string.helper"; +// types +import { IIssue } from "types"; + +type Props = { + issue: IIssue; + handleDelete: () => Promise; +}; + +export const ArchivedIssueQuickActions: React.FC = (props) => { + const { issue, handleDelete } = props; + + const router = useRouter(); + const { workspaceSlug } = router.query; + + // states + const [deleteIssueModal, setDeleteIssueModal] = useState(false); + + const { setToastAlert } = useToast(); + + const handleCopyIssueLink = () => { + copyUrlToClipboard(`/${workspaceSlug}/projects/${issue.project}/archived-issues/${issue.id}`).then(() => + setToastAlert({ + type: "success", + title: "Link copied", + message: "Issue link copied to clipboard", + }) + ); + }; + + return ( + <> + setDeleteIssueModal(false)} + onSubmit={handleDelete} + /> + + { + e.preventDefault(); + e.stopPropagation(); + handleCopyIssueLink(); + }} + > +
+ + Copy link +
+
+ { + e.preventDefault(); + e.stopPropagation(); + setDeleteIssueModal(true); + }} + > +
+ + Delete issue +
+
+
+ + ); +}; diff --git a/web/components/issues/issue-layouts/quick-action-dropdowns/index.ts b/web/components/issues/issue-layouts/quick-action-dropdowns/index.ts index 0d281a2a3..642c39032 100644 --- a/web/components/issues/issue-layouts/quick-action-dropdowns/index.ts +++ b/web/components/issues/issue-layouts/quick-action-dropdowns/index.ts @@ -1,3 +1,4 @@ export * from "./cycle-issue"; export * from "./module-issue"; export * from "./project-issue"; +export * from "./archived-issue"; diff --git a/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx b/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx new file mode 100644 index 000000000..2906de3f1 --- /dev/null +++ b/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { useRouter } from "next/router"; +import { observer } from "mobx-react-lite"; +import useSWR from "swr"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +// components +import { ArchivedIssueListLayout, ArchivedIssueAppliedFiltersRoot } from "components/issues"; + +export const ArchivedIssueLayoutRoot: React.FC = observer(() => { + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { archivedIssueFilters: archivedIssueFiltersStore, archivedIssues: archivedIssueStore } = useMobxStore(); + + useSWR(workspaceSlug && projectId ? `ARCHIVED_FILTERS_AND_ISSUES_${projectId.toString()}` : null, async () => { + if (workspaceSlug && projectId) { + await archivedIssueFiltersStore.fetchUserProjectFilters(workspaceSlug.toString(), projectId.toString()); + await archivedIssueStore.fetchIssues(workspaceSlug.toString(), projectId.toString()); + } + }); + + return ( +
+ +
+ +
+
+ ); +}); diff --git a/web/components/issues/issue-layouts/roots/index.ts b/web/components/issues/issue-layouts/roots/index.ts index 742bc43b9..515d73403 100644 --- a/web/components/issues/issue-layouts/roots/index.ts +++ b/web/components/issues/issue-layouts/roots/index.ts @@ -3,3 +3,4 @@ export * from "./global-view-layout-root"; export * from "./module-layout-root"; export * from "./project-layout-root"; export * from "./project-view-layout-root"; +export * from "./archived-issue-layout-root"; diff --git a/web/components/issues/issue-peek-overview/root.tsx b/web/components/issues/issue-peek-overview/root.tsx index 8324e783f..255e22929 100644 --- a/web/components/issues/issue-peek-overview/root.tsx +++ b/web/components/issues/issue-peek-overview/root.tsx @@ -1,4 +1,6 @@ import { FC, ReactNode } from "react"; +import { useRouter } from "next/router"; +import useSWR from "swr"; import { observer } from "mobx-react-lite"; // components import { IssueView } from "./view"; @@ -6,22 +8,78 @@ import { IssueView } from "./view"; import { useMobxStore } from "lib/mobx/store-provider"; // types import { IIssue } from "types"; +import { RootStore } from "store/root"; +// hooks +import useToast from "hooks/use-toast"; +// helpers +import { copyUrlToClipboard } from "helpers/string.helper"; interface IIssuePeekOverview { workspaceSlug: string; projectId: string; issueId: string; handleIssue: (issue: Partial) => void; + isArchived?: boolean; children?: ReactNode; } export const IssuePeekOverview: FC = observer((props) => { - const { workspaceSlug, projectId, issueId, handleIssue, children } = props; + const { workspaceSlug, projectId, issueId, handleIssue, children, isArchived = false } = props; - const { issueDetail: issueDetailStore, project: projectStore, user: userStore } = useMobxStore(); + const router = useRouter(); + const { peekIssueId } = router.query as { peekIssueId: string }; + + const { + user: userStore, + issue: issueStore, + issueDetail: issueDetailStore, + archivedIssueDetail: archivedIssueDetailStore, + archivedIssues: archivedIssuesStore, + project: projectStore, + }: RootStore = useMobxStore(); + + const { setToastAlert } = useToast(); + + useSWR( + workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId + ? `ISSUE_PEEK_OVERVIEW_${workspaceSlug}_${projectId}_${peekIssueId}` + : null, + async () => { + if (workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId) { + if (isArchived) await archivedIssueDetailStore.fetchPeekIssueDetails(workspaceSlug, projectId, issueId); + else await issueDetailStore.fetchPeekIssueDetails(workspaceSlug, projectId, issueId); + } + } + ); + + const handleCopyText = (e: React.MouseEvent) => { + e.stopPropagation(); + e.preventDefault(); + copyUrlToClipboard( + `${workspaceSlug}/projects/${projectId}/${isArchived ? "archived-issues" : "issues"}/${peekIssueId}` + ).then(() => { + setToastAlert({ + type: "success", + title: "Link Copied!", + message: "Issue link copied to clipboard.", + }); + }); + }; + + const redirectToIssueDetail = () => { + router.push({ + pathname: `/${workspaceSlug}/projects/${projectId}/${isArchived ? "archived-issues" : "issues"}/${issueId}`, + }); + }; + + const issue = isArchived ? archivedIssueDetailStore.getIssue : issueDetailStore.getIssue; + const isLoading = isArchived ? archivedIssueDetailStore.loader : issueDetailStore.loader; const issueUpdate = (_data: Partial) => { - handleIssue(_data); + if (handleIssue) { + handleIssue(_data); + issueDetailStore.updateIssue(workspaceSlug, projectId, issueId, _data); + } }; const issueReactionCreate = (reaction: string) => @@ -49,7 +107,18 @@ export const IssuePeekOverview: FC = observer((props) => { const issueSubscriptionRemove = () => issueDetailStore.removeIssueSubscription(workspaceSlug, projectId, issueId); - const handleDeleteIssue = () => issueDetailStore.deleteIssue(workspaceSlug, projectId, issueId); + const handleDeleteIssue = async () => { + if (isArchived) await archivedIssuesStore.deleteArchivedIssue(workspaceSlug, projectId, issue!); + else await issueStore.deleteIssue(workspaceSlug, projectId, issue!); + const { query } = router; + if (query.peekIssueId) { + delete query.peekIssueId; + router.push({ + pathname: router.pathname, + query: { ...query }, + }); + } + }; const userRole = userStore.currentProjectRole ?? 5; @@ -58,6 +127,11 @@ export const IssuePeekOverview: FC = observer((props) => { workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} + issue={issue} + isLoading={isLoading} + isArchived={isArchived} + handleCopyText={handleCopyText} + redirectToIssueDetail={redirectToIssueDetail} issueUpdate={issueUpdate} issueReactionCreate={issueReactionCreate} issueReactionRemove={issueReactionRemove} diff --git a/web/components/issues/issue-peek-overview/view.tsx b/web/components/issues/issue-peek-overview/view.tsx index 3f01cbadf..509fe593a 100644 --- a/web/components/issues/issue-peek-overview/view.tsx +++ b/web/components/issues/issue-peek-overview/view.tsx @@ -3,26 +3,28 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import useSWR from "swr"; import { MoveRight, MoveDiagonal, Bell, Link2, Trash2 } from "lucide-react"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; // components import { PeekOverviewIssueDetails } from "./issue-detail"; import { PeekOverviewProperties } from "./properties"; import { IssueComment } from "./activity"; import { Button, CenterPanelIcon, CustomSelect, FullScreenPanelIcon, SidePanelIcon } from "@plane/ui"; import { DeleteIssueModal } from "../delete-issue-modal"; +import { DeleteArchivedIssueModal } from "../delete-archived-issue-modal"; // types import { IIssue } from "types"; import { RootStore } from "store/root"; // hooks -import useToast from "hooks/use-toast"; -// helpers -import { copyUrlToClipboard } from "helpers/string.helper"; +import { useMobxStore } from "lib/mobx/store-provider"; interface IIssueView { workspaceSlug: string; projectId: string; issueId: string; + issue: IIssue | null; + isLoading?: boolean; + isArchived?: boolean; + handleCopyText: (e: React.MouseEvent) => void; + redirectToIssueDetail: () => void; issueUpdate: (issue: Partial) => void; issueReactionCreate: (reaction: string) => void; issueReactionRemove: (reaction: string) => void; @@ -64,6 +66,11 @@ export const IssueView: FC = observer((props) => { workspaceSlug, projectId, issueId, + issue, + isLoading, + isArchived, + handleCopyText, + redirectToIssueDetail, issueUpdate, issueReactionCreate, issueReactionRemove, @@ -88,20 +95,6 @@ export const IssueView: FC = observer((props) => { const [peekMode, setPeekMode] = useState("side-peek"); const [deleteIssueModal, setDeleteIssueModal] = useState(false); - const { setToastAlert } = useToast(); - - const handleCopyText = (e: React.MouseEvent) => { - e.stopPropagation(); - e.preventDefault(); - copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/issues/${peekIssueId}`).then(() => { - setToastAlert({ - type: "success", - title: "Link Copied!", - message: "Issue link copied to clipboard.", - }); - }); - }; - const updateRoutePeekId = () => { if (issueId != peekIssueId) { const { query } = router; @@ -122,23 +115,6 @@ export const IssueView: FC = observer((props) => { } }; - const redirectToIssueDetail = () => { - router.push({ - pathname: `/${workspaceSlug}/projects/${projectId}/issues/${issueId}`, - }); - }; - - useSWR( - workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId - ? `ISSUE_PEEK_OVERVIEW_${workspaceSlug}_${projectId}_${peekIssueId}` - : null, - async () => { - if (workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId) { - await issueDetailStore.fetchPeekIssueDetails(workspaceSlug, projectId, issueId); - } - } - ); - useSWR( workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId ? `ISSUE_PEEK_OVERVIEW_SUBSCRIPTION_${workspaceSlug}_${projectId}_${peekIssueId}` @@ -150,10 +126,9 @@ export const IssueView: FC = observer((props) => { } ); - const issue = issueDetailStore.getIssue; - const issueReactions = issueDetailStore.getIssueReactions; - const issueComments = issueDetailStore.getIssueComments; - const issueSubscription = issueDetailStore.getIssueSubscription; + const issueReactions = issueDetailStore.getIssueReactions || []; + const issueComments = issueDetailStore.getIssueComments || []; + const issueSubscription = issueDetailStore.getIssueSubscription || []; const user = userStore?.currentUser; @@ -161,7 +136,7 @@ export const IssueView: FC = observer((props) => { return ( <> - {issue && ( + {issue && !isArchived && ( setDeleteIssueModal(false)} @@ -169,6 +144,14 @@ export const IssueView: FC = observer((props) => { onSubmit={handleDeleteIssue} /> )} + {issue && isArchived && ( + setDeleteIssueModal(false)} + onSubmit={handleDeleteIssue} + /> + )}
{children && (
@@ -229,18 +212,20 @@ export const IssueView: FC = observer((props) => {
- + {!isArchived && ( + + )} @@ -253,8 +238,11 @@ export const IssueView: FC = observer((props) => {
{/* content */} -
- {issueDetailStore?.loader && !issue ? ( +
+ {isArchived && ( +
+ )} + {isLoading && !issue ? (
Loading...
) : ( issue && ( diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/index.tsx index cb0db2f78..13fb00f6d 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/index.tsx @@ -4,6 +4,7 @@ import { useRouter } from "next/router"; import { AppLayout } from "layouts/app-layout"; // contexts import { IssueViewContextProvider } from "contexts/issue-view.context"; +import { ArchivedIssueLayoutRoot } from "components/issues"; // ui import { ArchiveIcon } from "@plane/ui"; import { ProjectArchivedIssuesHeader } from "components/headers"; @@ -29,7 +30,7 @@ const ProjectArchivedIssuesPage: NextPageWithLayout = () => {
- {/* */} +
); }; diff --git a/web/store/archived-issues/index.ts b/web/store/archived-issues/index.ts index abfd52768..b1230f1c9 100644 --- a/web/store/archived-issues/index.ts +++ b/web/store/archived-issues/index.ts @@ -1,2 +1,3 @@ export * from "./issue.store"; export * from "./issue_filters.store"; +export * from "./issue_detail.store"; diff --git a/web/store/archived-issues/issue.store.ts b/web/store/archived-issues/issue.store.ts index 11c29f25c..624f4714a 100644 --- a/web/store/archived-issues/issue.store.ts +++ b/web/store/archived-issues/issue.store.ts @@ -1,10 +1,10 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; +import { observable, action, computed, makeObservable, runInAction, autorun } from "mobx"; // store import { RootStore } from "../root"; // types import { IIssue } from "types"; // services -import { IssueService } from "services/issue"; +import { IssueArchiveService } from "services/issue"; import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers"; import { IIssueGroupWithSubGroupsStructure, @@ -24,12 +24,23 @@ export interface IArchivedIssueStore { ungrouped: IIssueUnGroupedStructure; }; }; + issueDetail: { + [project_id: string]: { + [issue_id: string]: IIssue; + }; + }; + + // services + archivedIssueService: IssueArchiveService; + // computed getIssueType: IIssueType | null; getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null; + // action fetchIssues: (workspaceSlug: string, projectId: string) => Promise; updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void; + deleteArchivedIssue: (group: string | null, sub_group: string | null, issue: IIssue) => Promise; } export class ArchivedIssueStore implements IArchivedIssueStore { @@ -48,8 +59,10 @@ export class ArchivedIssueStore implements IArchivedIssueStore { ungrouped: IIssue[]; }; } = {}; + issueDetail: IArchivedIssueStore["issueDetail"] = {}; + // service - issueService; + archivedIssueService; rootStore; constructor(_rootStore: RootStore) { @@ -58,34 +71,36 @@ export class ArchivedIssueStore implements IArchivedIssueStore { loader: observable.ref, error: observable.ref, issues: observable.ref, + // computed getIssueType: computed, getIssues: computed, + // actions fetchIssues: action, updateIssueStructure: action, + deleteArchivedIssue: action, }); this.rootStore = _rootStore; - this.issueService = new IssueService(); + this.archivedIssueService = new IssueArchiveService(); + + autorun(() => { + const workspaceSlug = this.rootStore.workspace.workspaceSlug; + const projectId = this.rootStore.project.projectId; + + if ( + workspaceSlug && + projectId && + this.rootStore.archivedIssueFilters.userDisplayFilters && + this.rootStore.archivedIssueFilters.userFilters + ) + this.fetchIssues(workspaceSlug, projectId); + }); } get getIssueType() { - const groupedLayouts = ["kanban", "list", "calendar"]; - const ungroupedLayouts = ["spreadsheet", "gantt_chart"]; - - const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null; - const issueSubGroup = this.rootStore?.issueFilter?.userDisplayFilters?.sub_group_by || null; - if (!issueLayout) return null; - - const _issueState = groupedLayouts.includes(issueLayout) - ? issueSubGroup - ? "groupWithSubGroups" - : "grouped" - : ungroupedLayouts.includes(issueLayout) - ? "ungrouped" - : null; - - return _issueState || null; + const issueSubGroup = this.rootStore.archivedIssueFilters.userDisplayFilters?.sub_group_by || null; + return issueSubGroup ? "groupWithSubGroups" : "grouped"; } get getIssues() { @@ -122,10 +137,6 @@ export class ArchivedIssueStore implements IArchivedIssueStore { }, }; } - if (issueType === "ungrouped") { - issues = issues as IIssueUnGroupedStructure; - issues = issues.map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)); - } const orderBy = this.rootStore?.issueFilter?.userDisplayFilters?.order_by || ""; if (orderBy === "-created_at") { @@ -154,8 +165,8 @@ export class ArchivedIssueStore implements IArchivedIssueStore { this.rootStore.workspace.setWorkspaceSlug(workspaceSlug); this.rootStore.project.setProjectId(projectId); - const params = this.rootStore?.issueFilter?.appliedFilters; - const issueResponse = await this.issueService.getIssuesWithParams(workspaceSlug, projectId, params); + const params = this.rootStore.archivedIssueFilters.appliedFilters; + const issueResponse = await this.archivedIssueService.getArchivedIssues(workspaceSlug, projectId, params); const issueType = this.getIssueType; if (issueType != null) { @@ -178,7 +189,42 @@ export class ArchivedIssueStore implements IArchivedIssueStore { console.error("Error: Fetching error in issues", error); this.loader = false; this.error = error; - return error; + throw error; } }; + + /** + * @description Function to delete issue from the store. NOTE: This function is not deleting issue from the backend. + */ + deleteArchivedIssue = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => { + const projectId: string | null = issue?.project; + const issueType = this.getIssueType; + if (!projectId || !issueType) return null; + + let issues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null = + this.getIssues; + if (!issues) return null; + + if (issueType === "grouped" && group_id) { + issues = issues as IIssueGroupedStructure; + issues = { + ...issues, + [group_id]: issues?.[group_id]?.filter((i) => i?.id !== issue?.id), + }; + } + if (issueType === "groupWithSubGroups" && group_id && sub_group_id) { + issues = issues as IIssueGroupWithSubGroupsStructure; + issues = { + ...issues, + [sub_group_id]: { + ...issues?.[sub_group_id], + [group_id]: issues?.[sub_group_id]?.[group_id]?.filter((i) => i?.id !== issue?.id), + }, + }; + } + + runInAction(() => { + this.issues = { ...this.issues, [projectId]: { ...this.issues[projectId], [issueType]: issues } }; + }); + }; } diff --git a/web/store/archived-issues/issue_detail.store.ts b/web/store/archived-issues/issue_detail.store.ts new file mode 100644 index 000000000..ef3468f19 --- /dev/null +++ b/web/store/archived-issues/issue_detail.store.ts @@ -0,0 +1,198 @@ +import { observable, action, makeObservable, runInAction, computed } from "mobx"; +// store +import { RootStore } from "../root"; +// types +import { IIssue } from "types"; +// services +import { IssueArchiveService } from "services/issue"; + +export interface IArchivedIssueDetailStore { + loader: boolean; + error: any | null; + // issues + issueDetail: { + [issue_id: string]: IIssue; + }; + peekId: string | null; + + // services + archivedIssueService: IssueArchiveService; + + // computed + getIssue: IIssue | null; + + // action + deleteArchivedIssue: (workspaceSlug: string, projectId: string, issuesId: string) => Promise; + unarchiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise; + fetchIssueDetails: (workspaceSlug: string, projectId: string, issueId: string) => Promise; + fetchPeekIssueDetails: (workspaceSlug: string, projectId: string, issueId: string) => Promise; +} + +export class ArchivedIssueDetailStore implements IArchivedIssueDetailStore { + loader: boolean = false; + error: any | null = null; + issueDetail: IArchivedIssueDetailStore["issueDetail"] = {}; + peekId: string | null = null; + + // service + archivedIssueService; + rootStore; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable.ref, + error: observable.ref, + issueDetail: observable.ref, + peekId: observable.ref, + + // computed + getIssue: computed, + + // actions + deleteArchivedIssue: action, + unarchiveIssue: action, + fetchIssueDetails: action, + fetchPeekIssueDetails: action, + }); + this.rootStore = _rootStore; + this.archivedIssueService = new IssueArchiveService(); + } + + get getIssue() { + if (!this.peekId) return null; + const _issue = this.issueDetail[this.peekId]; + return _issue || null; + } + + /** + * @description Function to delete archived issue from the detail store and backend. + */ + deleteArchivedIssue = async (workspaceSlug: string, projectId: string, issuesId: string) => { + const originalIssues = { ...this.issueDetail }; + + const _issues = { ...this.issueDetail }; + delete _issues[issuesId]; + + // optimistically deleting item from store + runInAction(() => { + this.issueDetail = _issues; + }); + + try { + runInAction(() => { + this.loader = true; + this.error = null; + }); + + // deleting using api + const issueResponse = await this.archivedIssueService.deleteArchivedIssue(workspaceSlug, projectId, issuesId); + + runInAction(() => { + this.loader = false; + this.error = null; + }); + + return issueResponse; + } catch (error) { + console.error("Error: Fetching error in issues", error); + runInAction(() => { + this.loader = false; + this.error = error; + // reverting back to original issues + this.issueDetail = originalIssues; + }); + throw error; + } + }; + + fetchIssueDetails = async (workspaceSlug: string, projectId: string, issueId: string) => { + try { + runInAction(() => { + this.loader = true; + this.error = null; + }); + + const issueResponse = await this.archivedIssueService.retrieveArchivedIssue(workspaceSlug, projectId, issueId); + + runInAction(() => { + this.loader = false; + this.error = null; + this.issueDetail = { + ...this.issueDetail, + [issueId]: issueResponse, + }; + }); + + return issueResponse; + } catch (error) { + console.error("Error: Fetching error in issues", error); + runInAction(() => { + this.loader = false; + this.error = error; + }); + throw error; + } + }; + + unarchiveIssue = async (workspaceSlug: string, projectId: string, issueId: string) => { + try { + runInAction(() => { + this.loader = true; + this.error = null; + }); + + const issueResponse = await this.archivedIssueService.unarchiveIssue(workspaceSlug, projectId, issueId); + this.rootStore.archivedIssues.fetchIssues(workspaceSlug, projectId); + + // deleting from issue detail store + const _issues = { ...this.issueDetail }; + delete _issues[issueId]; + runInAction(() => { + this.issueDetail = _issues; + }); + + return issueResponse; + } catch (error) { + console.error("Error: Fetching error in issues", error); + runInAction(() => { + this.loader = false; + this.error = error; + }); + throw error; + } + }; + + fetchPeekIssueDetails = async (workspaceSlug: string, projectId: string, issueId: string) => { + runInAction(() => { + this.loader = true; + this.error = null; + this.peekId = issueId; + }); + + try { + const issueResponse = await this.archivedIssueService.retrieveArchivedIssue(workspaceSlug, projectId, issueId); + await this.rootStore.issueDetail.fetchIssueReactions(workspaceSlug, projectId, issueId); + await this.rootStore.issueDetail.fetchIssueComments(workspaceSlug, projectId, issueId); + + runInAction(() => { + this.loader = false; + this.error = null; + this.issueDetail = { + ...this.issueDetail, + [issueId]: issueResponse, + }; + }); + + return issueResponse; + } catch (error) { + console.error("Error: Fetching error in issues", error); + runInAction(() => { + this.loader = false; + this.error = error; + this.peekId = null; + }); + throw error; + } + }; +} diff --git a/web/store/archived-issues/issue_filters.store.ts b/web/store/archived-issues/issue_filters.store.ts index 04a0da9bd..edb1549a6 100644 --- a/web/store/archived-issues/issue_filters.store.ts +++ b/web/store/archived-issues/issue_filters.store.ts @@ -1,20 +1,53 @@ -import { observable, computed, makeObservable } from "mobx"; +import { observable, computed, makeObservable, action, runInAction } from "mobx"; // helpers import { handleIssueQueryParamsByLayout } from "helpers/issue.helper"; +// services +import { IssueService } from "services/issue"; +import { ProjectService } from "services/project"; // types import { RootStore } from "../root"; -import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types"; +import { + IIssueDisplayFilterOptions, + IIssueDisplayProperties, + IIssueFilterOptions, + TIssueParams, + IProjectViewProps, +} from "types"; export interface IArchivedIssueFilterStore { + loader: boolean; + error: any | null; + + // observables userDisplayProperties: IIssueDisplayProperties; userDisplayFilters: IIssueDisplayFilterOptions; userFilters: IIssueFilterOptions; + // services + projectService: ProjectService; + issueService: IssueService; + // computed appliedFilters: TIssueParams[] | null; + + // actions + fetchUserProjectFilters: (workspaceSlug: string, projectId: string) => Promise; + updateUserFilters: ( + workspaceSlug: string, + projectId: string, + properties: Partial + ) => Promise; + updateDisplayProperties: ( + workspaceSlug: string, + projectId: string, + properties: Partial + ) => Promise; } export class ArchivedIssueFilterStore implements IArchivedIssueFilterStore { + loader: boolean = false; + error: any | null = null; + // observables userFilters: IIssueFilterOptions = { priority: null, @@ -52,6 +85,10 @@ export class ArchivedIssueFilterStore implements IArchivedIssueFilterStore { // root store rootStore; + // services + projectService: ProjectService; + issueService: IssueService; + constructor(_rootStore: RootStore) { makeObservable(this, { // observables @@ -61,9 +98,19 @@ export class ArchivedIssueFilterStore implements IArchivedIssueFilterStore { // computed appliedFilters: computed, + + // actions + fetchUserProjectFilters: action, + updateUserFilters: action, + updateDisplayProperties: action, + computedFilter: action, }); this.rootStore = _rootStore; + + // services + this.issueService = new IssueService(); + this.projectService = new ProjectService(); } computedFilter = (filters: any, filteredParams: any) => { @@ -89,7 +136,7 @@ export class ArchivedIssueFilterStore implements IArchivedIssueFilterStore { labels: this.userFilters?.labels || undefined, start_date: this.userFilters?.start_date || undefined, target_date: this.userFilters?.target_date || undefined, - group_by: this.userDisplayFilters?.group_by || "state", + group_by: this.userDisplayFilters?.group_by, order_by: this.userDisplayFilters?.order_by || "-created_at", sub_group_by: this.userDisplayFilters?.sub_group_by || undefined, type: this.userDisplayFilters?.type || undefined, @@ -98,12 +145,100 @@ export class ArchivedIssueFilterStore implements IArchivedIssueFilterStore { start_target_date: this.userDisplayFilters?.start_target_date || true, }; - const filteredParams = handleIssueQueryParamsByLayout(this.userDisplayFilters.layout, "issues"); + const filteredParams = handleIssueQueryParamsByLayout("list", "issues"); if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); - if (this.userDisplayFilters.layout === "calendar") filteredRouteParams.group_by = "target_date"; - if (this.userDisplayFilters.layout === "gantt_chart") filteredRouteParams.start_target_date = true; - return filteredRouteParams; } + + updateUserFilters = async (workspaceSlug: string, projectId: string, properties: Partial) => { + const newViewProps = { + display_filters: { + ...this.userDisplayFilters, + ...properties.display_filters, + }, + filters: { + ...this.userFilters, + ...properties.filters, + }, + }; + + // set sub_group_by to null if group_by is set to null + if (newViewProps.display_filters.group_by === null) newViewProps.display_filters.sub_group_by = null; + + // set group_by to state if layout is switched to kanban and group_by is null + if (newViewProps.display_filters.layout === "kanban" && newViewProps.display_filters.group_by === null) + newViewProps.display_filters.group_by = "state"; + + try { + runInAction(() => { + this.userFilters = newViewProps.filters; + this.userDisplayFilters = { + ...newViewProps.display_filters, + layout: "list", + }; + }); + + this.projectService.setProjectView(workspaceSlug, projectId, { + view_props: newViewProps, + }); + } catch (error) { + this.fetchUserProjectFilters(workspaceSlug, projectId); + + runInAction(() => { + this.error = error; + }); + + console.log("Failed to update user filters in issue filter store", error); + } + }; + + updateDisplayProperties = async ( + workspaceSlug: string, + projectId: string, + properties: Partial + ) => { + const newProperties: IIssueDisplayProperties = { + ...this.userDisplayProperties, + ...properties, + }; + + try { + runInAction(() => { + this.userDisplayProperties = newProperties; + }); + + await this.issueService.updateIssueDisplayProperties(workspaceSlug, projectId, newProperties); + } catch (error) { + this.fetchUserProjectFilters(workspaceSlug, projectId); + + runInAction(() => { + this.error = error; + }); + + console.log("Failed to update user display properties in issue filter store", error); + } + }; + + fetchUserProjectFilters = async (workspaceSlug: string, projectId: string) => { + try { + const memberResponse = await this.projectService.projectMemberMe(workspaceSlug, projectId); + const issueProperties = await this.issueService.getIssueDisplayProperties(workspaceSlug, projectId); + + runInAction(() => { + this.userFilters = memberResponse?.view_props?.filters; + this.userDisplayFilters = { + ...(memberResponse?.view_props?.display_filters ?? {}), + layout: "list", + }; + this.userDisplayProperties = issueProperties?.properties; + }); + } catch (error) { + runInAction(() => { + this.error = error; + }); + + console.log("Failed to fetch user filters in issue filter store", error); + } + }; } diff --git a/web/store/root.ts b/web/store/root.ts index a1614dbdd..9af4db492 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -85,6 +85,8 @@ import { IArchivedIssueStore, ArchivedIssueFilterStore, IArchivedIssueFilterStore, + ArchivedIssueDetailStore, + IArchivedIssueDetailStore, } from "store/archived-issues"; import { DraftIssueStore, IDraftIssueStore, DraftIssueFilterStore, IDraftIssueFilterStore } from "store/draft-issues"; import { @@ -151,6 +153,7 @@ export class RootStore { profileIssueFilters: IProfileIssueFilterStore; archivedIssues: IArchivedIssueStore; + archivedIssueDetail: IArchivedIssueDetailStore; archivedIssueFilters: IArchivedIssueFilterStore; draftIssues: IDraftIssueStore; @@ -212,6 +215,7 @@ export class RootStore { this.profileIssueFilters = new ProfileIssueFilterStore(this); this.archivedIssues = new ArchivedIssueStore(this); + this.archivedIssueDetail = new ArchivedIssueDetailStore(this); this.archivedIssueFilters = new ArchivedIssueFilterStore(this); this.draftIssues = new DraftIssueStore(this); diff --git a/yarn.lock b/yarn.lock index 28068404f..04718cb90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -919,7 +919,7 @@ 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.1", "@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.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== @@ -967,12 +967,12 @@ dependencies: tslib "~2.5.0" -"@blueprintjs/colors@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@blueprintjs/colors/-/colors-5.0.4.tgz#c3e7d87c576eac624d6321432750ee74632327f5" - integrity sha512-dtAN7gOkuPPZRKIoafLXKVGj6MkpIrphMdoxT+bkaIPTVUWLtYPtpQSh08EH7IBI3zzTqfdqXee+U5lmyEfY5g== +"@blueprintjs/colors@^5.0.5": + version "5.0.5" + resolved "https://registry.yarnpkg.com/@blueprintjs/colors/-/colors-5.0.5.tgz#3a8faa640dd2877aa4fd00b886cf8e58daf5f868" + integrity sha512-UcCsBxE8GTF6GW1oHBb+cuhPpKiJFWbIRkemwcRkp9HvXXQHxEaXlFFC6jAx5pf3JmRwde5/ck3r+lJFP1YqzA== dependencies: - tslib "~2.5.0" + tslib "~2.6.2" "@blueprintjs/core@^4.16.3", "@blueprintjs/core@^4.20.2": version "4.20.2" @@ -991,19 +991,19 @@ react-transition-group "^4.4.5" tslib "~2.5.0" -"@blueprintjs/core@^5.5.1": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-5.5.1.tgz#1fa09868318f46758edb6efd8130b13034333adf" - integrity sha512-+8Af166xlLzzaoDDyzX1Adgd/hCVuIhp4/6RDDzcDnVHxQG4jnHK+D70LIV0FYNMZCzPW0Z6gH9ZTP52QDSqeg== +"@blueprintjs/core@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-5.6.0.tgz#915b708a8c2d7e916d30dae704829e2d948301d9" + integrity sha512-NtQL/iu8P8DhHUCWCstc9Ps+JkRZCPRJ2ZoxubOt21pfxN50CN0sKHkDETHUQyZ73RviveVIIK+m32mT5Wwdqg== dependencies: - "@blueprintjs/colors" "^5.0.4" - "@blueprintjs/icons" "^5.2.1" + "@blueprintjs/colors" "^5.0.5" + "@blueprintjs/icons" "^5.3.0" "@popperjs/core" "^2.11.7" classnames "^2.3.1" normalize.css "^8.0.1" react-popper "^2.3.0" react-transition-group "^4.4.5" - tslib "~2.5.0" + tslib "~2.6.2" "@blueprintjs/icons@^4.16.0": version "4.16.0" @@ -1014,14 +1014,14 @@ classnames "^2.3.1" tslib "~2.5.0" -"@blueprintjs/icons@^5.2.1": - version "5.2.1" - resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-5.2.1.tgz#3b2409fc01ca4c140b9e4cb10c6da3a22b24eed7" - integrity sha512-JAkcDQks4wZoZAcfKeId4/S4I0cEiuNhFZ88Kc+RQkHNUGD78wuANNQvPKeN5j0QXjAxYZ3qMsxKOdJ9YwmZ/A== +"@blueprintjs/icons@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-5.3.0.tgz#9c9498df415bf7e028ceac15f90228d0ffd9a521" + integrity sha512-PGZHbWZ41b/SDOENlZQE1pAab4eluzf/hZ6sHB5nPrQNJuGNr94yaPp6u//Tu24iqVFFP20Soi3+ckhf/o3V/g== dependencies: change-case "^4.1.2" classnames "^2.3.1" - tslib "~2.5.0" + tslib "~2.6.2" "@blueprintjs/popover2@^1.13.3": version "1.14.11" @@ -1037,13 +1037,13 @@ tslib "~2.5.0" "@blueprintjs/popover2@^2.0.10": - version "2.0.16" - resolved "https://registry.yarnpkg.com/@blueprintjs/popover2/-/popover2-2.0.16.tgz#208d248efd6e129ba5580707fffde57cb2527365" - integrity sha512-WFQdvhybzVHbkwFt0TdQ285XGP1PN3XH+x0TgMby3j5xBUPBd6UDZ6pZup2ZCMfxB9GGglyAip5ZFM7tRWW6Vg== + version "2.0.17" + resolved "https://registry.yarnpkg.com/@blueprintjs/popover2/-/popover2-2.0.17.tgz#ed1fd3a6fbb0a7ae623ccb649b150a7f22a09534" + integrity sha512-sJTlLD9ihKUITC8xEm1lzae4IumXkwoTEu/ajUTgd3GlLyQsUSC5CdlBihX7LlA60WbuyVSE3Jbazhqw2Fud2w== dependencies: - "@blueprintjs/core" "^5.5.1" + "@blueprintjs/core" "^5.6.0" classnames "^2.3.1" - tslib "~2.5.0" + tslib "~2.6.2" "@cfcs/core@^0.0.6": version "0.0.6" @@ -1519,87 +1519,87 @@ 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.21": - version "5.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.21.tgz#5bf952c9d3703ae4f697702f0821e5dea178f34e" - integrity sha512-eTKWx3WV/nwmRUK4z4K1MzlMyWCsi3WJ3RtV4DiXZeRh4qd4JCyp1Zzzi8Wv9xM4dEBmqQntFoei716PzwmFfA== +"@mui/base@5.0.0-beta.22": + version "5.0.0-beta.22" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.22.tgz#9ea6be6c8bfc4d8f825660da36d228f5315d4706" + integrity sha512-l4asGID5tmyerx9emJfXOKLyXzaBtdXNIFE3M+IrSZaFtGFvaQKHhc3+nxxSxPf1+G44psjczM0ekRQCdXx9HA== dependencies: "@babel/runtime" "^7.23.2" "@floating-ui/react-dom" "^2.0.2" - "@mui/types" "^7.2.7" - "@mui/utils" "^5.14.15" + "@mui/types" "^7.2.8" + "@mui/utils" "^5.14.16" "@popperjs/core" "^2.11.8" clsx "^2.0.0" prop-types "^15.8.1" -"@mui/core-downloads-tracker@^5.14.15": - version "5.14.15" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.15.tgz#23a9100eb125e5ab92e350e53e613e171d80be3b" - integrity sha512-ZCDzBWtCKjAYAlKKM3PA/jG/3uVIDT9ZitOtVixIVmTCQyc5jSV1qhJX8+qIGz4RQZ9KLzPWO2tXd0O5hvzouQ== +"@mui/core-downloads-tracker@^5.14.16": + version "5.14.16" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.16.tgz#03ceb422d69a33e6c1cbd7e943cf60816878be2a" + integrity sha512-97isBjzH2v1K7oB4UH2f4NOkBShOynY6dhnoR2XlUk/g6bb7ZBv2I3D1hvvqPtpEigKu93e7f/jAYr5d9LOc5w== "@mui/material@^5.14.1": - version "5.14.15" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.15.tgz#dadc58588aef4556a0ed6a2d70ad70922df5264f" - integrity sha512-Gq65rHjvLzkxmhG8bvag851Oqsmru7qkUb/cCI2xu7dQzmY345f9xJRJi72sRGjhaqHXWeRKw/yIwp/7oQoeXg== + version "5.14.16" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.16.tgz#45cd62d312d10399d3813ee6dc43bd1f11179bf4" + integrity sha512-W4zZ4vnxgGk6/HqBwgsDHKU7x2l2NhX+r8gAwfg58Rhu3ikfY7NkIS6y8Gl3NkATc4GG1FNaGjjpQKfJx3U6Jw== dependencies: "@babel/runtime" "^7.23.2" - "@mui/base" "5.0.0-beta.21" - "@mui/core-downloads-tracker" "^5.14.15" - "@mui/system" "^5.14.15" - "@mui/types" "^7.2.7" - "@mui/utils" "^5.14.15" - "@types/react-transition-group" "^4.4.7" + "@mui/base" "5.0.0-beta.22" + "@mui/core-downloads-tracker" "^5.14.16" + "@mui/system" "^5.14.16" + "@mui/types" "^7.2.8" + "@mui/utils" "^5.14.16" + "@types/react-transition-group" "^4.4.8" clsx "^2.0.0" csstype "^3.1.2" prop-types "^15.8.1" react-is "^18.2.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.14.15": - version "5.14.15" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.14.15.tgz#1889c92cf8b5c3bca1cdfcc678010c24ad57102d" - integrity sha512-V2Xh+Tu6A07NoSpup0P9m29GwvNMYl5DegsGWqlOTJyAV7cuuVjmVPqxgvL8xBng4R85xqIQJRMjtYYktoPNuQ== +"@mui/private-theming@^5.14.16": + version "5.14.16" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.14.16.tgz#ffdc9a9d3deaa46af000f04c0a9cc3a982f73071" + integrity sha512-FNlL0pTSEBh8nXsVWreCHDSHk+jG8cBx1sxRbT8JVtL+PYbYPi802zfV4B00Kkf0LNRVRvAVQwojMWSR/MYGng== dependencies: "@babel/runtime" "^7.23.2" - "@mui/utils" "^5.14.15" + "@mui/utils" "^5.14.16" prop-types "^15.8.1" -"@mui/styled-engine@^5.14.15": - version "5.14.15" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.14.15.tgz#01e9bd5cc0f4d83e9f636086d42b92ed1b0a360e" - integrity sha512-mbOjRf867BysNpexe5Z/P8s3bWzDPNowmKhi7gtNDP/LPEeqAfiDSuC4WPTXmtvse1dCl30Nl755OLUYuoi7Mw== +"@mui/styled-engine@^5.14.16": + version "5.14.16" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.14.16.tgz#a4a78a9980f138c2e705d04d67d44051f5005f22" + integrity sha512-FfvYvTG/Zd+KXMMImbcMYEeQAbONGuX5Vx3gBmmtB6KyA7Mvm9Pma1ly3R0gc44yeoFd+2wBjn1feS8h42HW5w== dependencies: "@babel/runtime" "^7.23.2" "@emotion/cache" "^11.11.0" csstype "^3.1.2" prop-types "^15.8.1" -"@mui/system@^5.14.15": - version "5.14.15" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.15.tgz#d232134170c46a09414c1ec8707d42bdc043fd90" - integrity sha512-zr0Gdk1RgKiEk+tCMB900LaOpEC8NaGvxtkmMdL/CXgkqQZSVZOt2PQsxJWaw7kE4YVkIe4VukFVc43qcq9u3w== +"@mui/system@^5.14.16": + version "5.14.16" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.16.tgz#5c30c5123767416358c3b73774eb985e189119a4" + integrity sha512-uKnPfsDqDs8bbN54TviAuoGWOmFiQLwNZ3Wvj+OBkJCzwA6QnLb/sSeCB7Pk3ilH4h4jQ0BHtbR+Xpjy9wlOuA== dependencies: "@babel/runtime" "^7.23.2" - "@mui/private-theming" "^5.14.15" - "@mui/styled-engine" "^5.14.15" - "@mui/types" "^7.2.7" - "@mui/utils" "^5.14.15" + "@mui/private-theming" "^5.14.16" + "@mui/styled-engine" "^5.14.16" + "@mui/types" "^7.2.8" + "@mui/utils" "^5.14.16" clsx "^2.0.0" csstype "^3.1.2" prop-types "^15.8.1" -"@mui/types@^7.2.7": - version "7.2.7" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.7.tgz#726052f7d519f0f64657576109aa297def9443ac" - integrity sha512-sofpWmcBqOlTzRbr1cLQuUDKaUYVZTw8ENQrtL39TECRNENEzwgnNPh6WMfqMZlMvf1Aj9DLg74XPjnLr0izUQ== +"@mui/types@^7.2.8": + version "7.2.8" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.8.tgz#2ed4402f104d65fcd4f460ca358654c8935e2285" + integrity sha512-9u0ji+xspl96WPqvrYJF/iO+1tQ1L5GTaDOeG3vCR893yy7VcWwRNiVMmPdPNpMDqx0WV1wtEW9OMwK9acWJzQ== -"@mui/utils@^5.14.15": - version "5.14.15" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.15.tgz#5f8bc39f29cf9fe95fa2c725e441f2116656d9fd" - integrity sha512-QBfHovAvTa0J1jXuYDaXGk+Yyp7+Fm8GSqx6nK2JbezGqzCFfirNdop/+bL9Flh/OQ/64PeXcW4HGDdOge+n3A== +"@mui/utils@^5.14.16": + version "5.14.16" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.16.tgz#09a15fd45530cadc642c5c08eb6cc660ea230506" + integrity sha512-3xV31GposHkwRbQzwJJuooWpK2ybWdEdeUPtRjv/6vjomyi97F3+68l+QVj9tPTvmfSbr2sx5c/NuvDulrdRmA== dependencies: "@babel/runtime" "^7.23.2" - "@types/prop-types" "^15.7.8" + "@types/prop-types" "^15.7.9" prop-types "^15.8.1" react-is "^18.2.0" @@ -2193,30 +2193,30 @@ dependencies: "@daybrush/utils" "^1.4.0" -"@sentry-internal/tracing@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.76.0.tgz#36c54425bc20c08e569e6da52e13d325611cad66" - integrity sha512-QQVIv+LS2sbGf/e5P2dRisHzXpy02dAcLqENLPG4sZ9otRaFNjdFYEqnlJ4qko+ORpJGQEQp/BX7Q/qzZQHlAg== +"@sentry-internal/tracing@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.77.0.tgz#f3d82486f8934a955b3dd2aa54c8d29586e42a37" + integrity sha512-8HRF1rdqWwtINqGEdx8Iqs9UOP/n8E0vXUu3Nmbqj4p5sQPA7vvCfq+4Y4rTqZFc7sNdFpDsRION5iQEh8zfZw== dependencies: - "@sentry/core" "7.76.0" - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" + "@sentry/core" "7.77.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" -"@sentry/browser@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.76.0.tgz#7d73573790023523f7d9c3757b8424b7ad60d664" - integrity sha512-83xA+cWrBhhkNuMllW5ucFsEO2NlUh2iBYtmg07lp3fyVW+6+b1yMKRnc4RFArJ+Wcq6UO+qk2ZEvrSAts1wEw== +"@sentry/browser@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.77.0.tgz#155440f1a0d3a1bbd5d564c28d6b0c9853a51d72" + integrity sha512-nJ2KDZD90H8jcPx9BysQLiQW+w7k7kISCWeRjrEMJzjtge32dmHA8G4stlUTRIQugy5F+73cOayWShceFP7QJQ== dependencies: - "@sentry-internal/tracing" "7.76.0" - "@sentry/core" "7.76.0" - "@sentry/replay" "7.76.0" - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" + "@sentry-internal/tracing" "7.77.0" + "@sentry/core" "7.77.0" + "@sentry/replay" "7.77.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" "@sentry/cli@^1.74.6": - version "1.75.2" - resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.75.2.tgz#2c38647b38300e52c9839612d42b7c23f8d6455b" - integrity sha512-CG0CKH4VCKWzEaegouWfCLQt9SFN+AieFESCatJ7zSuJmzF05ywpMusjxqRul6lMwfUhRKjGKOzcRJ1jLsfTBw== + version "1.76.0" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.76.0.tgz#3d48248a4fec2fee7c4d30320c563c91c75290ec" + integrity sha512-56bVyUJoi52dop/rFEaSoU4AfVRXpR6M+nZBwN1iGUAwdfBrarNbtmIOjfgPi+tVzVB5ck09PzVXG6zeBqJJcA== dependencies: https-proxy-agent "^5.0.0" mkdirp "^0.5.5" @@ -2225,94 +2225,94 @@ proxy-from-env "^1.1.0" which "^2.0.2" -"@sentry/core@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.76.0.tgz#b0d1dc399a862ea8a1c8a1c60a409e92eaf8e9e1" - integrity sha512-M+ptkCTeCNf6fn7p2MmEb1Wd9/JXUWxIT/0QEc+t11DNR4FYy1ZP2O9Zb3Zp2XacO7ORrlL3Yc+VIfl5JTgjfw== +"@sentry/core@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.77.0.tgz#21100843132beeeff42296c8370cdcc7aa1d8510" + integrity sha512-Tj8oTYFZ/ZD+xW8IGIsU6gcFXD/gfE+FUxUaeSosd9KHwBQNOLhZSsYo/tTVf/rnQI/dQnsd4onPZLiL+27aTg== dependencies: - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" -"@sentry/integrations@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.76.0.tgz#ea1b6d86609c5f25999f1d8d87383afdb00c77f0" - integrity sha512-4ea0PNZrGN9wKuE/8bBCRrxxw4Cq5T710y8rhdKHAlSUpbLqr/atRF53h8qH3Fi+ec0m38PB+MivKem9zUwlwA== +"@sentry/integrations@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.77.0.tgz#f2717e05cb7c69363316ccd34096b2ea07ae4c59" + integrity sha512-P055qXgBHeZNKnnVEs5eZYLdy6P49Zr77A1aWJuNih/EenzMy922GOeGy2mF6XYrn1YJSjEwsNMNsQkcvMTK8Q== dependencies: - "@sentry/core" "7.76.0" - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" + "@sentry/core" "7.77.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" localforage "^1.8.1" "@sentry/nextjs@^7.36.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.76.0.tgz#a3018ecf3df25cd8021aeaa8fb0314f8f6f6b38f" - integrity sha512-3/iTnBJ7qOrhoEUQw85CmZ+S2wTZapRui5yfWO6/We11T8q6tvrUPIYmnE0BY/2BIelz4dfPwXRHXRJlgEarhg== + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.77.0.tgz#036b1c45dd106e01d44967c97985464e108922be" + integrity sha512-8tYPBt5luFjrng1sAMJqNjM9sq80q0jbt6yariADU9hEr7Zk8YqFaOI2/Q6yn9dZ6XyytIRtLEo54kk2AO94xw== dependencies: "@rollup/plugin-commonjs" "24.0.0" - "@sentry/core" "7.76.0" - "@sentry/integrations" "7.76.0" - "@sentry/node" "7.76.0" - "@sentry/react" "7.76.0" - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" - "@sentry/vercel-edge" "7.76.0" + "@sentry/core" "7.77.0" + "@sentry/integrations" "7.77.0" + "@sentry/node" "7.77.0" + "@sentry/react" "7.77.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" + "@sentry/vercel-edge" "7.77.0" "@sentry/webpack-plugin" "1.20.0" chalk "3.0.0" resolve "1.22.8" rollup "2.78.0" stacktrace-parser "^0.1.10" -"@sentry/node@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.76.0.tgz#9efc8bbe4825b4a5a4f853210364d21980dd790e" - integrity sha512-C+YZ5S5W9oTphdWTBgV+3nDdcV1ldnupIHylHzf2Co+xNtJ76V06N5NjdJ/l9+qvQjMn0DdSp7Uu7KCEeNBT/g== +"@sentry/node@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.77.0.tgz#a247452779a5bcb55724457707286e3e4a29dbbe" + integrity sha512-Ob5tgaJOj0OYMwnocc6G/CDLWC7hXfVvKX/ofkF98+BbN/tQa5poL+OwgFn9BA8ud8xKzyGPxGU6LdZ8Oh3z/g== dependencies: - "@sentry-internal/tracing" "7.76.0" - "@sentry/core" "7.76.0" - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" + "@sentry-internal/tracing" "7.77.0" + "@sentry/core" "7.77.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" https-proxy-agent "^5.0.0" -"@sentry/react@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.76.0.tgz#8c91f6401372c29c74cc4005aaed080b92ffc3f6" - integrity sha512-FtwB1TjCaHLbyAnEEu3gBdcnh/hhpC+j0dII5bOqp4YvmkGkXfgQcjZskZFX7GydMcRAjWX35s0VRjuBBZu/fA== +"@sentry/react@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.77.0.tgz#9da14e4b21eae4b5a6306d39bb7c42ef0827d2c2" + integrity sha512-Q+htKzib5em0MdaQZMmPomaswaU3xhcVqmLi2CxqQypSjbYgBPPd+DuhrXKoWYLDDkkbY2uyfe4Lp3yLRWeXYw== dependencies: - "@sentry/browser" "7.76.0" - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" + "@sentry/browser" "7.77.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" hoist-non-react-statics "^3.3.2" -"@sentry/replay@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.76.0.tgz#bccf9ea4a6efc332a79d6a78f923697b9b283371" - integrity sha512-OACT7MfMHC/YGKnKST8SF1d6znr3Yu8fpUpfVVh2t9TNeh3+cQJVTOliHDqLy+k9Ljd5FtitgSn4IHtseCHDLQ== +"@sentry/replay@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.77.0.tgz#21d242c9cd70a7235237216174873fd140b6eb80" + integrity sha512-M9Ik2J5ekl+C1Och3wzLRZVaRGK33BlnBwfwf3qKjgLDwfKW+1YkwDfTHbc2b74RowkJbOVNcp4m8ptlehlSaQ== dependencies: - "@sentry-internal/tracing" "7.76.0" - "@sentry/core" "7.76.0" - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" + "@sentry-internal/tracing" "7.77.0" + "@sentry/core" "7.77.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" -"@sentry/types@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.76.0.tgz#628c9899bfa82ea762708314c50fd82f2138587d" - integrity sha512-vj6z+EAbVrKAXmJPxSv/clpwS9QjPqzkraMFk2hIdE/kii8s8kwnkBwTSpIrNc8GnzV3qYC4r3qD+BXDxAGPaw== +"@sentry/types@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.77.0.tgz#c5d00fe547b89ccde59cdea59143bf145cee3144" + integrity sha512-nfb00XRJVi0QpDHg+JkqrmEBHsqBnxJu191Ded+Cs1OJ5oPXEW6F59LVcBScGvMqe+WEk1a73eH8XezwfgrTsA== -"@sentry/utils@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.76.0.tgz#6b540b387d3ac539abd20978f4d3ae235114f6ab" - integrity sha512-40jFD+yfQaKpFYINghdhovzec4IEpB7aAuyH/GtE7E0gLpcqnC72r55krEIVILfqIR2Mlr5OKUzyeoCyWAU/yw== +"@sentry/utils@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.77.0.tgz#1f88501f0b8777de31b371cf859d13c82ebe1379" + integrity sha512-NmM2kDOqVchrey3N5WSzdQoCsyDkQkiRxExPaNI2oKQ/jMWHs9yt0tSy7otPBcXs0AP59ihl75Bvm1tDRcsp5g== dependencies: - "@sentry/types" "7.76.0" + "@sentry/types" "7.77.0" -"@sentry/vercel-edge@7.76.0": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-7.76.0.tgz#8986d4b7cb1f1dcf0ed6e5f34d5b9ce441f707dc" - integrity sha512-CU/besmv2SWNfVh4v7yVs1VknxU4aG7+kIW001wTYnaNXF8IjV8Bgyn0lDRxFuBXRcrTn8KJO/rUN7aJEmeg4Q== +"@sentry/vercel-edge@7.77.0": + version "7.77.0" + resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-7.77.0.tgz#6a90a869878e4e78803c4331c30aea841fcc6a73" + integrity sha512-ffddPCgxVeAccPYuH5sooZeHBqDuJ9OIhIRYKoDi4TvmwAzWo58zzZWhRpkHqHgIQdQvhLVZ5F+FSQVWnYSOkw== dependencies: - "@sentry/core" "7.76.0" - "@sentry/types" "7.76.0" - "@sentry/utils" "7.76.0" + "@sentry/core" "7.77.0" + "@sentry/types" "7.77.0" + "@sentry/utils" "7.77.0" "@sentry/webpack-plugin@1.20.0": version "1.20.0" @@ -2707,9 +2707,9 @@ integrity sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ== "@types/node@*", "@types/node@^20.5.2": - version "20.8.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.9.tgz#646390b4fab269abce59c308fc286dcd818a2b08" - integrity sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg== + version "20.8.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.10.tgz#a5448b895c753ae929c26ce85cab557c6d4a365e" + integrity sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w== dependencies: undici-types "~5.26.4" @@ -2748,7 +2748,7 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.1.tgz#27f7559836ad796cea31acb63163b203756a5b4e" integrity sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng== -"@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.8": +"@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.9": version "15.7.9" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d" integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g== @@ -2809,7 +2809,7 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-transition-group@^4.4.7": +"@types/react-transition-group@^4.4.8": version "4.4.8" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.8.tgz#46f87d80512959cac793ecc610a93d80ef241ccf" integrity sha512-QmQ22q+Pb+HQSn04NL3HtrqHwYMf4h3QKArOy5F8U5nEVMaihBs3SR10WiOM1iwPz5jIo8x/u11al+iEGZZrvg== @@ -3081,7 +3081,7 @@ aria-hidden@^1.1.1: dependencies: tslib "^2.0.0" -aria-query@^5.1.3: +aria-query@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== @@ -3179,10 +3179,10 @@ arraybuffer.prototype.slice@^1.0.2: is-array-buffer "^3.0.2" is-shared-array-buffer "^1.0.2" -ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== astral-regex@^2.0.0: version "2.0.0" @@ -3233,10 +3233,10 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -axe-core@^4.6.2: - version "4.8.2" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae" - integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g== +axe-core@=4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" + integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== axios@^1.1.3, axios@^1.3.4: version "1.6.0" @@ -3247,7 +3247,7 @@ axios@^1.1.3, axios@^1.3.4: form-data "^4.0.0" proxy-from-env "^1.1.0" -axobject-query@^3.1.1: +axobject-query@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== @@ -3433,9 +3433,9 @@ camelcase-css@^2.0.1: integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001558" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001558.tgz#d2c6e21fdbfe83817f70feab902421a19b7983ee" - integrity sha512-/Et7DwLqpjS47JPEcz6VnxU9PwcIdVi0ciLXRWBQdj1XFye68pSQYpV0QtPTfUKWuOaEig+/Vez2l74eDc1tPQ== + version "1.0.30001559" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz#95a982440d3d314c471db68d02664fb7536c5a30" + integrity sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA== capital-case@^1.0.4: version "1.0.4" @@ -4032,9 +4032,9 @@ ejs@^3.1.6: jake "^10.8.5" electron-to-chromium@^1.4.535: - version "1.4.571" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.571.tgz#8aa71539eb82db98740c3ec861256cc34e0356fd" - integrity sha512-Sc+VtKwKCDj3f/kLBjdyjMpNzoZsU6WuL/wFb6EH8USmHEcebxRXcRrVpOpayxd52tuey4RUDpUsw5OS5LhJqg== + version "1.4.575" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.575.tgz#7c0b87eb2c6214a993699792abd704de41255c39" + integrity sha512-kY2BGyvgAHiX899oF6xLXSIf99bAvvdPhDoJwG77nxCSyWYuRH6e9a9a3gpXBvCs6lj4dQZJkfnW2hdKWHEISg== emoji-regex@^8.0.0: version "8.0.0" @@ -4131,7 +4131,7 @@ es-abstract@^1.22.1: unbox-primitive "^1.0.2" which-typed-array "^1.1.13" -es-iterator-helpers@^1.0.12: +es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== @@ -4482,26 +4482,26 @@ eslint-plugin-import@^2.26.0: tsconfig-paths "^3.14.2" eslint-plugin-jsx-a11y@^6.5.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" - integrity sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA== + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" + integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== dependencies: - "@babel/runtime" "^7.20.7" - aria-query "^5.1.3" - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - ast-types-flow "^0.0.7" - axe-core "^4.6.2" - axobject-query "^3.1.1" + "@babel/runtime" "^7.23.2" + aria-query "^5.3.0" + array-includes "^3.1.7" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "=4.7.0" + axobject-query "^3.2.1" damerau-levenshtein "^1.0.8" emoji-regex "^9.2.2" - has "^1.0.3" - jsx-ast-utils "^3.3.3" - language-tags "=1.0.5" + es-iterator-helpers "^1.0.15" + hasown "^2.0.0" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - semver "^6.3.0" + object.entries "^1.1.7" + object.fromentries "^2.0.7" eslint-plugin-react-hooks@^4.5.0: version "4.6.0" @@ -5313,11 +5313,6 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" - integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== - hasown@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" @@ -5874,7 +5869,7 @@ jsonpointer@^5.0.0: resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== @@ -5911,17 +5906,17 @@ kleur@^4.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== -language-subtag-registry@~0.3.2: +language-subtag-registry@^0.3.20: version "0.3.22" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== -language-tags@=1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== dependencies: - language-subtag-registry "~0.3.2" + language-subtag-registry "^0.3.20" leven@^3.1.0: version "3.1.0" @@ -6680,7 +6675,7 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.5, object.entries@^1.1.6: +object.entries@^1.1.5, object.entries@^1.1.6, object.entries@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== @@ -7076,9 +7071,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.3.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.3.0.tgz#ba4a06ec6b4e1e90577df9931286953cdf4282c3" - integrity sha512-gVNZ74nqhRMiIUYWGQdosYetaKc83x8oT41a0LlV3AAFCAZwCpg4vmGkq8t34+cUhp3cnM4XDiU/7xlgK7HGrg== + version "6.4.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.4.0.tgz#6bc4c618b0c2d68b3bb8b552cbb97f8e300a0f82" + integrity sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ== prosemirror-changeset@^2.2.0: version "2.2.1" @@ -7226,9 +7221,9 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor prosemirror-model "^1.0.0" prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.28.2, prosemirror-view@^1.31.0: - version "1.32.2" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.32.2.tgz#e55fcf5b55847e3b9d9b7982c9a129ef237e60e1" - integrity sha512-l2RQUGaiDI8SG8ZjWIkjT8yjGmNwdzMFMzQmxv/Kh8Vx+ICnz5R+K0mrOS16rhfjX7n2t4emU0goh7TerQC3mw== + version "1.32.3" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.32.3.tgz#9019151211f685e553f681837435cae4885beece" + integrity sha512-tP7AUTxisM0m3PDxs6vDWgTjgcbFo4fnwg2M/5NHlgMqUJgBNOqSUZETBZKmLD7AxGN3GZ5yqEzQv9r9VCZKrg== dependencies: prosemirror-model "^1.16.0" prosemirror-state "^1.0.0" @@ -8301,9 +8296,9 @@ terser-webpack-plugin@^5.3.3: terser "^5.16.8" terser@^5.0.0, terser@^5.16.8: - version "5.23.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.23.0.tgz#a9c02bc3087d0f5b1cc63bbfb4fe0f7e5dbbde82" - integrity sha512-Iyy83LN0uX9ZZLCX4Qbu5JiHiWjOCTwrmM9InWOzVeM++KNWEsqV4YgN9U9E8AlohQ6Gs42ztczlWOG/lwDAMA== + version "5.24.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.24.0.tgz#4ae50302977bca4831ccc7b4fef63a3c04228364" + integrity sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -8352,9 +8347,9 @@ tippy.js@^6.3.7: "@popperjs/core" "^2.9.0" tiptap-markdown@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/tiptap-markdown/-/tiptap-markdown-0.8.2.tgz#93d42ef6225042d8bfe77861b93450aab184d67b" - integrity sha512-RyfpnH475+FYVh1fCiWF9+wBvA8T6X3PqxZR1MApEewxkoQ5kREQFiVwjZiez9qUQk/Bxu3RerFSJot65V6cbQ== + version "0.8.3" + resolved "https://registry.yarnpkg.com/tiptap-markdown/-/tiptap-markdown-0.8.3.tgz#51e93aad3c603c75a91111494ef4fd04115165fe" + integrity sha512-RULu1OXFTHdTJCHwdUOvDk0nDoH8YdgXulR0f+8XBd/x+SuT+EafdQuEKz2ggFlW1Mvl5niKGT5lAHTeXYFmaw== dependencies: "@types/markdown-it" "^12.2.3" markdown-it "^13.0.1" @@ -8362,9 +8357,9 @@ tiptap-markdown@^0.8.2: prosemirror-markdown "^1.11.1" tlds@^1.238.0: - version "1.244.0" - resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.244.0.tgz#b25468d18c53633706081434a337786f695d7662" - integrity sha512-nkacnxHmN5USM/cpmPx29sc2/AnmvUA9han0tNtAJ9yOhh4bPmZm4dGhyg/isWBIES4a70mjd0Q8FSaof6Vf0g== + version "1.245.0" + resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.245.0.tgz#afd4c0c33be7227f8f2d4578573fc922b839ba84" + integrity sha512-fbSQFQr8f41/e9q9IoKKVv7CUFvvE3TVJo7m0JQJZcf7jOOXRRf9DIP4Uf04aovYGKG686OvtV4ZrNY1bOz3aA== to-fast-properties@^2.0.0: version "2.0.0" @@ -8425,7 +8420,7 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@~2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -8719,9 +8714,9 @@ unist-util-visit@^4.0.0: unist-util-visit-parents "^5.1.1" universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== upath@^1.2.0: version "1.2.0" @@ -9138,9 +9133,9 @@ yaml@^1.10.0, yaml@^1.10.2: integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yaml@^2.1.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.3.tgz#01f6d18ef036446340007db8e016810e5d64aad9" - integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ== + version "2.3.4" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" + integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== yocto-queue@^0.1.0: version "0.1.0"