From cea39c758e8ce1b335fdd7eec7b377b9e071e07d Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:48:57 +0530 Subject: [PATCH 01/17] chore: layout refactor (#2532) * chore: layout refactor * fix: profile auth issue * chore: project setting layout refactor * chore: workspace layout refactor * chore: profile layout refactor * chore: layout import refactor --- web/components/headers/index.ts | 1 + web/components/headers/user-profile.tsx | 25 + web/components/profile/navbar.tsx | 9 +- web/layouts/app-layout-legacy/app-header.tsx | 75 --- web/layouts/app-layout-legacy/app-sidebar.tsx | 43 -- web/layouts/app-layout-legacy/layout.tsx | 1 - web/layouts/auth-layout-legacy/index.ts | 3 - .../project-authorization-wrapper.tsx | 122 ----- .../user-authorization-wrapper.tsx | 42 -- .../workspace-authorization-wrapper.tsx | 123 ----- web/layouts/profile-layout.tsx | 49 -- web/layouts/profile-layout/index.ts | 1 + web/layouts/profile-layout/layout.tsx | 44 ++ web/layouts/setting-layout/index.ts | 2 + .../project-setting-layout/layout.tsx | 34 +- .../workspace-setting-layout/layout.tsx | 32 +- web/pages/[workspaceSlug]/me/my-issues.tsx | 123 ----- .../[workspaceSlug]/me/profile/activity.tsx | 289 +++++------ .../[workspaceSlug]/me/profile/index.tsx | 451 +++++++++--------- .../me/profile/preferences.tsx | 45 +- .../profile/[userId]/assigned.tsx | 8 +- .../profile/[userId]/created.tsx | 8 +- .../profile/[userId]/index.tsx | 24 +- .../profile/[userId]/subscribed.tsx | 8 +- .../[projectId]/settings/automations.tsx | 23 +- .../[projectId]/settings/estimates.tsx | 28 +- .../[projectId]/settings/features.tsx | 93 ++-- .../projects/[projectId]/settings/index.tsx | 53 +- .../[projectId]/settings/integrations.tsx | 71 +-- .../projects/[projectId]/settings/labels.tsx | 149 +++--- .../projects/[projectId]/settings/members.tsx | 444 ++++++++--------- .../projects/[projectId]/settings/states.tsx | 143 +++--- .../[workspaceSlug]/settings/billing.tsx | 37 +- .../[workspaceSlug]/settings/exports.tsx | 22 +- .../[workspaceSlug]/settings/imports.tsx | 21 +- web/pages/[workspaceSlug]/settings/index.tsx | 393 +++++++-------- .../[workspaceSlug]/settings/integrations.tsx | 39 +- .../[workspaceSlug]/settings/members.tsx | 409 ++++++++-------- .../workspace-views/issues.tsx | 39 -- 39 files changed, 1496 insertions(+), 2030 deletions(-) create mode 100644 web/components/headers/user-profile.tsx delete mode 100644 web/layouts/app-layout-legacy/app-header.tsx delete mode 100644 web/layouts/app-layout-legacy/app-sidebar.tsx delete mode 100644 web/layouts/app-layout-legacy/layout.tsx delete mode 100644 web/layouts/auth-layout-legacy/index.ts delete mode 100644 web/layouts/auth-layout-legacy/project-authorization-wrapper.tsx delete mode 100644 web/layouts/auth-layout-legacy/user-authorization-wrapper.tsx delete mode 100644 web/layouts/auth-layout-legacy/workspace-authorization-wrapper.tsx delete mode 100644 web/layouts/profile-layout.tsx create mode 100644 web/layouts/profile-layout/index.ts create mode 100644 web/layouts/profile-layout/layout.tsx create mode 100644 web/layouts/setting-layout/index.ts delete mode 100644 web/pages/[workspaceSlug]/me/my-issues.tsx delete mode 100644 web/pages/[workspaceSlug]/workspace-views/issues.tsx diff --git a/web/components/headers/index.ts b/web/components/headers/index.ts index 0657b5ae3..1a52dd4de 100644 --- a/web/components/headers/index.ts +++ b/web/components/headers/index.ts @@ -18,3 +18,4 @@ export * from "./project-draft-issues"; export * from "./project-archived-issue-details"; export * from "./project-archived-issues"; export * from "./project-issue-details"; +export * from "./user-profile"; diff --git a/web/components/headers/user-profile.tsx b/web/components/headers/user-profile.tsx new file mode 100644 index 000000000..870aa1b54 --- /dev/null +++ b/web/components/headers/user-profile.tsx @@ -0,0 +1,25 @@ +import { FC } from "react"; + +import { useRouter } from "next/router"; + +// ui +import { BreadcrumbItem, Breadcrumbs } from "@plane/ui"; +// hooks +import { observer } from "mobx-react-lite"; + +export const UserProfileHeader: FC = observer(() => { + const router = useRouter(); + return ( +
+
+
+ router.back()}> + + +
+
+
+ ); +}); diff --git a/web/components/profile/navbar.tsx b/web/components/profile/navbar.tsx index cd43cc974..433452536 100644 --- a/web/components/profile/navbar.tsx +++ b/web/components/profile/navbar.tsx @@ -5,11 +5,9 @@ import Link from "next/link"; // components import { ProfileIssuesFilter } from "components/profile"; -// types -import { UserAuth } from "types"; type Props = { - memberRole: UserAuth; + isAuthorized: boolean; }; const viewerTabs = [ @@ -38,12 +36,11 @@ const adminTabs = [ }, ]; -export const ProfileNavbar: React.FC = ({ memberRole }) => { +export const ProfileNavbar: React.FC = ({ isAuthorized }) => { const router = useRouter(); const { workspaceSlug, userId } = router.query; - const tabsList = - memberRole.isOwner || memberRole.isMember || memberRole.isViewer ? [...viewerTabs, ...adminTabs] : viewerTabs; + const tabsList = isAuthorized ? [...viewerTabs, ...adminTabs] : viewerTabs; return (
diff --git a/web/layouts/app-layout-legacy/app-header.tsx b/web/layouts/app-layout-legacy/app-header.tsx deleted file mode 100644 index f9ae83497..000000000 --- a/web/layouts/app-layout-legacy/app-header.tsx +++ /dev/null @@ -1,75 +0,0 @@ -// next imports -import { useRouter } from "next/router"; -import Link from "next/link"; -// icons -import { Menu } from "lucide-react"; -// ui components -import { Tooltip } from "@plane/ui"; -// hooks -import useProjectDetails from "hooks/use-project-details"; - -type Props = { - breadcrumbs?: JSX.Element; - left?: JSX.Element; - right?: JSX.Element; - setToggleSidebar: React.Dispatch>; - noHeader: boolean; -}; - -const { NEXT_PUBLIC_DEPLOY_URL } = process.env; -let plane_deploy_url = NEXT_PUBLIC_DEPLOY_URL; - -if (typeof window !== "undefined" && !plane_deploy_url) { - plane_deploy_url = window.location.protocol + "//" + window.location.host + "/spaces"; -} - -const Header: React.FC = ({ breadcrumbs, left, right, setToggleSidebar, noHeader }) => { - const { projectDetails } = useProjectDetails(); - - const router = useRouter(); - const { workspaceSlug, projectId } = router.query; - - return ( -
-
-
- -
-
{breadcrumbs}
- - {projectDetails && projectDetails?.is_deployed && ( - - - -
-
- radio_button_checked -
-
Public
-
- open_in_new -
-
-
-
- - )} - -
{left}
-
-
{right}
-
- ); -}; - -export default Header; diff --git a/web/layouts/app-layout-legacy/app-sidebar.tsx b/web/layouts/app-layout-legacy/app-sidebar.tsx deleted file mode 100644 index 1db9dc983..000000000 --- a/web/layouts/app-layout-legacy/app-sidebar.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import dynamic from "next/dynamic"; -// components -import { WorkspaceHelpSection, WorkspaceSidebarDropdown, WorkspaceSidebarMenu } from "components/workspace"; - -const WorkspaceSidebarQuickAction = dynamic<{}>( - () => import("components/workspace/sidebar-quick-action").then((mod) => mod.WorkspaceSidebarQuickAction), - { - ssr: false, - } -); - -import { ProjectSidebarList } from "components/project"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; -import { observer } from "mobx-react-lite"; - -export interface SidebarProps { - toggleSidebar: boolean; - setToggleSidebar: React.Dispatch>; -} - -const Sidebar: React.FC = observer(({ toggleSidebar, setToggleSidebar }) => { - const { theme: themeStore } = useMobxStore(); - - return ( -
-
- - - - - -
-
- ); -}); - -export default Sidebar; diff --git a/web/layouts/app-layout-legacy/layout.tsx b/web/layouts/app-layout-legacy/layout.tsx deleted file mode 100644 index 90eef899c..000000000 --- a/web/layouts/app-layout-legacy/layout.tsx +++ /dev/null @@ -1 +0,0 @@ -export const AppLayoutLegacy = () => <>; diff --git a/web/layouts/auth-layout-legacy/index.ts b/web/layouts/auth-layout-legacy/index.ts deleted file mode 100644 index 608e96606..000000000 --- a/web/layouts/auth-layout-legacy/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./project-authorization-wrapper"; -export * from "./workspace-authorization-wrapper"; -export * from "./user-authorization-wrapper"; diff --git a/web/layouts/auth-layout-legacy/project-authorization-wrapper.tsx b/web/layouts/auth-layout-legacy/project-authorization-wrapper.tsx deleted file mode 100644 index 69f33b509..000000000 --- a/web/layouts/auth-layout-legacy/project-authorization-wrapper.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import { useState } from "react"; - -import Link from "next/link"; -import { useRouter } from "next/router"; - -// contexts -import { useProjectMyMembership, ProjectMemberProvider } from "contexts/project-member.context"; -// layouts -import AppHeader from "layouts/app-layout-legacy/app-header"; -import AppSidebar from "layouts/app-layout-legacy/app-sidebar"; -// components -import { NotAuthorizedView, JoinProject } from "components/auth-screens"; -import { CommandPalette } from "components/command-palette"; -// ui -import { Button, LayersIcon, Spinner } from "@plane/ui"; -import { EmptyState } from "components/common"; -// images -import emptyProject from "public/empty-state/project.svg"; - -type Props = { - children: React.ReactNode; - noHeader?: boolean; - bg?: "primary" | "secondary"; - breadcrumbs?: JSX.Element; - left?: JSX.Element; - right?: JSX.Element; -}; - -export const ProjectAuthorizationWrapper: React.FC = (props) => ( - - - -); - -const ProjectAuthorizationWrapped: React.FC = ({ - children, - noHeader = false, - bg = "primary", - breadcrumbs, - left, - right, -}) => { - const [toggleSidebar, setToggleSidebar] = useState(false); - - const router = useRouter(); - const { workspaceSlug, projectId } = router.query; - - const { loading, error, memberRole: memberType } = useProjectMyMembership(); - - const settingsLayout = router.pathname.includes("/settings"); - - return ( - <> - -
- - - {loading ? ( -
-
-

Loading your project...

- -
-
- ) : error?.status === 401 || error?.status === 403 ? ( - - ) : error?.status === 404 ? ( -
- { - const e = new KeyboardEvent("keydown", { - key: "p", - }); - document.dispatchEvent(e); - }, - }} - /> -
- ) : settingsLayout && (memberType?.isGuest || memberType?.isViewer) ? ( - - - - - - } - type="project" - /> - ) : ( -
- -
-
{children}
-
-
- )} -
- - ); -}; diff --git a/web/layouts/auth-layout-legacy/user-authorization-wrapper.tsx b/web/layouts/auth-layout-legacy/user-authorization-wrapper.tsx deleted file mode 100644 index 33e414e28..000000000 --- a/web/layouts/auth-layout-legacy/user-authorization-wrapper.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useRouter } from "next/router"; - -import useSWR from "swr"; - -// services -import { UserService } from "services/user.service"; -// ui -import { Spinner } from "@plane/ui"; -// fetch-keys -import { CURRENT_USER } from "constants/fetch-keys"; - -type Props = { - children: React.ReactNode; -}; - -// services -const userService = new UserService(); - -export const UserAuthorizationLayout: React.FC = ({ children }) => { - const router = useRouter(); - - const { data: currentUser, error } = useSWR(CURRENT_USER, () => userService.currentUser()); - - if (!currentUser && !error) { - return ( -
-
- -
-
- ); - } - - if (error) { - const redirectTo = router.asPath; - - router.push(`/?next=${redirectTo}`); - return null; - } - - return <>{children}; -}; diff --git a/web/layouts/auth-layout-legacy/workspace-authorization-wrapper.tsx b/web/layouts/auth-layout-legacy/workspace-authorization-wrapper.tsx deleted file mode 100644 index 0f8b7a3d4..000000000 --- a/web/layouts/auth-layout-legacy/workspace-authorization-wrapper.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { useState } from "react"; -import Link from "next/link"; -import { useRouter } from "next/router"; -import useSWR from "swr"; -// services -import { WorkspaceService } from "services/workspace.service"; -// contexts -import { WorkspaceMemberProvider } from "contexts/workspace-member.context"; -// layouts -import AppSidebar from "layouts/app-layout-legacy/app-sidebar"; -import AppHeader from "layouts/app-layout-legacy/app-header"; -import { UserAuthorizationLayout } from "./user-authorization-wrapper"; -// components -import { Button, LayersIcon, Spinner } from "@plane/ui"; -import { NotAuthorizedView, NotAWorkspaceMember } from "components/auth-screens"; -import { CommandPalette } from "components/command-palette"; -// fetch-keys -import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys"; - -type Props = { - children: React.ReactNode; - noHeader?: boolean; - bg?: "primary" | "secondary"; - breadcrumbs?: JSX.Element; - left?: JSX.Element; - right?: JSX.Element; -}; - -const workspaceService = new WorkspaceService(); - -export const WorkspaceAuthorizationLayout: React.FC = ({ - children, - noHeader = false, - bg = "primary", - breadcrumbs, - left, - right, -}) => { - const [toggleSidebar, setToggleSidebar] = useState(false); - - const router = useRouter(); - const { workspaceSlug } = router.query; - - const { data: workspaceMemberMe, error } = useSWR( - workspaceSlug ? WORKSPACE_MEMBERS_ME(workspaceSlug as string) : null, - workspaceSlug ? () => workspaceService.workspaceMemberMe(workspaceSlug.toString()) : null - ); - - if (!workspaceMemberMe && !error) - return ( -
-
-

Loading your workspace...

- -
-
- ); - - if (error?.status === 401 || error?.status === 403) return ; - - // FIXME: show 404 for workspace not workspace member - if (error?.status === 404) { - return ( -
-

No such workspace exists. Create one?

-
- ); - } - - const settingsLayout = router.pathname.includes("/settings"); - const memberType = { - isOwner: workspaceMemberMe?.role === 20, - isMember: workspaceMemberMe?.role === 15, - isViewer: workspaceMemberMe?.role === 10, - isGuest: workspaceMemberMe?.role === 5, - }; - - return ( - - - -
- - {settingsLayout && (memberType?.isGuest || memberType?.isViewer) ? ( - - - - - - } - type="workspace" - /> - ) : ( -
- -
-
{children}
-
-
- )} -
-
-
- ); -}; diff --git a/web/layouts/profile-layout.tsx b/web/layouts/profile-layout.tsx deleted file mode 100644 index e7ee873a5..000000000 --- a/web/layouts/profile-layout.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { useRouter } from "next/router"; -// hooks -import { useWorkspaceMyMembership } from "contexts/workspace-member.context"; -// layouts -import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy"; -// components -import { ProfileNavbar, ProfileSidebar } from "components/profile"; -// ui -import { Breadcrumbs, BreadcrumbItem } from "@plane/ui"; - -type Props = { - children: React.ReactNode; - className?: string; -}; - -export const ProfileAuthWrapper = (props: Props) => { - const router = useRouter(); - return ( - router.back()}> - - - } - > - - - ); -}; - -const ProfileLayout: React.FC = ({ children, className }) => { - const { memberRole } = useWorkspaceMyMembership(); - - return ( -
- -
- - {memberRole.isOwner || memberRole.isMember || memberRole.isViewer ? ( -
{children}
- ) : ( -
- You do not have the permission to access this page. -
- )} -
-
- ); -}; diff --git a/web/layouts/profile-layout/index.ts b/web/layouts/profile-layout/index.ts new file mode 100644 index 000000000..eec9d1e67 --- /dev/null +++ b/web/layouts/profile-layout/index.ts @@ -0,0 +1 @@ +export * from "./layout"; diff --git a/web/layouts/profile-layout/layout.tsx b/web/layouts/profile-layout/layout.tsx new file mode 100644 index 000000000..c7e379167 --- /dev/null +++ b/web/layouts/profile-layout/layout.tsx @@ -0,0 +1,44 @@ +import useSWR from "swr"; +import { useRouter } from "next/router"; +// services +import { WorkspaceService } from "services/workspace.service"; +// components +import { ProfileNavbar, ProfileSidebar } from "components/profile"; +// constants +import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys"; + +type Props = { + children: React.ReactNode; + className?: string; +}; + +// services +const workspaceService = new WorkspaceService(); + +export const ProfileAuthWrapper: React.FC = ({ children, className }) => { + const router = useRouter(); + const { workspaceSlug } = router.query; + + const { data: memberDetails } = useSWR( + workspaceSlug ? WORKSPACE_MEMBERS_ME(workspaceSlug.toString()) : null, + workspaceSlug ? () => workspaceService.workspaceMemberMe(workspaceSlug.toString()) : null + ); + + const isAuthorized = memberDetails?.role === 20 || memberDetails?.role === 15 || memberDetails?.role === 10; + + return ( +
+ +
+ + {isAuthorized ? ( +
{children}
+ ) : ( +
+ You do not have the permission to access this page. +
+ )} +
+
+ ); +}; diff --git a/web/layouts/setting-layout/index.ts b/web/layouts/setting-layout/index.ts new file mode 100644 index 000000000..32a12e160 --- /dev/null +++ b/web/layouts/setting-layout/index.ts @@ -0,0 +1,2 @@ +export * from "./project-setting-layout"; +export * from "./workspace-setting-layout"; diff --git a/web/layouts/setting-layout/project-setting-layout/layout.tsx b/web/layouts/setting-layout/project-setting-layout/layout.tsx index b34f599ae..7a0bee0eb 100644 --- a/web/layouts/setting-layout/project-setting-layout/layout.tsx +++ b/web/layouts/setting-layout/project-setting-layout/layout.tsx @@ -1,40 +1,20 @@ import { FC, ReactNode } from "react"; -// layouts -import { UserAuthWrapper, ProjectAuthWrapper, WorkspaceAuthWrapper } from "layouts/auth-layout"; // components -import { AppSidebar } from "layouts/app-layout"; import { ProjectSettingsSidebar } from "./sidebar"; export interface IProjectSettingLayout { children: ReactNode; - header: ReactNode; } export const ProjectSettingLayout: FC = (props) => { - const { children, header } = props; + const { children } = props; return ( - <> - - - -
- -
- {header} -
-
-
- -
- {children} -
-
-
-
-
-
-
- +
+
+ +
+ {children} +
); }; diff --git a/web/layouts/setting-layout/workspace-setting-layout/layout.tsx b/web/layouts/setting-layout/workspace-setting-layout/layout.tsx index 74c09b05f..a584c26c1 100644 --- a/web/layouts/setting-layout/workspace-setting-layout/layout.tsx +++ b/web/layouts/setting-layout/workspace-setting-layout/layout.tsx @@ -1,38 +1,20 @@ import { FC, ReactNode } from "react"; -// layouts -import { UserAuthWrapper, WorkspaceAuthWrapper } from "layouts/auth-layout"; // components -import { AppSidebar } from "layouts/app-layout"; import { WorkspaceSettingsSidebar } from "./sidebar"; export interface IWorkspaceSettingLayout { children: ReactNode; - header: ReactNode; } export const WorkspaceSettingLayout: FC = (props) => { - const { children, header } = props; + const { children } = props; return ( - <> - - -
- -
- {header} -
-
-
- -
- {children} -
-
-
-
-
-
- +
+
+ +
+ {children} +
); }; diff --git a/web/pages/[workspaceSlug]/me/my-issues.tsx b/web/pages/[workspaceSlug]/me/my-issues.tsx deleted file mode 100644 index 09036471f..000000000 --- a/web/pages/[workspaceSlug]/me/my-issues.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import React, { useEffect } from "react"; - -import { useRouter } from "next/router"; - -// icons -import { Plus } from "lucide-react"; -// layouts -import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy"; -// hooks -import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter"; -// components -import { MyIssuesView, MyIssuesViewOptions } from "components/issues"; -// ui -import { Breadcrumbs, BreadcrumbItem, Button } from "@plane/ui"; -// types -import type { NextPage } from "next"; -import useUser from "hooks/use-user"; - -const MyIssuesPage: NextPage = () => { - const router = useRouter(); - const { workspaceSlug } = router.query; - - const { user } = useUser(); - - const { filters, setFilters } = useMyIssuesFilters(workspaceSlug?.toString()); - - const tabsList = [ - { - key: "assigned", - label: "Assigned", - selected: (filters?.assignees ?? []).length > 0, - onClick: () => { - setFilters({ - assignees: [user?.id ?? ""], - created_by: null, - subscriber: null, - }); - }, - }, - { - key: "created", - label: "Created", - selected: (filters?.created_by ?? []).length > 0, - onClick: () => { - setFilters({ - assignees: null, - created_by: [user?.id ?? ""], - subscriber: null, - }); - }, - }, - { - key: "subscribed", - label: "Subscribed", - selected: (filters?.subscriber ?? []).length > 0, - onClick: () => { - setFilters({ - assignees: null, - created_by: null, - subscriber: [user?.id ?? ""], - }); - }, - }, - ]; - - useEffect(() => { - if (!filters || !user) return; - - if (!filters.assignees && !filters.created_by && !filters.subscriber) { - setFilters({ - assignees: [user.id], - }); - return; - } - }, [filters, setFilters, user]); - - return ( - router.back()}> - - - } - right={ -
- - -
- } - > -
-
-
- {tabsList.map((tab) => ( - - ))} -
-
- -
-
- ); -}; - -export default MyIssuesPage; diff --git a/web/pages/[workspaceSlug]/me/profile/activity.tsx b/web/pages/[workspaceSlug]/me/profile/activity.tsx index 5298da83f..85117d975 100644 --- a/web/pages/[workspaceSlug]/me/profile/activity.tsx +++ b/web/pages/[workspaceSlug]/me/profile/activity.tsx @@ -4,7 +4,8 @@ import Link from "next/link"; // services import { UserService } from "services/user.service"; // layouts -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; +import { AppLayout } from "layouts/app-layout"; // components import { ActivityIcon, ActivityMessage } from "components/core"; import { RichReadOnlyEditor } from "@plane/rich-text-editor"; @@ -30,160 +31,164 @@ const ProfileActivity = () => { ); return ( - }> - {userActivity ? ( -
-
-

Activity

-
-
-
    - {userActivity.results.map((activityItem: any) => { - if (activityItem.field === "comment") { - return ( -
    -
    -
    - {activityItem.field ? ( - activityItem.new_value === "restore" && ( - - ) - ) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? ( - {activityItem.actor_detail.display_name} - ) : ( -
    - {activityItem.actor_detail.display_name?.charAt(0)} -
    - )} + }> + + {userActivity ? ( +
    +
    +

    Activity

    +
    +
    +
      + {userActivity.results.map((activityItem: any) => { + if (activityItem.field === "comment") { + return ( +
      +
      +
      + {activityItem.field ? ( + activityItem.new_value === "restore" && ( + + ) + ) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? ( + {activityItem.actor_detail.display_name} + ) : ( +
      + {activityItem.actor_detail.display_name?.charAt(0)} +
      + )} - - -
      -
      -
      -
      - {activityItem.actor_detail.is_bot - ? activityItem.actor_detail.first_name + " Bot" - : activityItem.actor_detail.display_name} -
      -

      - Commented {timeAgo(activityItem.created_at)} -

      + +
      -
      - +
      +
      +
      + {activityItem.actor_detail.is_bot + ? activityItem.actor_detail.first_name + " Bot" + : activityItem.actor_detail.display_name} +
      +

      + Commented {timeAgo(activityItem.created_at)} +

      +
      +
      + +
      -
      - ); - } + ); + } - const message = - activityItem.verb === "created" && - activityItem.field !== "cycles" && - activityItem.field !== "modules" && - activityItem.field !== "attachment" && - activityItem.field !== "link" && - activityItem.field !== "estimate" ? ( - - created{" "} - - - this issue. - - - - ) : activityItem.field ? ( - - ) : ( - "created the issue." - ); + const message = + activityItem.verb === "created" && + activityItem.field !== "cycles" && + activityItem.field !== "modules" && + activityItem.field !== "attachment" && + activityItem.field !== "link" && + activityItem.field !== "estimate" ? ( + + created{" "} + + + this issue. + + + + ) : activityItem.field ? ( + + ) : ( + "created the issue." + ); - if ("field" in activityItem && activityItem.field !== "updated_by") { - return ( -
    • -
      -
      - <> -
      -
      -
      -
      - {activityItem.field ? ( - activityItem.new_value === "restore" ? ( - + if ("field" in activityItem && activityItem.field !== "updated_by") { + return ( +
    • +
      +
      + <> +
      +
      +
      +
      + {activityItem.field ? ( + activityItem.new_value === "restore" ? ( + + ) : ( + + ) + ) : activityItem.actor_detail.avatar && + activityItem.actor_detail.avatar !== "" ? ( + {activityItem.actor_detail.display_name} ) : ( - - ) - ) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? ( - {activityItem.actor_detail.display_name} - ) : ( -
      - {activityItem.actor_detail.display_name?.charAt(0)} -
      - )} +
      + {activityItem.actor_detail.display_name?.charAt(0)} +
      + )} +
      -
      -
      -
      - {activityItem.field === "archived_at" && activityItem.new_value !== "restore" ? ( - Plane - ) : activityItem.actor_detail.is_bot ? ( - - {activityItem.actor_detail.first_name} Bot - - ) : ( - - {activityItem.actor_detail.display_name} - - )}{" "} - {message} {timeAgo(activityItem.created_at)} +
      +
      + {activityItem.field === "archived_at" && activityItem.new_value !== "restore" ? ( + Plane + ) : activityItem.actor_detail.is_bot ? ( + + {activityItem.actor_detail.first_name} Bot + + ) : ( + + {activityItem.actor_detail.display_name} + + )}{" "} + {message}{" "} + {timeAgo(activityItem.created_at)} +
      -
      - + +
      -
    • - - ); - } - })} -
    -
    -
    - ) : ( - - - - - - - )} -
    + + ); + } + })} +
+
+
+ ) : ( + + + + + + + )} +
+ ); }; diff --git a/web/pages/[workspaceSlug]/me/profile/index.tsx b/web/pages/[workspaceSlug]/me/profile/index.tsx index 9e2e16570..ffcfdcdee 100644 --- a/web/pages/[workspaceSlug]/me/profile/index.tsx +++ b/web/pages/[workspaceSlug]/me/profile/index.tsx @@ -9,7 +9,8 @@ import { UserService } from "services/user.service"; import useUserAuth from "hooks/use-user-auth"; import useToast from "hooks/use-toast"; // layouts -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; // components import { ImagePickerPopover, ImageUploadModal } from "components/core"; import { WorkspaceSettingHeader } from "components/headers"; @@ -143,252 +144,254 @@ const Profile: NextPage = () => { })); return ( - }> - setIsImageUploadModalOpen(false)} - isRemoving={isRemoving} - handleDelete={() => handleDelete(myProfile?.avatar, true)} - onSuccess={(url) => { - setValue("avatar", url); - handleSubmit(onSubmit)(); - setIsImageUploadModalOpen(false); - }} - value={watch("avatar") !== "" ? watch("avatar") : undefined} - userImage - /> - {myProfile ? ( -
-
-
- {myProfile?.first_name -
-
-
- + }> + + setIsImageUploadModalOpen(false)} + isRemoving={isRemoving} + handleDelete={() => handleDelete(myProfile?.avatar, true)} + onSuccess={(url) => { + setValue("avatar", url); + handleSubmit(onSubmit)(); + setIsImageUploadModalOpen(false); + }} + value={watch("avatar") !== "" ? watch("avatar") : undefined} + userImage + /> + {myProfile ? ( + +
+
+ {myProfile?.first_name +
+
+
+ +
-
-
- ( - { - setValue("cover_image", imageUrl); - }} - control={control} - value={watch("cover_image") ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"} - /> - )} - /> -
-
- -
-
-
- {`${watch("first_name")} ${watch("last_name")}`} +
+ ( + { + setValue("cover_image", imageUrl); + }} + control={control} + value={watch("cover_image") ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"} + /> + )} + />
- {watch("email")}
- - - - - - View Profile - - -
+
+
+
+ {`${watch("first_name")} ${watch("last_name")}`} +
+ {watch("email")} +
-
-
-

First Name

- ( - - )} - /> + + + + + + View Profile + +
-
-

Last Name

+
+
+

First Name

+ ( + + )} + /> +
- ( - - )} - /> -
+
+

Last Name

-
-

Email

- ( - - )} - /> -
+ ( + + )} + /> +
-
-

Role

- ( - - {USER_ROLES.map((item) => ( - - {item.label} - - ))} - - )} - /> - {errors.role && Please select a role} -
+
+

Email

+ ( + + )} + /> +
-
-

Display name

- { - if (value.trim().length < 1) return "Display name can't be empty."; +
+

Role

+ ( + + {USER_ROLES.map((item) => ( + + {item.label} + + ))} + + )} + /> + {errors.role && Please select a role} +
- if (value.split(" ").length > 1) return "Display name can't have two consecutive spaces."; +
+

Display name

+ { + if (value.trim().length < 1) return "Display name can't be empty."; - if (value.replace(/\s/g, "").length < 1) - return "Display name must be at least 1 characters long."; + if (value.split(" ").length > 1) return "Display name can't have two consecutive spaces."; - if (value.replace(/\s/g, "").length > 20) - return "Display name must be less than 20 characters long."; + if (value.replace(/\s/g, "").length < 1) + return "Display name must be at least 1 characters long."; - return true; - }, - }} - render={({ field: { value, onChange, ref } }) => ( - - )} - /> -
+ if (value.replace(/\s/g, "").length > 20) + return "Display name must be less than 20 characters long."; -
-

Timezone

+ return true; + }, + }} + render={({ field: { value, onChange, ref } }) => ( + + )} + /> +
- ( - t.value === value)?.label ?? value : "Select a timezone"} - options={timeZoneOptions} - onChange={onChange} - optionsClassName="w-full" - input - /> - )} - /> - {errors.role && Please select a role} -
+
+

Timezone

-
- + ( + t.value === value)?.label ?? value : "Select a timezone"} + options={timeZoneOptions} + onChange={onChange} + optionsClassName="w-full" + input + /> + )} + /> + {errors.role && Please select a role} +
+ +
+ +
+ + ) : ( +
+
- - ) : ( -
- -
- )} - + )} + + ); }; diff --git a/web/pages/[workspaceSlug]/me/profile/preferences.tsx b/web/pages/[workspaceSlug]/me/profile/preferences.tsx index beae8a341..11a19d186 100644 --- a/web/pages/[workspaceSlug]/me/profile/preferences.tsx +++ b/web/pages/[workspaceSlug]/me/profile/preferences.tsx @@ -5,7 +5,8 @@ import { useTheme } from "next-themes"; import { useMobxStore } from "lib/mobx/store-provider"; import useToast from "hooks/use-toast"; // layouts -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; // components import { CustomThemeSelector, ThemeSwitch } from "components/core"; import { WorkspaceSettingHeader } from "components/headers"; @@ -44,29 +45,31 @@ const ProfilePreferencesPage = observer(() => { }; return ( - }> - {userStore.currentUser ? ( -
-
-

Preferences

-
-
-
-

Theme

-

Select or customize your interface color scheme.

+ }> + + {userStore.currentUser ? ( +
+
+

Preferences

-
- +
+
+

Theme

+

Select or customize your interface color scheme.

+
+
+ +
+ {userTheme?.theme === "custom" && }
- {userTheme?.theme === "custom" && } -
- ) : ( -
- -
- )} -
+ ) : ( +
+ +
+ )} + +
); }); diff --git a/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx b/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx index 267679a89..cce7a2b56 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx @@ -3,11 +3,11 @@ import type { NextPage } from "next"; import { useRouter } from "next/router"; import useSWR from "swr"; import { observer } from "mobx-react-lite"; -// contexts -import { ProfileIssuesContextProvider } from "contexts/profile-issues-context"; // layouts +import { AppLayout } from "layouts/app-layout"; import { ProfileAuthWrapper } from "layouts/profile-layout"; // components +import { UserProfileHeader } from "components/headers"; import { ProfileIssuesListLayout } from "components/issues/issue-layouts/list/profile-issues-root"; import { ProfileIssuesKanBanLayout } from "components/issues/issue-layouts/kanban/profile-issues-root"; // hooks @@ -45,7 +45,7 @@ const ProfileAssignedIssues: NextPage = observer(() => { const activeLayout = profileIssueFiltersStore.userDisplayFilters.layout; return ( - + }> {profileIssuesStore.loader ? (
Loading...
@@ -59,7 +59,7 @@ const ProfileAssignedIssues: NextPage = observer(() => {
)} - + ); }); diff --git a/web/pages/[workspaceSlug]/profile/[userId]/created.tsx b/web/pages/[workspaceSlug]/profile/[userId]/created.tsx index 1cac31e62..ad6e89dea 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/created.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/created.tsx @@ -1,20 +1,20 @@ import React from "react"; -// contexts -import { ProfileIssuesContextProvider } from "contexts/profile-issues-context"; // layouts +import { AppLayout } from "layouts/app-layout"; import { ProfileAuthWrapper } from "layouts/profile-layout"; // components +import { UserProfileHeader } from "components/headers"; import { ProfileIssuesView } from "components/profile"; // types import type { NextPage } from "next"; const ProfileCreatedIssues: NextPage = () => ( - + }> - + ); export default ProfileCreatedIssues; diff --git a/web/pages/[workspaceSlug]/profile/[userId]/index.tsx b/web/pages/[workspaceSlug]/profile/[userId]/index.tsx index c674dcf33..eb175b631 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/index.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/index.tsx @@ -7,8 +7,10 @@ import useSWR from "swr"; // services import { UserService } from "services/user.service"; // layouts +import { AppLayout } from "layouts/app-layout"; import { ProfileAuthWrapper } from "layouts/profile-layout"; // components +import { UserProfileHeader } from "components/headers"; import { ProfileActivity, ProfilePriorityDistribution, @@ -43,17 +45,19 @@ const ProfileOverview: NextPage = () => { }); return ( - -
- - -
- - + }> + +
+ + +
+ + +
+
- -
- + + ); }; diff --git a/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx b/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx index 3a1ca01ee..3d3400a80 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx @@ -1,20 +1,20 @@ import React from "react"; -// contexts -import { ProfileIssuesContextProvider } from "contexts/profile-issues-context"; // layouts +import { AppLayout } from "layouts/app-layout"; import { ProfileAuthWrapper } from "layouts/profile-layout"; // components +import { UserProfileHeader } from "components/headers"; import { ProfileIssuesView } from "components/profile"; // types import type { NextPage } from "next"; const ProfileSubscribedIssues: NextPage = () => ( - + }> - + ); export default ProfileSubscribedIssues; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/automations.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/automations.tsx index cc709d598..99a7f01ef 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/automations.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/automations.tsx @@ -7,7 +7,8 @@ import useSWR, { mutate } from "swr"; // services import { ProjectService } from "services/project"; // layouts -import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { ProjectSettingLayout } from "layouts/setting-layout"; // hooks import useUserAuth from "hooks/use-user-auth"; import useProjectDetails from "hooks/use-project-details"; @@ -70,15 +71,17 @@ const AutomationsSettings: NextPage = () => { const isAdmin = memberDetails?.role === 20; return ( - }> -
-
-

Automations

-
- - -
-
+ } withProjectWrapper> + +
+
+

Automations

+
+ + +
+
+
); }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx index 125142cf2..0bfbd04b0 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx @@ -7,7 +7,8 @@ import { ProjectService, ProjectEstimateService } from "services/project"; // hooks import useProjectDetails from "hooks/use-project-details"; // layouts -import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { ProjectSettingLayout } from "layouts/setting-layout"; // components import { CreateUpdateEstimateModal, SingleEstimate } from "components/estimates"; import { ProjectSettingHeader } from "components/headers"; @@ -98,18 +99,17 @@ const EstimatesSettings: NextPage = () => { }; return ( - <> - { - setEstimateFormOpen(false); - setEstimateToUpdate(undefined); - }} - user={user} - /> - - }> + } withProjectWrapper> + + { + setEstimateFormOpen(false); + setEstimateToUpdate(undefined); + }} + user={user} + />

Estimates

@@ -172,7 +172,7 @@ const EstimatesSettings: NextPage = () => { )}
- +
); }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx index 2e232e1b0..41878525c 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx @@ -6,7 +6,8 @@ import useSWR, { mutate } from "swr"; import { ProjectService } from "services/project"; import { TrackEventService, MiscellaneousEventType } from "services/track_event.service"; // layouts -import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { ProjectSettingLayout } from "layouts/setting-layout"; // hooks import useToast from "hooks/use-toast"; import useUserAuth from "hooks/use-user-auth"; @@ -136,52 +137,54 @@ const FeaturesSettings: NextPage = () => { const isAdmin = memberDetails?.role === 20; return ( - }> -
-
-

Features

-
-
- {featuresList.map((feature) => ( -
-
-
- {feature.icon} -
-
-

{feature.title}

-

{feature.description}

+ } withProjectWrapper> + +
+
+

Features

+
+
+ {featuresList.map((feature) => ( +
+
+
+ {feature.icon} +
+
+

{feature.title}

+

{feature.description}

+
+ { + trackEventService.trackMiscellaneousEvent( + { + workspaceId: (projectDetails?.workspace as any)?.id, + workspaceSlug, + projectId, + projectIdentifier: projectDetails?.identifier, + projectName: projectDetails?.name, + }, + getEventType(feature.title, !projectDetails?.[feature.property as keyof IProject]), + user as IUser + ); + handleSubmit({ + [feature.property]: !projectDetails?.[feature.property as keyof IProject], + }); + }} + disabled={!isAdmin} + size="sm" + />
- { - trackEventService.trackMiscellaneousEvent( - { - workspaceId: (projectDetails?.workspace as any)?.id, - workspaceSlug, - projectId, - projectIdentifier: projectDetails?.identifier, - projectName: projectDetails?.name, - }, - getEventType(feature.title, !projectDetails?.[feature.property as keyof IProject]), - user as IUser - ); - handleSubmit({ - [feature.property]: !projectDetails?.[feature.property as keyof IProject], - }); - }} - disabled={!isAdmin} - size="sm" - /> -
- ))} -
-
-
+ ))} +
+ + + ); }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx index 26b3ae90c..b78d44970 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx @@ -3,7 +3,8 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // layouts -import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { ProjectSettingLayout } from "layouts/setting-layout"; // components import { ProjectSettingHeader } from "components/headers"; import { @@ -18,9 +19,6 @@ import type { NextPage } from "next"; import { useMobxStore } from "lib/mobx/store-provider"; import { observer } from "mobx-react-lite"; -// services -// const projectService = new ProjectService(); - const GeneralSettings: NextPage = observer(() => { const { project: projectStore } = useMobxStore(); // states @@ -42,33 +40,34 @@ const GeneralSettings: NextPage = observer(() => { // const selectedNetwork = NETWORK_CHOICES.find((n) => n.key === watch("network")); const isAdmin = projectDetails?.member_role === 20; - console.log("isAdmin", isAdmin); return ( - }> - {projectDetails && ( - setSelectedProject(null)} - /> - )} - -
- {projectDetails && workspaceSlug ? ( - - ) : ( - - )} - - {isAdmin && ( - setSelectedProject(projectDetails.id ?? null)} + } withProjectWrapper> + + {projectDetails && ( + setSelectedProject(null)} /> )} -
-
+ +
+ {projectDetails && workspaceSlug ? ( + + ) : ( + + )} + + {isAdmin && ( + setSelectedProject(projectDetails.id ?? null)} + /> + )} +
+ + ); }); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx index 7daa2cec1..0011ceff8 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx @@ -5,7 +5,8 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // layouts -import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { ProjectSettingLayout } from "layouts/setting-layout"; // services import { IntegrationService } from "services/integrations"; import { ProjectService } from "services/project"; @@ -50,40 +51,42 @@ const ProjectIntegrations: NextPage = () => { const isAdmin = projectDetails?.member_role === 20; return ( - }> -
-
-

Integrations

-
- {workspaceIntegrations ? ( - workspaceIntegrations.length > 0 ? ( -
- {workspaceIntegrations.map((integration) => ( - - ))} -
+ }> + +
+
+

Integrations

+
+ {workspaceIntegrations ? ( + workspaceIntegrations.length > 0 ? ( +
+ {workspaceIntegrations.map((integration) => ( + + ))} +
+ ) : ( + router.push(`/${workspaceSlug}/settings/integrations`), + }} + disabled={!isAdmin} + /> + ) ) : ( - router.push(`/${workspaceSlug}/settings/integrations`), - }} - disabled={!isAdmin} - /> - ) - ) : ( - - - - - - - )} -
-
+ + + + + + + )} +
+
+ ); }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx index 222cbc90a..6b0ff25e1 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx @@ -9,7 +9,8 @@ import useUserAuth from "hooks/use-user-auth"; // services import { IssueLabelService } from "services/issue"; // layouts -import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { ProjectSettingLayout } from "layouts/setting-layout"; // components import { CreateUpdateLabelInline, @@ -92,43 +93,60 @@ const LabelsSettings: NextPage = () => { onClose={() => setSelectDeleteLabel(null)} user={user} /> - }> -
-
-

Labels

+ }> + +
+
+

Labels

- -
-
- {labelForm && ( - { - setLabelForm(false); - setIsUpdating(false); - setLabelToUpdate(null); - }} - ref={scrollToRef} - /> - )} - <> - {issueLabels ? ( - issueLabels.length > 0 ? ( - issueLabels.map((label) => { - const children = issueLabels?.filter((l) => l.parent === label.id); + +
+
+ {labelForm && ( + { + setLabelForm(false); + setIsUpdating(false); + setLabelToUpdate(null); + }} + ref={scrollToRef} + /> + )} + <> + {issueLabels ? ( + issueLabels.length > 0 ? ( + issueLabels.map((label) => { + const children = issueLabels?.filter((l) => l.parent === label.id); - if (children && children.length === 0) { - if (!label.parent) + if (children && children.length === 0) { + if (!label.parent) + return ( + addLabelToGroup(label)} + editLabel={(label) => { + editLabel(label); + scrollToRef.current?.scrollIntoView({ + behavior: "smooth", + }); + }} + handleLabelDelete={() => setSelectDeleteLabel(label)} + /> + ); + } else return ( - addLabelToGroup(label)} + labelChildren={children} + addLabelToGroup={addLabelToGroup} editLabel={(label) => { editLabel(label); scrollToRef.current?.scrollIntoView({ @@ -136,49 +154,34 @@ const LabelsSettings: NextPage = () => { }); }} handleLabelDelete={() => setSelectDeleteLabel(label)} + user={user} /> ); - } else - return ( - { - editLabel(label); - scrollToRef.current?.scrollIntoView({ - behavior: "smooth", - }); - }} - handleLabelDelete={() => setSelectDeleteLabel(label)} - user={user} - /> - ); - }) + }) + ) : ( + newLabel(), + }} + /> + ) ) : ( - newLabel(), - }} - /> - ) - ) : ( - - - - - - - )} - -
-
-
+ + + + + + + )} + +
+
+
+ ); }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx index a23ac5f5f..7a0b34197 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx @@ -12,7 +12,8 @@ import useProjectMembers from "hooks/use-project-members"; import useProjectDetails from "hooks/use-project-details"; import { Controller, useForm } from "react-hook-form"; // layouts -import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { ProjectSettingLayout } from "layouts/setting-layout"; // components import ConfirmProjectMemberRemove from "components/project/confirm-project-member-remove"; import SendProjectInvitationModal from "components/project/send-project-invitation-modal"; @@ -196,234 +197,239 @@ const MembersSettings: NextPage = () => { const isAdmin = memberDetails?.role === 20; return ( - }> - { - setSelectedRemoveMember(null); - setSelectedInviteRemoveMember(null); - }} - data={members.find((item) => item.id === selectedRemoveMember || item.id === selectedInviteRemoveMember)} - handleDelete={async () => { - if (!activeWorkspace || !projectDetails) return; - if (selectedRemoveMember) { - await projectService.deleteProjectMember(activeWorkspace.slug, projectDetails.id, selectedRemoveMember); - mutateMembers((prevData: any) => prevData?.filter((item: any) => item.id !== selectedRemoveMember), false); - } - if (selectedInviteRemoveMember) { - await projectInvitationService.deleteProjectInvitation( - activeWorkspace.slug, - projectDetails.id, - selectedInviteRemoveMember - ); - mutateInvitations( - (prevData: any) => prevData?.filter((item: any) => item.id !== selectedInviteRemoveMember), - false - ); - } - setToastAlert({ - type: "success", - message: "Member removed successfully", - title: "Success", - }); - }} - /> - mutateMembers()} - /> -
-
-

Defaults

-
-
-
-
-

Project Lead

-
- {projectDetails ? ( - ( - { - submitChanges({ project_lead: val }); - }} - isDisabled={!isAdmin} - /> - )} - /> - ) : ( - - - - )} + }> + + { + setSelectedRemoveMember(null); + setSelectedInviteRemoveMember(null); + }} + data={members.find((item) => item.id === selectedRemoveMember || item.id === selectedInviteRemoveMember)} + handleDelete={async () => { + if (!activeWorkspace || !projectDetails) return; + if (selectedRemoveMember) { + await projectService.deleteProjectMember(activeWorkspace.slug, projectDetails.id, selectedRemoveMember); + mutateMembers( + (prevData: any) => prevData?.filter((item: any) => item.id !== selectedRemoveMember), + false + ); + } + if (selectedInviteRemoveMember) { + await projectInvitationService.deleteProjectInvitation( + activeWorkspace.slug, + projectDetails.id, + selectedInviteRemoveMember + ); + mutateInvitations( + (prevData: any) => prevData?.filter((item: any) => item.id !== selectedInviteRemoveMember), + false + ); + } + setToastAlert({ + type: "success", + message: "Member removed successfully", + title: "Success", + }); + }} + /> + mutateMembers()} + /> +
+
+

Defaults

+
+
+
+
+

Project Lead

+
+ {projectDetails ? ( + ( + { + submitChanges({ project_lead: val }); + }} + isDisabled={!isAdmin} + /> + )} + /> + ) : ( + + + + )} +
-
-
-

Default Assignee

-
- {projectDetails ? ( - ( - { - submitChanges({ default_assignee: val }); - }} - isDisabled={!isAdmin} - /> - )} - /> - ) : ( - - - - )} +
+

Default Assignee

+
+ {projectDetails ? ( + ( + { + submitChanges({ default_assignee: val }); + }} + isDisabled={!isAdmin} + /> + )} + /> + ) : ( + + + + )} +
-
-
-

Members

- -
- {!projectMembers || !projectInvitations ? ( - - - - - - - ) : ( -
- {members.length > 0 - ? members.map((member) => ( -
-
- {member.avatar && member.avatar !== "" ? ( -
- {member.display_name} -
- ) : member.display_name || member.email ? ( -
- {(member.display_name || member.email)?.charAt(0)} -
- ) : ( -
- ? -
- )} -
- {member.member ? ( - - - - {member.first_name} {member.last_name} - - ({member.display_name}) - - +
+

Members

+ +
+ {!projectMembers || !projectInvitations ? ( + + + + + + + ) : ( +
+ {members.length > 0 + ? members.map((member) => ( +
+
+ {member.avatar && member.avatar !== "" ? ( +
+ {member.display_name} +
+ ) : member.display_name || member.email ? ( +
+ {(member.display_name || member.email)?.charAt(0)} +
) : ( -

{member.display_name || member.email}

+
+ ? +
)} - {isOwner &&

{member.email}

} +
+ {member.member ? ( + + + + {member.first_name} {member.last_name} + + ({member.display_name}) + + + ) : ( +

{member.display_name || member.email}

+ )} + {isOwner &&

{member.email}

} +
+
+
+ {!member.member && ( +
+ Pending +
+ )} + + + {ROLE[member.role as keyof typeof ROLE]} + + {member.memberId !== user?.id && } +
+ } + value={member.role} + onChange={(value: 5 | 10 | 15 | 20 | undefined) => { + if (!activeWorkspace || !projectDetails) return; + + mutateMembers( + (prevData: any) => + prevData.map((m: any) => (m.id === member.id ? { ...m, role: value } : m)), + false + ); + + projectService + .updateProjectMember(activeWorkspace.slug, projectDetails.id, member.id, { + role: value, + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "An error occurred while updating member role. Please try again.", + }); + }); + }} + disabled={ + member.memberId === user?.id || + !member.member || + (currentUser && currentUser.role !== 20 && currentUser.role < member.role) + } + > + {Object.keys(ROLE).map((key) => { + if (currentUser && currentUser.role !== 20 && currentUser.role < parseInt(key)) return null; + + return ( + + <>{ROLE[parseInt(key) as keyof typeof ROLE]} + + ); + })} + + + { + if (member.member) setSelectedRemoveMember(member.id); + else setSelectedInviteRemoveMember(member.id); + }} + > + + + + {member.memberId !== user?.id ? "Remove member" : "Leave project"} + + +
-
- {!member.member && ( -
- Pending -
- )} - - - {ROLE[member.role as keyof typeof ROLE]} - - {member.memberId !== user?.id && } -
- } - value={member.role} - onChange={(value: 5 | 10 | 15 | 20 | undefined) => { - if (!activeWorkspace || !projectDetails) return; - - mutateMembers( - (prevData: any) => - prevData.map((m: any) => (m.id === member.id ? { ...m, role: value } : m)), - false - ); - - projectService - .updateProjectMember(activeWorkspace.slug, projectDetails.id, member.id, { - role: value, - }) - .catch(() => { - setToastAlert({ - type: "error", - title: "Error!", - message: "An error occurred while updating member role. Please try again.", - }); - }); - }} - disabled={ - member.memberId === user?.id || - !member.member || - (currentUser && currentUser.role !== 20 && currentUser.role < member.role) - } - > - {Object.keys(ROLE).map((key) => { - if (currentUser && currentUser.role !== 20 && currentUser.role < parseInt(key)) return null; - - return ( - - <>{ROLE[parseInt(key) as keyof typeof ROLE]} - - ); - })} - - - { - if (member.member) setSelectedRemoveMember(member.id); - else setSelectedInviteRemoveMember(member.id); - }} - > - - - - {member.memberId !== user?.id ? "Remove member" : "Leave project"} - - - -
-
- )) - : null} -
- )} -
-
+ )) + : null} +
+ )} +
+
+ ); }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx index af233d013..d27fe1dcc 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx @@ -10,7 +10,8 @@ import { ProjectStateService } from "services/project"; import useProjectDetails from "hooks/use-project-details"; import useUserAuth from "hooks/use-user-auth"; // layouts -import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { ProjectSettingLayout } from "layouts/setting-layout"; // components import { CreateUpdateStateInline, DeleteStateModal, SingleState, StateGroup } from "components/states"; import { ProjectSettingHeader } from "components/headers"; @@ -57,81 +58,83 @@ const StatesSettings: NextPage = () => { onClose={() => setSelectDeleteState(null)} user={user} /> - }> -
-
-

States

-
-
- {states && projectDetails && orderedStateGroups ? ( - Object.keys(orderedStateGroups).map((key) => { - if (orderedStateGroups[key].length !== 0) - return ( -
-
-

{key}

- -
-
- {key === activeGroup && ( - { - setActiveGroup(null); - setSelectedState(null); - }} - data={null} - selectedGroup={key as keyof StateGroup} - user={user} - /> - )} - {orderedStateGroups[key].map((state, index) => - state.id !== selectedState ? ( - setSelectedState(state.id)} - handleDeleteState={() => setSelectDeleteState(state.id)} + }> + +
+
+

States

+
+
+ {states && projectDetails && orderedStateGroups ? ( + Object.keys(orderedStateGroups).map((key) => { + if (orderedStateGroups[key].length !== 0) + return ( +
+
+

{key}

+ +
+
+ {key === activeGroup && ( + { + setActiveGroup(null); + setSelectedState(null); + }} + data={null} + selectedGroup={key as keyof StateGroup} user={user} /> - ) : ( -
- { - setActiveGroup(null); - setSelectedState(null); - }} - groupLength={orderedStateGroups[key].length} - data={statesList?.find((state) => state.id === selectedState) ?? null} - selectedGroup={key as keyof StateGroup} + )} + {orderedStateGroups[key].map((state, index) => + state.id !== selectedState ? ( + setSelectedState(state.id)} + handleDeleteState={() => setSelectDeleteState(state.id)} user={user} /> -
- ) - )} + ) : ( +
+ { + setActiveGroup(null); + setSelectedState(null); + }} + groupLength={orderedStateGroups[key].length} + data={statesList?.find((state) => state.id === selectedState) ?? null} + selectedGroup={key as keyof StateGroup} + user={user} + /> +
+ ) + )} +
-
- ); - }) - ) : ( - - - - - - - )} + ); + }) + ) : ( + + + + + + + )} +
-
- + + ); }; diff --git a/web/pages/[workspaceSlug]/settings/billing.tsx b/web/pages/[workspaceSlug]/settings/billing.tsx index 65a645217..8178d000b 100644 --- a/web/pages/[workspaceSlug]/settings/billing.tsx +++ b/web/pages/[workspaceSlug]/settings/billing.tsx @@ -1,6 +1,7 @@ import React from "react"; // layouts -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; // component import { WorkspaceSettingHeader } from "components/headers"; // ui @@ -9,24 +10,26 @@ import { Button } from "@plane/ui"; import type { NextPage } from "next"; const BillingSettings: NextPage = () => ( - }> -
-
-
-

Billing & Plans

-
-
-
+ }> + +
-

Current plan

-

You are currently using the free plan

- - - +
+

Billing & Plans

+
-
-
-
+
+
+

Current plan

+

You are currently using the free plan

+ + + +
+
+ + + ); export default BillingSettings; diff --git a/web/pages/[workspaceSlug]/settings/exports.tsx b/web/pages/[workspaceSlug]/settings/exports.tsx index 97e599094..58380df8e 100644 --- a/web/pages/[workspaceSlug]/settings/exports.tsx +++ b/web/pages/[workspaceSlug]/settings/exports.tsx @@ -1,20 +1,24 @@ +// layout +import { AppLayout } from "layouts/app-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; // components +import { WorkspaceSettingHeader } from "components/headers"; import ExportGuide from "components/exporter/guide"; // types import type { NextPage } from "next"; // helper -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; -import { WorkspaceSettingHeader } from "components/headers"; const ImportExport: NextPage = () => ( - }> -
-
-

Exports

+ }> + +
+
+

Exports

+
+
- -
- + + ); export default ImportExport; diff --git a/web/pages/[workspaceSlug]/settings/imports.tsx b/web/pages/[workspaceSlug]/settings/imports.tsx index 5263a97b7..033a85848 100644 --- a/web/pages/[workspaceSlug]/settings/imports.tsx +++ b/web/pages/[workspaceSlug]/settings/imports.tsx @@ -1,20 +1,23 @@ // layouts -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; // components +import { AppLayout } from "layouts/app-layout"; import IntegrationGuide from "components/integration/guide"; import { WorkspaceSettingHeader } from "components/headers"; // types import type { NextPage } from "next"; const ImportExport: NextPage = () => ( - }> -
-
-

Imports

-
- -
-
+ }> + +
+
+

Imports

+
+ +
+
+
); export default ImportExport; diff --git a/web/pages/[workspaceSlug]/settings/index.tsx b/web/pages/[workspaceSlug]/settings/index.tsx index 35fb220e8..5ccd4ed9e 100644 --- a/web/pages/[workspaceSlug]/settings/index.tsx +++ b/web/pages/[workspaceSlug]/settings/index.tsx @@ -13,7 +13,8 @@ import { FileService } from "services/file.service"; import useToast from "hooks/use-toast"; import useUserAuth from "hooks/use-user-auth"; // layouts -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; // components import { ImageUploadModal } from "components/core"; import { DeleteWorkspaceModal } from "components/workspace"; @@ -152,207 +153,209 @@ const WorkspaceSettings: NextPage = () => { const isAdmin = memberDetails?.role === 20; return ( - }> - setIsImageUploadModalOpen(false)} - isRemoving={isImageRemoving} - handleDelete={() => handleDelete(activeWorkspace?.logo)} - onSuccess={(imageUrl) => { - setIsImageUploading(true); - setValue("logo", imageUrl); - setIsImageUploadModalOpen(false); - handleSubmit(onSubmit)().then(() => setIsImageUploading(false)); - }} - value={watch("logo")} - /> - { - setIsOpen(false); - }} - data={activeWorkspace ?? null} - user={user} - /> - {activeWorkspace ? ( -
-
-
- -
-
-

{watch("name")}

- {`${ - typeof window !== "undefined" && window.location.origin.replace("http://", "").replace("https://", "") - }/${activeWorkspace.slug}`} -
-
-
-
- -
-
-
-

Workspace Name

- ( - - )} - /> -
- -
-

Company Size

- ( - c === value) ?? "Select organization size"} - width="w-full" - input - disabled={!isAdmin} - > - {ORGANIZATION_SIZE?.map((item) => ( - - {item} - - ))} - - )} - /> -
- -
-

Workspace URL

- ( - - )} - /> -
-
- -
- -
-
- {isAdmin && ( - - {({ open }) => ( -
- +

{watch("name")}

+ {`${ + typeof window !== "undefined" && window.location.origin.replace("http://", "").replace("https://", "") + }/${activeWorkspace.slug}`} +
+ -
-
- - + {watch("logo") && watch("logo") !== null && watch("logo") !== "" ? ( + <> + + Edit logo + + ) : ( + "Upload logo" + )} +
- )} - - )} -
- ) : ( -
- -
- )} -
+
+
+ +
+
+
+

Workspace Name

+ ( + + )} + /> +
+ +
+

Company Size

+ ( + c === value) ?? "Select organization size"} + width="w-full" + input + disabled={!isAdmin} + > + {ORGANIZATION_SIZE?.map((item) => ( + + {item} + + ))} + + )} + /> +
+ +
+

Workspace URL

+ ( + + )} + /> +
+
+ +
+ +
+
+ {isAdmin && ( + + {({ open }) => ( +
+ + Delete Workspace + {/* */} + {open ? : } + + + + +
+ + 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. + +
+ +
+
+
+
+
+ )} +
+ )} +
+ ) : ( +
+ +
+ )} + + ); }; diff --git a/web/pages/[workspaceSlug]/settings/integrations.tsx b/web/pages/[workspaceSlug]/settings/integrations.tsx index 1ec29736e..434925c82 100644 --- a/web/pages/[workspaceSlug]/settings/integrations.tsx +++ b/web/pages/[workspaceSlug]/settings/integrations.tsx @@ -7,7 +7,8 @@ import useSWR from "swr"; // services import { IntegrationService } from "services/integrations"; // layouts -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; // components import { SingleIntegrationCard } from "components/integration"; import { WorkspaceSettingHeader } from "components/headers"; @@ -32,23 +33,25 @@ const WorkspaceIntegrations: NextPage = () => { ); return ( - }> -
- -
- {appIntegrations ? ( - appIntegrations.map((integration) => ( - - )) - ) : ( - - - - - )} -
-
-
+ }> + +
+ +
+ {appIntegrations ? ( + appIntegrations.map((integration) => ( + + )) + ) : ( + + + + + )} +
+
+
+
); }; diff --git a/web/pages/[workspaceSlug]/settings/members.tsx b/web/pages/[workspaceSlug]/settings/members.tsx index 0a2cc7cc9..4c055b687 100644 --- a/web/pages/[workspaceSlug]/settings/members.tsx +++ b/web/pages/[workspaceSlug]/settings/members.tsx @@ -12,7 +12,8 @@ import useToast from "hooks/use-toast"; import useUser from "hooks/use-user"; import useWorkspaceMembers from "hooks/use-workspace-members"; // layouts -import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; +import { AppLayout } from "layouts/app-layout"; +import { WorkspaceSettingLayout } from "layouts/setting-layout"; // components import ConfirmWorkspaceMemberRemove from "components/workspace/confirm-workspace-member-remove"; import SendWorkspaceInvitationModal from "components/workspace/send-workspace-invitation-modal"; @@ -92,218 +93,220 @@ const MembersSettings: NextPage = () => { }; return ( - }> - { - setSelectedRemoveMember(null); - setSelectedInviteRemoveMember(null); - }} - data={ - selectedRemoveMember - ? members.find((item) => item.id === selectedRemoveMember) - : selectedInviteRemoveMember - ? members.find((item) => item.id === selectedInviteRemoveMember) - : null - } - handleDelete={async () => { - if (!workspaceSlug) return; - if (selectedRemoveMember) { - workspaceService - .deleteWorkspaceMember(workspaceSlug as string, selectedRemoveMember) - .catch((err) => { - const error = err?.error; - setToastAlert({ - type: "error", - title: "Error", - message: error || "Something went wrong", - }); - }) - .finally(() => { - mutateMembers((prevData: any) => prevData?.filter((item: any) => item.id !== selectedRemoveMember)); - }); + }> + + { + setSelectedRemoveMember(null); + setSelectedInviteRemoveMember(null); + }} + data={ + selectedRemoveMember + ? members.find((item) => item.id === selectedRemoveMember) + : selectedInviteRemoveMember + ? members.find((item) => item.id === selectedInviteRemoveMember) + : null } - if (selectedInviteRemoveMember) { - mutateInvitations( - (prevData: any) => prevData?.filter((item: any) => item.id !== selectedInviteRemoveMember), - false - ); - workspaceService - .deleteWorkspaceInvitations(workspaceSlug as string, selectedInviteRemoveMember) - .then(() => { - setToastAlert({ - type: "success", - title: "Success", - message: "Member removed successfully", + handleDelete={async () => { + if (!workspaceSlug) return; + if (selectedRemoveMember) { + workspaceService + .deleteWorkspaceMember(workspaceSlug as string, selectedRemoveMember) + .catch((err) => { + const error = err?.error; + setToastAlert({ + type: "error", + title: "Error", + message: error || "Something went wrong", + }); + }) + .finally(() => { + mutateMembers((prevData: any) => prevData?.filter((item: any) => item.id !== selectedRemoveMember)); }); - }) - .catch((err) => { - const error = err?.error; - setToastAlert({ - type: "error", - title: "Error", - message: error || "Something went wrong", + } + if (selectedInviteRemoveMember) { + mutateInvitations( + (prevData: any) => prevData?.filter((item: any) => item.id !== selectedInviteRemoveMember), + false + ); + workspaceService + .deleteWorkspaceInvitations(workspaceSlug as string, selectedInviteRemoveMember) + .then(() => { + setToastAlert({ + type: "success", + title: "Success", + message: "Member removed successfully", + }); + }) + .catch((err) => { + const error = err?.error; + setToastAlert({ + type: "error", + title: "Error", + message: error || "Something went wrong", + }); + }) + .finally(() => { + mutateInvitations(); }); - }) - .finally(() => { - mutateInvitations(); - }); - } - setSelectedRemoveMember(null); - setSelectedInviteRemoveMember(null); - }} - /> - -
-
-

Members

- -
- {!workspaceMembers || !workspaceInvitations ? ( - - - - - - - ) : ( -
- {members.length > 0 - ? members.map((member) => ( -
-
- {member.avatar && member.avatar !== "" ? ( - - - {member.display_name - - - ) : member.display_name || member.email ? ( - - - {(member.display_name || member.email)?.charAt(0)} - - - ) : ( -
- ? -
- )} -
- {member.member ? ( + } + setSelectedRemoveMember(null); + setSelectedInviteRemoveMember(null); + }} + /> + +
+
+

Members

+ +
+ {!workspaceMembers || !workspaceInvitations ? ( + + + + + + + ) : ( +
+ {members.length > 0 + ? members.map((member) => ( +
+
+ {member.avatar && member.avatar !== "" ? ( - - - {member.first_name} {member.last_name} - - ({member.display_name}) + + {member.display_name + + + ) : member.display_name || member.email ? ( + + + {(member.display_name || member.email)?.charAt(0)} ) : ( -

{member.display_name || member.email}

+
+ ? +
)} - {isOwner &&

{member.email}

} +
+ {member.member ? ( + + + + {member.first_name} {member.last_name} + + ({member.display_name}) + + + ) : ( +

{member.display_name || member.email}

+ )} + {isOwner &&

{member.email}

} +
+
+
+ {!member?.status && ( +
+

Pending

+
+ )} + {member?.status && !member?.accountCreated && ( +
+

Account not created

+
+ )} + + + {ROLE[member.role as keyof typeof ROLE]} + + {member.memberId !== user?.id && } +
+ } + value={member.role} + onChange={(value: 5 | 10 | 15 | 20 | undefined) => { + if (!workspaceSlug) return; + + mutateMembers( + (prevData: any) => + prevData?.map((m: any) => (m.id === member.id ? { ...m, role: value } : m)), + false + ); + + workspaceService + .updateWorkspaceMember(workspaceSlug?.toString(), member.id, { + role: value, + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "An error occurred while updating member role. Please try again.", + }); + }); + }} + disabled={ + member.memberId === currentUser?.member.id || + !member.status || + (currentUser && currentUser.role !== 20 && currentUser.role < member.role) + } + > + {Object.keys(ROLE).map((key) => { + if (currentUser && currentUser.role !== 20 && currentUser.role < parseInt(key)) return null; + + return ( + + <>{ROLE[parseInt(key) as keyof typeof ROLE]} + + ); + })} + + + { + if (member.member) { + setSelectedRemoveMember(member.id); + } else { + setSelectedInviteRemoveMember(member.id); + } + }} + > + + + + {user?.id === member.memberId ? "Leave" : "Remove member"} + + +
-
- {!member?.status && ( -
-

Pending

-
- )} - {member?.status && !member?.accountCreated && ( -
-

Account not created

-
- )} - - - {ROLE[member.role as keyof typeof ROLE]} - - {member.memberId !== user?.id && } -
- } - value={member.role} - onChange={(value: 5 | 10 | 15 | 20 | undefined) => { - if (!workspaceSlug) return; - - mutateMembers( - (prevData: any) => - prevData?.map((m: any) => (m.id === member.id ? { ...m, role: value } : m)), - false - ); - - workspaceService - .updateWorkspaceMember(workspaceSlug?.toString(), member.id, { - role: value, - }) - .catch(() => { - setToastAlert({ - type: "error", - title: "Error!", - message: "An error occurred while updating member role. Please try again.", - }); - }); - }} - disabled={ - member.memberId === currentUser?.member.id || - !member.status || - (currentUser && currentUser.role !== 20 && currentUser.role < member.role) - } - > - {Object.keys(ROLE).map((key) => { - if (currentUser && currentUser.role !== 20 && currentUser.role < parseInt(key)) return null; - - return ( - - <>{ROLE[parseInt(key) as keyof typeof ROLE]} - - ); - })} - - - { - if (member.member) { - setSelectedRemoveMember(member.id); - } else { - setSelectedInviteRemoveMember(member.id); - } - }} - > - - - - {user?.id === member.memberId ? "Leave" : "Remove member"} - - - -
-
- )) - : null} -
- )} -
-
+ )) + : null} +
+ )} + +
+ ); }; diff --git a/web/pages/[workspaceSlug]/workspace-views/issues.tsx b/web/pages/[workspaceSlug]/workspace-views/issues.tsx deleted file mode 100644 index ef81e86a9..000000000 --- a/web/pages/[workspaceSlug]/workspace-views/issues.tsx +++ /dev/null @@ -1,39 +0,0 @@ -// layouts -import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy"; -// components -// import { WorkspaceIssuesViewOptions } from "components/issues/workspace-views/workspace-issue-view-option"; -// import { WorkspaceViewIssues } from "components/issues/workspace-views/workpace-view-issues"; -// ui -import { PrimaryButton } from "components/ui"; -// icons -import { CheckCircle, Plus } from "lucide-react"; - -const WorkspaceView = () => ( - - - Workspace issues -
- } - right={ -
- {/* */} - { - const e = new KeyboardEvent("keydown", { key: "c" }); - document.dispatchEvent(e); - }} - > - - Add Issue - -
- } - > - {/* */} - -); - -export default WorkspaceView; From a6d741e7846e0896aeb988087f8f4a24821d1a8a Mon Sep 17 00:00:00 2001 From: guru_sainath Date: Wed, 25 Oct 2023 16:09:50 +0530 Subject: [PATCH 02/17] chore: implemented drag and drop between dates for project issues, cycle, module, and project views for calendar layout (#2535) --- .../issue-layouts/calendar/day-tile.tsx | 61 +++++++------ .../issue-layouts/calendar/issue-blocks.tsx | 58 ++++++------ .../calendar/roots/cycle-root.tsx | 10 ++- .../calendar/roots/module-root.tsx | 4 +- .../calendar/roots/project-root.tsx | 10 ++- .../calendar/roots/project-view-root.tsx | 4 +- .../cycle/cycle_issue_calendar_view.store.ts | 89 +++++++++++++++++++ web/store/cycle/index.ts | 1 + web/store/issue/index.ts | 1 + web/store/issue/issue_calendar_view.store.ts | 88 ++++++++++++++++++ web/store/module/index.ts | 1 + .../module_issue_calendar_view.store.ts | 89 +++++++++++++++++++ web/store/project-view/index.ts | 2 + .../project_view_issue_calendar_view.store.ts | 89 +++++++++++++++++++ .../project-view/project_view_issues.store.ts | 32 ++++++- web/store/root.ts | 16 ++++ 16 files changed, 492 insertions(+), 63 deletions(-) create mode 100644 web/store/cycle/cycle_issue_calendar_view.store.ts create mode 100644 web/store/issue/issue_calendar_view.store.ts create mode 100644 web/store/module/module_issue_calendar_view.store.ts create mode 100644 web/store/project-view/project_view_issue_calendar_view.store.ts diff --git a/web/components/issues/issue-layouts/calendar/day-tile.tsx b/web/components/issues/issue-layouts/calendar/day-tile.tsx index 7d07ce7f4..03d797522 100644 --- a/web/components/issues/issue-layouts/calendar/day-tile.tsx +++ b/web/components/issues/issue-layouts/calendar/day-tile.tsx @@ -29,35 +29,46 @@ export const CalendarDayTile: React.FC = observer((props) => { const issuesList = issues ? (issues as IIssueGroupedStructure)[renderDateFormat(date.date)] : null; return ( - - {(provided, snapshot) => ( + <> +
+ {/* header */}
- <> -
- {date.date.getDate() === 1 && MONTHS_LIST[date.date.getMonth() + 1].shortTitle + " "} - {date.date.getDate()} -
- - {provided.placeholder} - + {date.date.getDate() === 1 && MONTHS_LIST[date.date.getMonth() + 1].shortTitle + " "} + {date.date.getDate()}
- )} - + + {/* content */} +
+ + {(provided, snapshot) => ( +
+ + {provided.placeholder} +
+ )} +
+
+
+ ); }); diff --git a/web/components/issues/issue-layouts/calendar/issue-blocks.tsx b/web/components/issues/issue-layouts/calendar/issue-blocks.tsx index de58b8622..eac2ef43d 100644 --- a/web/components/issues/issue-layouts/calendar/issue-blocks.tsx +++ b/web/components/issues/issue-layouts/calendar/issue-blocks.tsx @@ -17,42 +17,46 @@ export const CalendarIssueBlocks: React.FC = observer((props) => { const { workspaceSlug } = router.query; return ( - )} ))} -
+ ); }); diff --git a/web/components/issues/issue-layouts/calendar/roots/cycle-root.tsx b/web/components/issues/issue-layouts/calendar/roots/cycle-root.tsx index 0f0c19f06..ec9e6b94f 100644 --- a/web/components/issues/issue-layouts/calendar/roots/cycle-root.tsx +++ b/web/components/issues/issue-layouts/calendar/roots/cycle-root.tsx @@ -11,12 +11,16 @@ import { IIssueGroupedStructure } from "store/issue"; import { IIssue } from "types"; export const CycleCalendarLayout: React.FC = observer(() => { - const { cycleIssue: cycleIssueStore, issueFilter: issueFilterStore, issueDetail: issueDetailStore } = useMobxStore(); + const { + cycleIssue: cycleIssueStore, + issueFilter: issueFilterStore, + issueDetail: issueDetailStore, + cycleIssueCalendarView: cycleIssueCalendarViewStore, + } = useMobxStore(); const router = useRouter(); const { workspaceSlug, cycleId } = router.query; - // TODO: add drag and drop functionality const onDragEnd = (result: DropResult) => { if (!result) return; @@ -26,7 +30,7 @@ export const CycleCalendarLayout: React.FC = observer(() => { // return if dropped on the same date if (result.destination.droppableId === result.source.droppableId) return; - // issueKanBanViewStore?.handleDragDrop(result.source, result.destination); + cycleIssueCalendarViewStore?.handleDragDrop(result.source, result.destination); }; const issues = cycleIssueStore.getIssues; diff --git a/web/components/issues/issue-layouts/calendar/roots/module-root.tsx b/web/components/issues/issue-layouts/calendar/roots/module-root.tsx index c0afd5a0a..1f0219d55 100644 --- a/web/components/issues/issue-layouts/calendar/roots/module-root.tsx +++ b/web/components/issues/issue-layouts/calendar/roots/module-root.tsx @@ -15,12 +15,12 @@ export const ModuleCalendarLayout: React.FC = observer(() => { moduleIssue: moduleIssueStore, issueFilter: issueFilterStore, issueDetail: issueDetailStore, + moduleIssueCalendarView: moduleIssueCalendarViewStore, } = useMobxStore(); const router = useRouter(); const { workspaceSlug, moduleId } = router.query; - // TODO: add drag and drop functionality const onDragEnd = (result: DropResult) => { if (!result) return; @@ -30,7 +30,7 @@ export const ModuleCalendarLayout: React.FC = observer(() => { // return if dropped on the same date if (result.destination.droppableId === result.source.droppableId) return; - // issueKanBanViewStore?.handleDragDrop(result.source, result.destination); + moduleIssueCalendarViewStore?.handleDragDrop(result.source, result.destination); }; const issues = moduleIssueStore.getIssues; diff --git a/web/components/issues/issue-layouts/calendar/roots/project-root.tsx b/web/components/issues/issue-layouts/calendar/roots/project-root.tsx index 1d7c1cea3..96459a350 100644 --- a/web/components/issues/issue-layouts/calendar/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/calendar/roots/project-root.tsx @@ -11,12 +11,16 @@ import { IIssueGroupedStructure } from "store/issue"; import { IIssue } from "types"; export const CalendarLayout: React.FC = observer(() => { - const { issue: issueStore, issueFilter: issueFilterStore, issueDetail: issueDetailStore } = useMobxStore(); + const { + issue: issueStore, + issueFilter: issueFilterStore, + issueDetail: issueDetailStore, + issueCalendarView: issueCalendarViewStore, + } = useMobxStore(); const router = useRouter(); const { workspaceSlug } = router.query; - // TODO: add drag and drop functionality const onDragEnd = (result: DropResult) => { if (!result) return; @@ -26,7 +30,7 @@ export const CalendarLayout: React.FC = observer(() => { // return if dropped on the same date if (result.destination.droppableId === result.source.droppableId) return; - // issueKanBanViewStore?.handleDragDrop(result.source, result.destination); + issueCalendarViewStore?.handleDragDrop(result.source, result.destination); }; const issues = issueStore.getIssues; diff --git a/web/components/issues/issue-layouts/calendar/roots/project-view-root.tsx b/web/components/issues/issue-layouts/calendar/roots/project-view-root.tsx index 5aa9e1545..6ea847609 100644 --- a/web/components/issues/issue-layouts/calendar/roots/project-view-root.tsx +++ b/web/components/issues/issue-layouts/calendar/roots/project-view-root.tsx @@ -15,12 +15,12 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => { projectViewIssues: projectViewIssuesStore, issueFilter: issueFilterStore, issueDetail: issueDetailStore, + projectViewIssueCalendarView: projectViewIssueCalendarViewStore, } = useMobxStore(); const router = useRouter(); const { workspaceSlug } = router.query; - // TODO: add drag and drop functionality const onDragEnd = (result: DropResult) => { if (!result) return; @@ -30,7 +30,7 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => { // return if dropped on the same date if (result.destination.droppableId === result.source.droppableId) return; - // issueKanBanViewStore?.handleDragDrop(result.source, result.destination); + projectViewIssueCalendarViewStore?.handleDragDrop(result.source, result.destination); }; const issues = projectViewIssuesStore.getIssues; diff --git a/web/store/cycle/cycle_issue_calendar_view.store.ts b/web/store/cycle/cycle_issue_calendar_view.store.ts new file mode 100644 index 000000000..0ebb38c37 --- /dev/null +++ b/web/store/cycle/cycle_issue_calendar_view.store.ts @@ -0,0 +1,89 @@ +import { action, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +import { IIssueType } from "./cycle_issue.store"; + +export interface ICycleIssueCalendarViewStore { + // actions + handleDragDrop: (source: any, destination: any) => void; +} + +export class CycleIssueCalendarViewStore implements ICycleIssueCalendarViewStore { + // root store + rootStore; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // actions + handleDragDrop: action, + }); + + this.rootStore = _rootStore; + } + + handleDragDrop = async (source: any, destination: any) => { + const workspaceSlug = this.rootStore?.workspace?.workspaceSlug; + const projectId = this.rootStore?.project?.projectId; + const cycleId = this.rootStore?.cycle?.cycleId; + const issueType: IIssueType | null = this.rootStore?.cycleIssue?.getIssueType; + const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null; + const currentIssues: any = this.rootStore.cycleIssue.getIssues; + + if (workspaceSlug && projectId && cycleId && issueType && issueLayout === "calendar" && currentIssues) { + // update issue payload + let updateIssue: any = { + workspaceSlug: workspaceSlug, + projectId: projectId, + }; + + const droppableSourceColumnId = source.droppableId; + const droppableDestinationColumnId = destination.droppableId; + + if (droppableSourceColumnId === droppableDestinationColumnId) return; + + if (droppableSourceColumnId != droppableDestinationColumnId) { + // horizontal + const _sourceIssues = currentIssues[droppableSourceColumnId]; + let _destinationIssues = currentIssues[droppableDestinationColumnId] || []; + + const [removed] = _sourceIssues.splice(source.index, 1); + + if (_destinationIssues && _destinationIssues.length > 0) + _destinationIssues.splice(destination.index, 0, { + ...removed, + target_date: droppableDestinationColumnId, + }); + else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }]; + + updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId }; + + currentIssues[droppableSourceColumnId] = _sourceIssues; + currentIssues[droppableDestinationColumnId] = _destinationIssues; + } + + const reorderedIssues = { + ...this.rootStore?.cycleIssue.issues, + [cycleId]: { + ...this.rootStore?.cycleIssue.issues?.[cycleId], + [issueType]: { + ...this.rootStore?.cycleIssue.issues?.[cycleId]?.[issueType], + [issueType]: currentIssues, + }, + }, + }; + + runInAction(() => { + this.rootStore.cycleIssue.issues = { ...reorderedIssues }; + }); + + this.rootStore.issueDetail?.updateIssue( + updateIssue.workspaceSlug, + updateIssue.projectId, + updateIssue.issueId, + updateIssue + ); + } + + return; + }; +} diff --git a/web/store/cycle/index.ts b/web/store/cycle/index.ts index b8fb17576..ae854f978 100644 --- a/web/store/cycle/index.ts +++ b/web/store/cycle/index.ts @@ -1,4 +1,5 @@ export * from "./cycle_issue_filters.store"; export * from "./cycle_issue_kanban_view.store"; +export * from "./cycle_issue_calendar_view.store"; export * from "./cycle_issue.store"; export * from "./cycles.store"; diff --git a/web/store/issue/index.ts b/web/store/issue/index.ts index 27c613eb8..7b6cb4f34 100644 --- a/web/store/issue/index.ts +++ b/web/store/issue/index.ts @@ -2,4 +2,5 @@ export * from "./issue_detail.store"; export * from "./issue_draft.store"; export * from "./issue_filters.store"; export * from "./issue_kanban_view.store"; +export * from "./issue_calendar_view.store"; export * from "./issue.store"; diff --git a/web/store/issue/issue_calendar_view.store.ts b/web/store/issue/issue_calendar_view.store.ts new file mode 100644 index 000000000..5f9cc89bf --- /dev/null +++ b/web/store/issue/issue_calendar_view.store.ts @@ -0,0 +1,88 @@ +import { action, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +import { IIssueType } from "./issue.store"; + +export interface IIssueCalendarViewStore { + // actions + handleDragDrop: (source: any, destination: any) => void; +} + +export class IssueCalendarViewStore implements IIssueCalendarViewStore { + // root store + rootStore; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // actions + handleDragDrop: action, + }); + + this.rootStore = _rootStore; + } + + handleDragDrop = async (source: any, destination: any) => { + const workspaceSlug = this.rootStore?.workspace?.workspaceSlug; + const projectId = this.rootStore?.project?.projectId; + const issueType: IIssueType | null = this.rootStore?.issue?.getIssueType; + const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null; + const currentIssues: any = this.rootStore.issue.getIssues; + + if (workspaceSlug && projectId && issueType && issueLayout === "calendar" && currentIssues) { + // update issue payload + let updateIssue: any = { + workspaceSlug: workspaceSlug, + projectId: projectId, + }; + + const droppableSourceColumnId = source.droppableId; + const droppableDestinationColumnId = destination.droppableId; + + if (droppableSourceColumnId === droppableDestinationColumnId) return; + + // horizontal + if (droppableSourceColumnId != droppableDestinationColumnId) { + const _sourceIssues = currentIssues[droppableSourceColumnId]; + let _destinationIssues = currentIssues[droppableDestinationColumnId] || []; + + const [removed] = _sourceIssues.splice(source.index, 1); + + if (_destinationIssues && _destinationIssues.length > 0) + _destinationIssues.splice(destination.index, 0, { + ...removed, + target_date: droppableDestinationColumnId, + }); + else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }]; + + updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId }; + + currentIssues[droppableSourceColumnId] = _sourceIssues; + currentIssues[droppableDestinationColumnId] = _destinationIssues; + } + + const reorderedIssues = { + ...this.rootStore?.issue.issues, + [projectId]: { + ...this.rootStore?.issue.issues?.[projectId], + [issueType]: { + ...this.rootStore?.issue.issues?.[projectId]?.[issueType], + [issueType]: currentIssues, + }, + }, + }; + + runInAction(() => { + this.rootStore.issue.issues = { ...reorderedIssues }; + }); + + this.rootStore.issueDetail?.updateIssue( + updateIssue.workspaceSlug, + updateIssue.projectId, + updateIssue.issueId, + updateIssue + ); + } + + return; + }; +} diff --git a/web/store/module/index.ts b/web/store/module/index.ts index 4f2bc1027..3d62d3de8 100644 --- a/web/store/module/index.ts +++ b/web/store/module/index.ts @@ -1,4 +1,5 @@ export * from "./module_filters.store"; export * from "./module_issue_kanban_view.store"; +export * from "./module_issue_calendar_view.store"; export * from "./module_issue.store"; export * from "./modules.store"; diff --git a/web/store/module/module_issue_calendar_view.store.ts b/web/store/module/module_issue_calendar_view.store.ts new file mode 100644 index 000000000..95a866040 --- /dev/null +++ b/web/store/module/module_issue_calendar_view.store.ts @@ -0,0 +1,89 @@ +import { action, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +import { IIssueType } from "./module_issue.store"; + +export interface IModuleIssueCalendarViewStore { + // actions + handleDragDrop: (source: any, destination: any) => void; +} + +export class ModuleIssueCalendarViewStore implements IModuleIssueCalendarViewStore { + // root store + rootStore; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // actions + handleDragDrop: action, + }); + + this.rootStore = _rootStore; + } + + handleDragDrop = async (source: any, destination: any) => { + const workspaceSlug = this.rootStore?.workspace?.workspaceSlug; + const projectId = this.rootStore?.project?.projectId; + const moduleId = this.rootStore?.module?.moduleId; + const issueType: IIssueType | null = this.rootStore?.moduleIssue?.getIssueType; + const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null; + const currentIssues: any = this.rootStore.moduleIssue.getIssues; + + if (workspaceSlug && projectId && moduleId && issueType && issueLayout === "calendar" && currentIssues) { + // update issue payload + let updateIssue: any = { + workspaceSlug: workspaceSlug, + projectId: projectId, + }; + + const droppableSourceColumnId = source.droppableId; + const droppableDestinationColumnId = destination.droppableId; + + if (droppableSourceColumnId === droppableDestinationColumnId) return; + + if (droppableSourceColumnId != droppableDestinationColumnId) { + // horizontal + const _sourceIssues = currentIssues[droppableSourceColumnId]; + let _destinationIssues = currentIssues[droppableDestinationColumnId] || []; + + const [removed] = _sourceIssues.splice(source.index, 1); + + if (_destinationIssues && _destinationIssues.length > 0) + _destinationIssues.splice(destination.index, 0, { + ...removed, + target_date: droppableDestinationColumnId, + }); + else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }]; + + updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId }; + + currentIssues[droppableSourceColumnId] = _sourceIssues; + currentIssues[droppableDestinationColumnId] = _destinationIssues; + } + + const reorderedIssues = { + ...this.rootStore?.moduleIssue.issues, + [moduleId]: { + ...this.rootStore?.moduleIssue.issues?.[moduleId], + [issueType]: { + ...this.rootStore?.moduleIssue.issues?.[moduleId]?.[issueType], + [issueType]: currentIssues, + }, + }, + }; + + runInAction(() => { + this.rootStore.moduleIssue.issues = { ...reorderedIssues }; + }); + + this.rootStore.issueDetail?.updateIssue( + updateIssue.workspaceSlug, + updateIssue.projectId, + updateIssue.issueId, + updateIssue + ); + } + + return; + }; +} diff --git a/web/store/project-view/index.ts b/web/store/project-view/index.ts index 8fd611bab..39a4c2fac 100644 --- a/web/store/project-view/index.ts +++ b/web/store/project-view/index.ts @@ -1,3 +1,5 @@ export * from "./project_view_filters.store"; export * from "./project_view_issues.store"; export * from "./project_views.store"; + +export * from "./project_view_issue_calendar_view.store"; diff --git a/web/store/project-view/project_view_issue_calendar_view.store.ts b/web/store/project-view/project_view_issue_calendar_view.store.ts new file mode 100644 index 000000000..2f70df136 --- /dev/null +++ b/web/store/project-view/project_view_issue_calendar_view.store.ts @@ -0,0 +1,89 @@ +import { action, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +import { IIssueType } from "./project_view_issues.store"; + +export interface IProjectViewIssueCalendarViewStore { + // actions + handleDragDrop: (source: any, destination: any) => void; +} + +export class ProjectViewIssueCalendarViewStore implements IProjectViewIssueCalendarViewStore { + // root store + rootStore; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // actions + handleDragDrop: action, + }); + + this.rootStore = _rootStore; + } + + handleDragDrop = async (source: any, destination: any) => { + const workspaceSlug = this.rootStore?.workspace?.workspaceSlug; + const projectId = this.rootStore?.project?.projectId; + const viewId = this.rootStore?.projectViews?.viewId; + const issueType: IIssueType | null = this.rootStore?.projectViewIssues?.getIssueType; + const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null; + const currentIssues: any = this.rootStore.projectViewIssues.getIssues; + + if (workspaceSlug && projectId && viewId && issueType && issueLayout === "calendar" && currentIssues) { + // update issue payload + let updateIssue: any = { + workspaceSlug: workspaceSlug, + projectId: projectId, + }; + + const droppableSourceColumnId = source.droppableId; + const droppableDestinationColumnId = destination.droppableId; + + if (droppableSourceColumnId === droppableDestinationColumnId) return; + + if (droppableSourceColumnId != droppableDestinationColumnId) { + // horizontal + const _sourceIssues = currentIssues[droppableSourceColumnId]; + let _destinationIssues = currentIssues[droppableDestinationColumnId] || []; + + const [removed] = _sourceIssues.splice(source.index, 1); + + if (_destinationIssues && _destinationIssues.length > 0) + _destinationIssues.splice(destination.index, 0, { + ...removed, + target_date: droppableDestinationColumnId, + }); + else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }]; + + updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId }; + + currentIssues[droppableSourceColumnId] = _sourceIssues; + currentIssues[droppableDestinationColumnId] = _destinationIssues; + } + + const reorderedIssues = { + ...this.rootStore?.projectViewIssues.viewIssues, + [viewId]: { + ...this.rootStore?.projectViewIssues.viewIssues?.[viewId], + [issueType]: { + ...this.rootStore?.projectViewIssues.viewIssues?.[viewId]?.[issueType], + [issueType]: currentIssues, + }, + }, + }; + + runInAction(() => { + this.rootStore.projectViewIssues.viewIssues = { ...reorderedIssues }; + }); + + this.rootStore.issueDetail?.updateIssue( + updateIssue.workspaceSlug, + updateIssue.projectId, + updateIssue.issueId, + updateIssue + ); + } + + return; + }; +} diff --git a/web/store/project-view/project_view_issues.store.ts b/web/store/project-view/project_view_issues.store.ts index 9588237fe..1c6374942 100644 --- a/web/store/project-view/project_view_issues.store.ts +++ b/web/store/project-view/project_view_issues.store.ts @@ -6,10 +6,18 @@ import { handleIssueQueryParamsByLayout } from "helpers/issue.helper"; import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers"; // types import { RootStore } from "../root"; -import { IIssueGroupWithSubGroupsStructure, IIssueGroupedStructure, IIssueUnGroupedStructure } from "store/issue"; import { IIssue, IIssueFilterOptions } from "types"; import { IBlockUpdateData } from "components/gantt-chart"; +export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped"; +export type IIssueGroupedStructure = { [group_id: string]: IIssue[] }; +export type IIssueGroupWithSubGroupsStructure = { + [group_id: string]: { + [sub_group_id: string]: IIssue[]; + }; +}; +export type IIssueUnGroupedStructure = IIssue[]; + export interface IProjectViewIssuesStore { // states loader: boolean; @@ -37,6 +45,7 @@ export interface IProjectViewIssuesStore { // computed getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null; + getIssueType: IIssueType | null; } export class ProjectViewIssuesStore implements IProjectViewIssuesStore { @@ -75,6 +84,7 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore { fetchViewIssues: action, // computed + getIssueType: computed, getIssues: computed, }); @@ -108,6 +118,26 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore { return computedFilters; }; + 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; + } + get getIssues() { const viewId: string | null = this.rootStore.projectViews.viewId; const issueType = this.rootStore.issue.getIssueType; diff --git a/web/store/root.ts b/web/store/root.ts index 4a830435a..1a85185d6 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -12,6 +12,8 @@ import { IssueDetailStore, IssueFilterStore, IssueKanBanViewStore, + IIssueCalendarViewStore, + IssueCalendarViewStore, IssueStore, } from "store/issue"; import { IWorkspaceFilterStore, IWorkspaceStore, WorkspaceFilterStore, WorkspaceStore } from "store/workspace"; @@ -24,6 +26,8 @@ import { ModuleFilterStore, ModuleIssueKanBanViewStore, ModuleIssueStore, + IModuleIssueCalendarViewStore, + ModuleIssueCalendarViewStore, ModuleStore, } from "store/module"; import { @@ -33,6 +37,8 @@ import { CycleStore, ICycleIssueFilterStore, ICycleIssueKanBanViewStore, + ICycleIssueCalendarViewStore, + CycleIssueCalendarViewStore, ICycleIssueStore, ICycleStore, } from "store/cycle"; @@ -43,6 +49,8 @@ import { ProjectViewFiltersStore, ProjectViewIssuesStore, ProjectViewsStore, + IProjectViewIssueCalendarViewStore, + ProjectViewIssueCalendarViewStore, } from "store/project-view"; import CalendarStore, { ICalendarStore } from "store/calendar.store"; import { @@ -95,19 +103,23 @@ export class RootStore { moduleIssue: IModuleIssueStore; moduleFilter: IModuleFilterStore; moduleIssueKanBanView: IModuleIssueKanBanViewStore; + moduleIssueCalendarView: IModuleIssueCalendarViewStore; cycle: ICycleStore; cycleIssue: ICycleIssueStore; cycleIssueFilter: ICycleIssueFilterStore; cycleIssueKanBanView: ICycleIssueKanBanViewStore; + cycleIssueCalendarView: ICycleIssueCalendarViewStore; projectViews: IProjectViewsStore; projectViewIssues: IProjectViewIssuesStore; projectViewFilters: IProjectViewFiltersStore; + projectViewIssueCalendarView: IProjectViewIssueCalendarViewStore; issueFilter: IIssueFilterStore; issueDetail: IIssueDetailStore; issueKanBanView: IIssueKanBanViewStore; + issueCalendarView: IIssueCalendarViewStore; draftIssuesStore: DraftIssuesStore; calendar: ICalendarStore; @@ -145,20 +157,24 @@ export class RootStore { this.moduleIssue = new ModuleIssueStore(this); this.moduleFilter = new ModuleFilterStore(this); this.moduleIssueKanBanView = new ModuleIssueKanBanViewStore(this); + this.moduleIssueCalendarView = new ModuleIssueCalendarViewStore(this); this.cycle = new CycleStore(this); this.cycleIssue = new CycleIssueStore(this); this.cycleIssueFilter = new CycleIssueFilterStore(this); this.cycleIssueKanBanView = new CycleIssueKanBanViewStore(this); + this.cycleIssueCalendarView = new CycleIssueCalendarViewStore(this); this.projectViews = new ProjectViewsStore(this); this.projectViewIssues = new ProjectViewIssuesStore(this); this.projectViewFilters = new ProjectViewFiltersStore(this); + this.projectViewIssueCalendarView = new ProjectViewIssueCalendarViewStore(this); this.issue = new IssueStore(this); this.issueFilter = new IssueFilterStore(this); this.issueDetail = new IssueDetailStore(this); this.issueKanBanView = new IssueKanBanViewStore(this); + this.issueCalendarView = new IssueCalendarViewStore(this); this.draftIssuesStore = new DraftIssuesStore(this); this.calendar = new CalendarStore(this); From ca2da41dd2cef3d9d979a506302a55eb3316532e Mon Sep 17 00:00:00 2001 From: guru_sainath Date: Wed, 25 Oct 2023 19:24:14 +0530 Subject: [PATCH 03/17] chore: issue comment reaction workflow and mutation update (#2537) --- .../issue-peek-overview/activity/card.tsx | 3 + .../activity/comment-card.tsx | 3 + .../activity/comment-reaction.tsx | 19 +++-- .../issue-peek-overview/activity/view.tsx | 3 + .../issue-peek-overview/reactions/root.tsx | 2 +- .../issues/issue-peek-overview/root.tsx | 4 +- .../issues/issue-peek-overview/view.tsx | 2 + web/store/issue/issue_detail.store.ts | 73 +++++++++++++------ 8 files changed, 75 insertions(+), 34 deletions(-) diff --git a/web/components/issues/issue-peek-overview/activity/card.tsx b/web/components/issues/issue-peek-overview/activity/card.tsx index b66b5754f..8fbf8605a 100644 --- a/web/components/issues/issue-peek-overview/activity/card.tsx +++ b/web/components/issues/issue-peek-overview/activity/card.tsx @@ -12,6 +12,7 @@ import { render24HourFormatTime, renderLongDateFormat, timeAgo } from "helpers/d interface IssueActivityCard { workspaceSlug: string; projectId: string; + issueId: string; user: any; issueComments: any; issueCommentUpdate: (comment: any) => void; @@ -24,6 +25,7 @@ export const IssueActivityCard: FC = (props) => { const { workspaceSlug, projectId, + issueId, user, issueComments, issueCommentUpdate, @@ -118,6 +120,7 @@ export const IssueActivityCard: FC = (props) => { void; issueCommentReactionRemove: (commentId: string, reaction: string) => void; @@ -36,6 +37,7 @@ export const IssueCommentCard: React.FC = (props) => { showAccessSpecifier = false, workspaceSlug, projectId, + issueId, user, issueCommentReactionCreate, issueCommentReactionRemove, @@ -157,6 +159,7 @@ export const IssueCommentCard: React.FC = (props) => { = observer((props) => { - const { workspaceSlug, projectId, user, comment, issueCommentReactionCreate, issueCommentReactionRemove } = props; + const { workspaceSlug, projectId, issueId, user, comment, issueCommentReactionCreate, issueCommentReactionRemove } = + props; const { issueDetail: issueDetailStore }: RootStore = useMobxStore(); @@ -32,15 +34,18 @@ export const IssueCommentReaction: FC = observer((props) }; useSWR( - workspaceSlug && projectId && comment && comment?.id ? `ISSUE+PEEK_OVERVIEW_COMMENT_${comment?.id}` : null, + workspaceSlug && projectId && issueId && comment && comment?.id + ? `ISSUE+PEEK_OVERVIEW_COMMENT_${comment?.id}` + : null, () => { - if (workspaceSlug && projectId && comment && comment.id) { - issueDetailStore.fetchIssueCommentReactions(workspaceSlug, projectId, comment?.id); + if (workspaceSlug && projectId && issueId && comment && comment.id) { + issueDetailStore.fetchIssueCommentReactions(workspaceSlug, projectId, issueId, comment?.id); } } ); - const issueReactions = issueDetailStore?.getIssueCommentReactionsByCommentId(comment.id) || []; + let issueReactions = issueDetailStore?.getIssueCommentReactions || null; + issueReactions = issueReactions && comment.id ? issueReactions?.[comment.id] : []; return (
diff --git a/web/components/issues/issue-peek-overview/activity/view.tsx b/web/components/issues/issue-peek-overview/activity/view.tsx index f5db0f297..d7f9bcf92 100644 --- a/web/components/issues/issue-peek-overview/activity/view.tsx +++ b/web/components/issues/issue-peek-overview/activity/view.tsx @@ -6,6 +6,7 @@ import { IssueCommentEditor } from "./comment-editor"; interface IIssueComment { workspaceSlug: string; projectId: string; + issueId: string; user: any; issueComments: any; issueCommentCreate: (comment: any) => void; @@ -19,6 +20,7 @@ export const IssueComment: FC = (props) => { const { workspaceSlug, projectId, + issueId, user, issueComments, issueCommentCreate, @@ -46,6 +48,7 @@ export const IssueComment: FC = (props) => { = (props) => { const handleReaction = (reaction: string) => { const isReactionAvailable = - issueReactions[reaction].find((_reaction: any) => _reaction.actor === user?.id) ?? false; + issueReactions?.[reaction].find((_reaction: any) => _reaction.actor === user?.id) ?? false; if (isReactionAvailable) issueReactionRemove(reaction); else issueReactionCreate(reaction); diff --git a/web/components/issues/issue-peek-overview/root.tsx b/web/components/issues/issue-peek-overview/root.tsx index 8b96a3100..e94b728c0 100644 --- a/web/components/issues/issue-peek-overview/root.tsx +++ b/web/components/issues/issue-peek-overview/root.tsx @@ -50,10 +50,10 @@ export const IssuePeekOverview: FC = observer((props) => { issueDetailStore.removeIssueComment(workspaceSlug, projectId, issueId, commentId); const issueCommentReactionCreate = (commentId: string, reaction: string) => - issueDetailStore.creationIssueCommentReaction(workspaceSlug, projectId, commentId, reaction); + issueDetailStore.creationIssueCommentReaction(workspaceSlug, projectId, issueId, commentId, reaction); const issueCommentReactionRemove = (commentId: string, reaction: string) => - issueDetailStore.removeIssueCommentReaction(workspaceSlug, projectId, commentId, reaction); + issueDetailStore.removeIssueCommentReaction(workspaceSlug, projectId, issueId, commentId, reaction); return ( = observer((props) => { = observer((props) => { void; @@ -31,7 +33,7 @@ export interface IIssueDetailStore { getIssue: IIssue | null; getIssueReactions: any | null; getIssueComments: any | null; - getIssueCommentReactionsByCommentId: any | null; + getIssueCommentReactions: any | null; // fetch issue details fetchIssueDetails: (workspaceSlug: string, projectId: string, issueId: string) => Promise; @@ -59,16 +61,23 @@ export interface IIssueDetailStore { ) => Promise; removeIssueComment: (workspaceSlug: string, projectId: string, issueId: string, commentId: string) => Promise; - fetchIssueCommentReactions: (workspaceSlug: string, projectId: string, commentId: string) => Promise; + fetchIssueCommentReactions: ( + workspaceSlug: string, + projectId: string, + issueId: string, + commentId: string + ) => Promise; creationIssueCommentReaction: ( workspaceSlug: string, projectId: string, + issueId: string, commentId: string, reaction: string ) => Promise; removeIssueCommentReaction: ( workspaceSlug: string, projectId: string, + issueId: string, commentId: string, reaction: string ) => Promise; @@ -114,11 +123,10 @@ export class IssueDetailStore implements IIssueDetailStore { getIssue: computed, getIssueReactions: computed, getIssueComments: computed, + getIssueCommentReactions: computed, setPeekId: action, - getIssueCommentReactionsByCommentId: action, - fetchIssueDetails: action, createIssue: action, updateIssue: action, @@ -164,11 +172,11 @@ export class IssueDetailStore implements IIssueDetailStore { return _comments || null; } - getIssueCommentReactionsByCommentId = (commentId: string) => { - if (!commentId) return null; - const _reactions = this.issue_comment_reactions[commentId]; - return _reactions || null; - }; + get getIssueCommentReactions() { + if (!this.peekId) return null; + const _commentReactions = this.issue_comment_reactions[this.peekId]; + return _commentReactions || null; + } setPeekId = (issueId: string | null) => (this.peekId = issueId); @@ -513,13 +521,16 @@ export class IssueDetailStore implements IIssueDetailStore { }; // comment reaction - fetchIssueCommentReactions = async (workspaceSlug: string, projectId: string, commentId: string) => { + fetchIssueCommentReactions = async (workspaceSlug: string, projectId: string, issueId: string, commentId: string) => { try { const _reactions = await this.issueReactionService.listIssueCommentReactions(workspaceSlug, projectId, commentId); const _issue_comment_reactions = { ...this.issue_comment_reactions, - [commentId]: groupReactionEmojis(_reactions), + [issueId]: { + ...this.issue_comment_reactions[issueId], + [commentId]: groupReactionEmojis(_reactions), + }, }; runInAction(() => { @@ -533,10 +544,12 @@ export class IssueDetailStore implements IIssueDetailStore { creationIssueCommentReaction = async ( workspaceSlug: string, projectId: string, + issueId: string, commentId: string, reaction: string ) => { - let _currentReactions = this.getIssueCommentReactionsByCommentId(commentId); + let _currentReactions = this.getIssueCommentReactions; + _currentReactions = _currentReactions && commentId ? _currentReactions?.[commentId] : null; try { const _reaction = await this.issueReactionService.createIssueCommentReaction( @@ -550,14 +563,19 @@ export class IssueDetailStore implements IIssueDetailStore { _currentReactions = { ..._currentReactions, - [reaction]: [..._currentReactions[reaction], { ..._reaction }], + [reaction]: [..._currentReactions?.[reaction], { ..._reaction }], + }; + + const _issue_comment_reactions = { + ...this.issue_comment_reactions, + [issueId]: { + ...this.issue_comment_reactions[issueId], + [commentId]: _currentReactions, + }, }; runInAction(() => { - this.issue_comment_reactions = { - ...this.issue_comment_reactions, - [commentId]: _currentReactions, - }; + this.issue_comment_reactions = _issue_comment_reactions; }); } catch (error) { console.warn("error removing the issue comment", error); @@ -567,10 +585,12 @@ export class IssueDetailStore implements IIssueDetailStore { removeIssueCommentReaction = async ( workspaceSlug: string, projectId: string, + issueId: string, commentId: string, reaction: string ) => { - let _currentReactions = this.getIssueCommentReactionsByCommentId(commentId); + let _currentReactions = this.getIssueCommentReactions; + _currentReactions = _currentReactions && commentId ? _currentReactions?.[commentId] : null; try { const user = this.rootStore.user.currentUser; @@ -578,14 +598,19 @@ export class IssueDetailStore implements IIssueDetailStore { if (user) { _currentReactions = { ..._currentReactions, - [reaction]: [..._currentReactions[reaction].filter((r: any) => r.actor !== user.id)], + [reaction]: [..._currentReactions?.[reaction].filter((r: any) => r.actor !== user.id)], + }; + + const _issue_comment_reactions = { + ...this.issue_comment_reactions, + [issueId]: { + ...this.issue_comment_reactions[issueId], + [commentId]: _currentReactions, + }, }; runInAction(() => { - this.issue_comment_reactions = { - ...this.issue_comment_reactions, - [commentId]: _currentReactions, - }; + this.issue_comment_reactions = _issue_comment_reactions; }); await this.issueReactionService.deleteIssueCommentReaction(workspaceSlug, projectId, commentId, reaction); From a49f00bd39eb463a361926cdcb84dc7eed049e74 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Wed, 25 Oct 2023 19:47:58 +0530 Subject: [PATCH 04/17] chore: refactor and beautify issue properties (#2539) * chore: update all issue property components * style: issue properties --- web/components/estimates/estimate-select.tsx | 160 ++++++++ .../estimates/{index.tsx => index.ts} | 3 +- .../issues/issue-layouts/kanban/block.tsx | 27 +- .../issue-layouts/kanban/blocks-list.tsx | 24 +- .../issues/issue-layouts/kanban/default.tsx | 57 ++- .../issues/issue-layouts/kanban/index.ts | 4 +- .../issue-layouts/kanban/properties.tsx | 362 +++++++++--------- .../kanban/{ => roots}/cycle-root.tsx | 31 +- .../issue-layouts/kanban/roots/index.ts | 5 + .../kanban/{ => roots}/module-root.tsx | 25 +- .../{ => roots}/profile-issues-root.tsx | 13 +- .../{root.tsx => roots/project-root.tsx} | 29 +- .../project-view-root.tsx} | 6 +- .../issues/issue-layouts/kanban/swimlanes.tsx | 57 ++- .../issues/issue-layouts/list/block.tsx | 17 +- .../issues/issue-layouts/list/blocks-list.tsx | 14 +- .../issues/issue-layouts/list/default.tsx | 28 +- .../issues/issue-layouts/list/index.ts | 4 +- .../issues/issue-layouts/list/properties.tsx | 103 +++-- .../list/{ => roots}/cycle-root.tsx | 19 +- .../issues/issue-layouts/list/roots/index.ts | 5 + .../list/{ => roots}/module-root.tsx | 19 +- .../list/{ => roots}/profile-issues-root.tsx | 7 +- .../list/{root.tsx => roots/project-root.tsx} | 19 +- .../project-view-root.tsx} | 4 +- .../issue-layouts/properties/assignee.tsx | 256 +------------ .../issues/issue-layouts/properties/date.tsx | 140 ++++--- .../issue-layouts/properties/estimates.tsx | 229 +---------- .../issue-layouts/properties/labels.tsx | 234 +---------- .../issue-layouts/properties/priority.tsx | 226 +---------- .../issues/issue-layouts/properties/state.tsx | 214 +---------- .../spreadsheet/columns/state-column.tsx | 6 +- .../issues/issue-peek-overview/properties.tsx | 38 +- .../issues/sub-issues/properties.tsx | 6 +- web/components/project/label-select.tsx | 270 ++++++------- web/components/project/members-select.tsx | 27 +- web/components/project/priority-select.tsx | 80 ++-- web/components/states/state-select.tsx | 33 +- web/layouts/auth-layout/project-wrapper.tsx | 8 +- .../profile/[userId]/assigned.tsx | 4 +- 40 files changed, 1066 insertions(+), 1747 deletions(-) create mode 100644 web/components/estimates/estimate-select.tsx rename web/components/estimates/{index.tsx => index.ts} (77%) rename web/components/issues/issue-layouts/kanban/{ => roots}/cycle-root.tsx (83%) create mode 100644 web/components/issues/issue-layouts/kanban/roots/index.ts rename web/components/issues/issue-layouts/kanban/{ => roots}/module-root.tsx (85%) rename web/components/issues/issue-layouts/kanban/{ => roots}/profile-issues-root.tsx (94%) rename web/components/issues/issue-layouts/kanban/{root.tsx => roots/project-root.tsx} (82%) rename web/components/issues/issue-layouts/kanban/{view-root.tsx => roots/project-view-root.tsx} (95%) rename web/components/issues/issue-layouts/list/{ => roots}/cycle-root.tsx (80%) create mode 100644 web/components/issues/issue-layouts/list/roots/index.ts rename web/components/issues/issue-layouts/list/{ => roots}/module-root.tsx (80%) rename web/components/issues/issue-layouts/list/{ => roots}/profile-issues-root.tsx (95%) rename web/components/issues/issue-layouts/list/{root.tsx => roots/project-root.tsx} (77%) rename web/components/issues/issue-layouts/list/{view-root.tsx => roots/project-view-root.tsx} (94%) diff --git a/web/components/estimates/estimate-select.tsx b/web/components/estimates/estimate-select.tsx new file mode 100644 index 000000000..5ac283b83 --- /dev/null +++ b/web/components/estimates/estimate-select.tsx @@ -0,0 +1,160 @@ +import React, { useState } from "react"; +import { usePopper } from "react-popper"; +import { Combobox } from "@headlessui/react"; +import { Check, ChevronDown, Search, Triangle } from "lucide-react"; +// types +import { Tooltip } from "components/ui"; +import { Placement } from "@popperjs/core"; +// constants +import { IEstimatePoint } from "types"; + +type Props = { + value: number | null; + onChange: (value: number | null) => void; + estimatePoints: IEstimatePoint[] | undefined; + className?: string; + buttonClassName?: string; + optionsClassName?: string; + placement?: Placement; + hideDropdownArrow?: boolean; + disabled?: boolean; +}; + +export const EstimateSelect: React.FC = (props) => { + const { + value, + onChange, + estimatePoints, + className = "", + buttonClassName = "", + optionsClassName = "", + placement, + hideDropdownArrow = false, + disabled = false, + } = props; + + const [query, setQuery] = useState(""); + + const [referenceElement, setReferenceElement] = useState(null); + const [popperElement, setPopperElement] = useState(null); + + const { styles, attributes } = usePopper(referenceElement, popperElement, { + placement: placement ?? "bottom-start", + modifiers: [ + { + name: "preventOverflow", + options: { + padding: 12, + }, + }, + ], + }); + + const options: { value: number | null; query: string; content: any }[] | undefined = estimatePoints?.map( + (estimate) => ({ + value: estimate.key, + query: estimate.value, + content: ( +
+ + {estimate.value} +
+ ), + }) + ); + options?.unshift({ + value: null, + query: "none", + content: ( +
+ + None +
+ ), + }); + + const filteredOptions = + query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); + + const selectedEstimate = estimatePoints?.find((e) => e.key === value); + const label = ( + +
+ + {selectedEstimate?.value ?? "None"} +
+
+ ); + + return ( + onChange(val as number | null)} + disabled={disabled} + > + + + + +
+
+ + setQuery(e.target.value)} + placeholder="Search" + displayValue={(assigned: any) => assigned?.name} + /> +
+
+ {filteredOptions ? ( + filteredOptions.length > 0 ? ( + filteredOptions.map((option) => ( + + `flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 ${ + active ? "bg-custom-background-80" : "" + } ${selected ? "text-custom-text-100" : "text-custom-text-200"}` + } + > + {({ selected }) => ( + <> + {option.content} + {selected && } + + )} + + )) + ) : ( + +

No matching results

+
+ ) + ) : ( +

Loading...

+ )} +
+
+
+
+ ); +}; diff --git a/web/components/estimates/index.tsx b/web/components/estimates/index.ts similarity index 77% rename from web/components/estimates/index.tsx rename to web/components/estimates/index.ts index f20c74780..b88ceaf03 100644 --- a/web/components/estimates/index.tsx +++ b/web/components/estimates/index.ts @@ -1,3 +1,4 @@ export * from "./create-update-estimate-modal"; -export * from "./single-estimate"; export * from "./delete-estimate-modal"; +export * from "./estimate-select"; +export * from "./single-estimate"; diff --git a/web/components/issues/issue-layouts/kanban/block.tsx b/web/components/issues/issue-layouts/kanban/block.tsx index 34f0a550e..505da1da3 100644 --- a/web/components/issues/issue-layouts/kanban/block.tsx +++ b/web/components/issues/issue-layouts/kanban/block.tsx @@ -2,7 +2,7 @@ import { Draggable } from "@hello-pangea/dnd"; // components import { KanBanProperties } from "./properties"; // types -import { IIssue } from "types"; +import { IEstimatePoint, IIssue, IIssueLabels, IState, IUserLite } from "types"; interface IssueBlockProps { sub_group_id: string; @@ -18,10 +18,27 @@ interface IssueBlockProps { ) => void; quickActions: (sub_group_by: string | null, group_by: string | null, issue: IIssue) => React.ReactNode; displayProperties: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + estimates: IEstimatePoint[] | null; } export const KanbanIssueBlock: React.FC = (props) => { - const { sub_group_id, columnId, index, issue, isDragDisabled, handleIssues, quickActions, displayProperties } = props; + const { + sub_group_id, + columnId, + index, + issue, + isDragDisabled, + handleIssues, + quickActions, + displayProperties, + states, + labels, + members, + estimates, + } = props; const updateIssue = (sub_group_by: string | null, group_by: string | null, issueToUpdate: IIssue) => { if (issueToUpdate) handleIssues(sub_group_by, group_by, issueToUpdate, "update"); @@ -54,7 +71,7 @@ export const KanbanIssueBlock: React.FC = (props) => { {issue.project_detail.identifier}-{issue.sequence_id}
)} -
{issue.name}
+
{issue.name}
= (props) => { issue={issue} handleIssues={updateIssue} display_properties={displayProperties} + states={states} + labels={labels} + members={members} + estimates={estimates} />
diff --git a/web/components/issues/issue-layouts/kanban/blocks-list.tsx b/web/components/issues/issue-layouts/kanban/blocks-list.tsx index aeee5c2fc..0e921638a 100644 --- a/web/components/issues/issue-layouts/kanban/blocks-list.tsx +++ b/web/components/issues/issue-layouts/kanban/blocks-list.tsx @@ -1,6 +1,6 @@ // components import { KanbanIssueBlock } from "components/issues"; -import { IIssue } from "types"; +import { IEstimatePoint, IIssue, IIssueLabels, IState, IUserLite } from "types"; interface IssueBlocksListProps { sub_group_id: string; @@ -15,10 +15,26 @@ interface IssueBlocksListProps { ) => void; quickActions: (sub_group_by: string | null, group_by: string | null, issue: IIssue) => React.ReactNode; display_properties: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + estimates: IEstimatePoint[] | null; } export const KanbanIssueBlocksList: React.FC = (props) => { - const { sub_group_id, columnId, issues, isDragDisabled, handleIssues, quickActions, display_properties } = props; + const { + sub_group_id, + columnId, + issues, + isDragDisabled, + handleIssues, + quickActions, + display_properties, + states, + labels, + members, + estimates, + } = props; return ( <> @@ -35,6 +51,10 @@ export const KanbanIssueBlocksList: React.FC = (props) => columnId={columnId} sub_group_id={sub_group_id} isDragDisabled={isDragDisabled} + states={states} + labels={labels} + members={members} + estimates={estimates} /> ))} diff --git a/web/components/issues/issue-layouts/kanban/default.tsx b/web/components/issues/issue-layouts/kanban/default.tsx index 691e50fb9..dd781a289 100644 --- a/web/components/issues/issue-layouts/kanban/default.tsx +++ b/web/components/issues/issue-layouts/kanban/default.tsx @@ -7,7 +7,7 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { KanBanGroupByHeaderRoot } from "./headers/group-by-root"; import { KanbanIssueBlocksList } from "components/issues"; // types -import { IIssue } from "types"; +import { IEstimatePoint, IIssue, IIssueLabels, IProject, IState, IUserLite } from "types"; // constants import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES, getValueFromObject } from "constants/issue"; @@ -29,6 +29,11 @@ export interface IGroupByKanBan { display_properties: any; kanBanToggle: any; handleKanBanToggle: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + priorities: any; + estimates: IEstimatePoint[] | null; } const GroupByKanBan: React.FC = observer((props) => { @@ -45,6 +50,11 @@ const GroupByKanBan: React.FC = observer((props) => { display_properties, kanBanToggle, handleKanBanToggle, + states, + labels, + members, + priorities, + estimates, } = props; const verticalAlignPosition = (_list: any) => @@ -93,6 +103,10 @@ const GroupByKanBan: React.FC = observer((props) => { handleIssues={handleIssues} quickActions={quickActions} display_properties={display_properties} + states={states} + labels={labels} + members={members} + estimates={estimates} /> ) : ( isDragDisabled && ( @@ -128,14 +142,13 @@ export interface IKanBan { display_properties: any; kanBanToggle: any; handleKanBanToggle: any; - - states: any; + states: IState[] | null; stateGroups: any; priorities: any; - labels: any; - members: any; - projects: any; - estimates: any; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + projects: IProject[] | null; + estimates: IEstimatePoint[] | null; } export const KanBan: React.FC = observer((props) => { @@ -176,6 +189,11 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + priorities={priorities} + estimates={estimates} /> )} @@ -193,6 +211,11 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + priorities={priorities} + estimates={estimates} /> )} @@ -210,6 +233,11 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + priorities={priorities} + estimates={estimates} /> )} @@ -227,6 +255,11 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + priorities={priorities} + estimates={estimates} /> )} @@ -244,6 +277,11 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + priorities={priorities} + estimates={estimates} /> )} @@ -261,6 +299,11 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + priorities={priorities} + estimates={estimates} /> )}
diff --git a/web/components/issues/issue-layouts/kanban/index.ts b/web/components/issues/issue-layouts/kanban/index.ts index 3adfe5c26..f84f7c8af 100644 --- a/web/components/issues/issue-layouts/kanban/index.ts +++ b/web/components/issues/issue-layouts/kanban/index.ts @@ -1,5 +1,3 @@ export * from "./block"; +export * from "./roots"; export * from "./blocks-list"; -export * from "./cycle-root"; -export * from "./module-root"; -export * from "./root"; diff --git a/web/components/issues/issue-layouts/kanban/properties.tsx b/web/components/issues/issue-layouts/kanban/properties.tsx index 979ead23b..e321094d4 100644 --- a/web/components/issues/issue-layouts/kanban/properties.tsx +++ b/web/components/issues/issue-layouts/kanban/properties.tsx @@ -10,190 +10,196 @@ import { IssuePropertyAssignee } from "../properties/assignee"; import { IssuePropertyEstimates } from "../properties/estimates"; import { IssuePropertyDate } from "../properties/date"; import { Tooltip } from "@plane/ui"; +import { IEstimatePoint, IIssue, IIssueLabels, IState, IUserLite, TIssuePriorities } from "types"; export interface IKanBanProperties { sub_group_id: string; columnId: string; - issue: any; - handleIssues?: (sub_group_by: string | null, group_by: string | null, issue: any) => void; + issue: IIssue; + handleIssues: (sub_group_by: string | null, group_by: string | null, issue: IIssue) => void; display_properties: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + estimates: IEstimatePoint[] | null; } -export const KanBanProperties: React.FC = observer( - ({ sub_group_id, columnId: group_id, issue, handleIssues, display_properties }) => { - const handleState = (id: string) => { - if (handleIssues) - handleIssues( - !sub_group_id && sub_group_id === "null" ? null : sub_group_id, - !group_id && group_id === "null" ? null : group_id, - { ...issue, state: id } - ); - }; +export const KanBanProperties: React.FC = observer((props) => { + const { + sub_group_id, + columnId: group_id, + issue, + handleIssues, + display_properties, + states, + labels, + members, + estimates, + } = props; - const handlePriority = (id: string) => { - if (handleIssues) - handleIssues( - !sub_group_id && sub_group_id === "null" ? null : sub_group_id, - !group_id && group_id === "null" ? null : group_id, - { ...issue, priority: id } - ); - }; - - const handleLabel = (ids: string[]) => { - if (handleIssues) - handleIssues( - !sub_group_id && sub_group_id === "null" ? null : sub_group_id, - !group_id && group_id === "null" ? null : group_id, - { ...issue, labels: ids } - ); - }; - - const handleAssignee = (ids: string[]) => { - if (handleIssues) - handleIssues( - !sub_group_id && sub_group_id === "null" ? null : sub_group_id, - !group_id && group_id === "null" ? null : group_id, - { ...issue, assignees: ids } - ); - }; - - const handleStartDate = (date: string) => { - if (handleIssues) - handleIssues( - !sub_group_id && sub_group_id === "null" ? null : sub_group_id, - !group_id && group_id === "null" ? null : group_id, - { ...issue, start_date: date } - ); - }; - - const handleTargetDate = (date: string) => { - if (handleIssues) - handleIssues( - !sub_group_id && sub_group_id === "null" ? null : sub_group_id, - !group_id && group_id === "null" ? null : group_id, - { ...issue, target_date: date } - ); - }; - - const handleEstimate = (id: string) => { - if (handleIssues) - handleIssues( - !sub_group_id && sub_group_id === "null" ? null : sub_group_id, - !group_id && group_id === "null" ? null : group_id, - { ...issue, estimate_point: id } - ); - }; - - return ( -
- {/* basic properties */} - {/* state */} - {display_properties && display_properties?.state && ( - handleState(id)} - disabled={false} - /> - )} - - {/* priority */} - {display_properties && display_properties?.priority && ( - handlePriority(id)} - disabled={false} - /> - )} - - {/* label */} - {display_properties && display_properties?.labels && ( - handleLabel(ids)} - disabled={false} - /> - )} - - {/* assignee */} - {display_properties && display_properties?.assignee && ( - handleAssignee(ids)} - disabled={false} - /> - )} - - {/* start date */} - {display_properties && display_properties?.start_date && ( - handleStartDate(date)} - disabled={false} - /> - )} - - {/* target/due date */} - {display_properties && display_properties?.due_date && ( - handleTargetDate(date)} - disabled={false} - /> - )} - - {/* estimates */} - {display_properties && display_properties?.estimate && ( - handleEstimate(id)} - disabled={false} - workspaceSlug={issue?.workspace_detail?.slug || null} - projectId={issue?.project_detail?.id || null} - /> - )} - - {/* extra render properties */} - {/* sub-issues */} - {display_properties && display_properties?.sub_issue_count && ( - -
-
- -
-
{issue.sub_issues_count}
-
-
- )} - - {/* attachments */} - {display_properties && display_properties?.attachment_count && ( - -
-
- -
-
{issue.attachment_count}
-
-
- )} - - {/* link */} - {display_properties && display_properties?.link && ( - -
-
- -
-
{issue.link_count}
-
-
- )} -
+ const handleState = (state: IState) => { + handleIssues( + !sub_group_id && sub_group_id === "null" ? null : sub_group_id, + !group_id && group_id === "null" ? null : group_id, + { ...issue, state: state.id } ); - } -); + }; + + const handlePriority = (value: TIssuePriorities) => { + handleIssues( + !sub_group_id && sub_group_id === "null" ? null : sub_group_id, + !group_id && group_id === "null" ? null : group_id, + { ...issue, priority: value } + ); + }; + + const handleLabel = (ids: string[]) => { + handleIssues( + !sub_group_id && sub_group_id === "null" ? null : sub_group_id, + !group_id && group_id === "null" ? null : group_id, + { ...issue, labels_list: ids } + ); + }; + + const handleAssignee = (ids: string[]) => { + handleIssues( + !sub_group_id && sub_group_id === "null" ? null : sub_group_id, + !group_id && group_id === "null" ? null : group_id, + { ...issue, assignees_list: ids } + ); + }; + + const handleStartDate = (date: string) => { + handleIssues( + !sub_group_id && sub_group_id === "null" ? null : sub_group_id, + !group_id && group_id === "null" ? null : group_id, + { ...issue, start_date: date } + ); + }; + + const handleTargetDate = (date: string) => { + handleIssues( + !sub_group_id && sub_group_id === "null" ? null : sub_group_id, + !group_id && group_id === "null" ? null : group_id, + { ...issue, target_date: date } + ); + }; + + const handleEstimate = (value: number | null) => { + handleIssues( + !sub_group_id && sub_group_id === "null" ? null : sub_group_id, + !group_id && group_id === "null" ? null : group_id, + { ...issue, estimate_point: value } + ); + }; + + return ( +
+ {/* basic properties */} + {/* state */} + {display_properties && display_properties?.state && ( + + )} + + {/* priority */} + {display_properties && display_properties?.priority && ( + + )} + + {/* label */} + {display_properties && display_properties?.labels && ( + + )} + + {/* assignee */} + {display_properties && display_properties?.assignee && ( + + )} + + {/* start date */} + {display_properties && display_properties?.start_date && ( + handleStartDate(date)} + disabled={false} + placeHolder="Start date" + /> + )} + + {/* target/due date */} + {display_properties && display_properties?.due_date && ( + handleTargetDate(date)} + disabled={false} + placeHolder="Target date" + /> + )} + + {/* estimates */} + {display_properties && display_properties?.estimate && ( + + )} + + {/* extra render properties */} + {/* sub-issues */} + {display_properties && display_properties?.sub_issue_count && ( + +
+ +
{issue.sub_issues_count}
+
+
+ )} + + {/* attachments */} + {display_properties && display_properties?.attachment_count && ( + +
+ +
{issue.attachment_count}
+
+
+ )} + + {/* link */} + {display_properties && display_properties?.link && ( + +
+ +
{issue.link_count}
+
+
+ )} +
+ ); +}); diff --git a/web/components/issues/issue-layouts/kanban/cycle-root.tsx b/web/components/issues/issue-layouts/kanban/roots/cycle-root.tsx similarity index 83% rename from web/components/issues/issue-layouts/kanban/cycle-root.tsx rename to web/components/issues/issue-layouts/kanban/roots/cycle-root.tsx index f4d09aada..188e27a68 100644 --- a/web/components/issues/issue-layouts/kanban/cycle-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/cycle-root.tsx @@ -5,9 +5,11 @@ import { DragDropContext } from "@hello-pangea/dnd"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { KanBanSwimLanes } from "./swimlanes"; -import { KanBan } from "./default"; +import { KanBanSwimLanes } from "../swimlanes"; +import { KanBan } from "../default"; import { CycleIssueQuickActions } from "components/issues"; +// helpers +import { orderArrayBy } from "helpers/array.helper"; // types import { IIssue } from "types"; // constants @@ -25,7 +27,7 @@ export const CycleKanBanLayout: React.FC = observer(() => { } = useMobxStore(); const router = useRouter(); - const { workspaceSlug, cycleId } = router.query; + const { workspaceSlug, projectId, cycleId } = router.query; const issues = cycleIssueStore?.getIssues; @@ -60,12 +62,12 @@ export const CycleKanBanLayout: React.FC = observer(() => { if (!workspaceSlug || !cycleId) return; if (action === "update") { - cycleIssueStore.updateIssueStructure(group_by, null, issue); + cycleIssueStore.updateIssueStructure(group_by, sub_group_by, issue); issueDetailStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue); } - if (action === "delete") cycleIssueStore.deleteIssue(group_by, null, issue); + if (action === "delete") cycleIssueStore.deleteIssue(group_by, sub_group_by, issue); if (action === "remove" && issue.bridge_id) { - cycleIssueStore.deleteIssue(group_by, null, issue); + cycleIssueStore.deleteIssue(group_by, sub_group_by, issue); cycleIssueStore.removeIssueFromCycle( workspaceSlug.toString(), issue.project, @@ -81,13 +83,18 @@ export const CycleKanBanLayout: React.FC = observer(() => { cycleIssueKanBanViewStore.handleKanBanToggle(toggle, value); }; + 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 = projectStore?.projectStates || null; - const estimates = 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 (
@@ -113,9 +120,9 @@ export const CycleKanBanLayout: React.FC = observer(() => { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} /> ) : ( { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} /> )} diff --git a/web/components/issues/issue-layouts/kanban/roots/index.ts b/web/components/issues/issue-layouts/kanban/roots/index.ts new file mode 100644 index 000000000..139c09a7a --- /dev/null +++ b/web/components/issues/issue-layouts/kanban/roots/index.ts @@ -0,0 +1,5 @@ +export * from "./cycle-root"; +export * from "./module-root"; +export * from "./profile-issues-root"; +export * from "./project-root"; +export * from "./project-view-root"; diff --git a/web/components/issues/issue-layouts/kanban/module-root.tsx b/web/components/issues/issue-layouts/kanban/roots/module-root.tsx similarity index 85% rename from web/components/issues/issue-layouts/kanban/module-root.tsx rename to web/components/issues/issue-layouts/kanban/roots/module-root.tsx index 594f15757..754693d11 100644 --- a/web/components/issues/issue-layouts/kanban/module-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/module-root.tsx @@ -5,9 +5,11 @@ import { DragDropContext } from "@hello-pangea/dnd"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { KanBanSwimLanes } from "./swimlanes"; -import { KanBan } from "./default"; +import { KanBanSwimLanes } from "../swimlanes"; +import { KanBan } from "../default"; import { ModuleIssueQuickActions } from "components/issues"; +// helpers +import { orderArrayBy } from "helpers/array.helper"; // types import { IIssue } from "types"; // constants @@ -25,7 +27,7 @@ export const ModuleKanBanLayout: React.FC = observer(() => { } = useMobxStore(); const router = useRouter(); - const { workspaceSlug, moduleId } = router.query; + const { workspaceSlug, projectId, moduleId } = router.query; const issues = moduleIssueStore?.getIssues; @@ -81,13 +83,18 @@ export const ModuleKanBanLayout: React.FC = observer(() => { moduleIssueKanBanViewStore.handleKanBanToggle(toggle, value); }; + 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 = projectStore?.projectStates || null; - const estimates = 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 (
@@ -113,9 +120,9 @@ export const ModuleKanBanLayout: React.FC = observer(() => { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} /> ) : ( { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} /> )} diff --git a/web/components/issues/issue-layouts/kanban/profile-issues-root.tsx b/web/components/issues/issue-layouts/kanban/roots/profile-issues-root.tsx similarity index 94% rename from web/components/issues/issue-layouts/kanban/profile-issues-root.tsx rename to web/components/issues/issue-layouts/kanban/roots/profile-issues-root.tsx index badcd04aa..d2346120a 100644 --- a/web/components/issues/issue-layouts/kanban/profile-issues-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/profile-issues-root.tsx @@ -5,8 +5,8 @@ import { DragDropContext } from "@hello-pangea/dnd"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { KanBanSwimLanes } from "./swimlanes"; -import { KanBan } from "./default"; +import { KanBanSwimLanes } from "../swimlanes"; +import { KanBan } from "../default"; import { ProjectIssueQuickActions } from "components/issues"; // constants import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue"; @@ -79,7 +79,6 @@ export const ProfileIssuesKanBanLayout: FC = observer(() => { const members = projectStore?.projectMembers || null; const stateGroups = ISSUE_STATE_GROUPS || null; const projects = projectStore?.workspaceProjects || null; - const estimates = null; return (
@@ -104,9 +103,9 @@ export const ProfileIssuesKanBanLayout: FC = observer(() => { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={null} /> ) : ( { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={null} /> )} diff --git a/web/components/issues/issue-layouts/kanban/root.tsx b/web/components/issues/issue-layouts/kanban/roots/project-root.tsx similarity index 82% rename from web/components/issues/issue-layouts/kanban/root.tsx rename to web/components/issues/issue-layouts/kanban/roots/project-root.tsx index 741e878a0..fb375b382 100644 --- a/web/components/issues/issue-layouts/kanban/root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/project-root.tsx @@ -1,13 +1,15 @@ -import { FC, useCallback } from "react"; +import { useCallback } from "react"; import { useRouter } from "next/router"; import { DragDropContext } from "@hello-pangea/dnd"; import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { KanBanSwimLanes } from "./swimlanes"; -import { KanBan } from "./default"; +import { KanBanSwimLanes } from "../swimlanes"; +import { KanBan } from "../default"; import { ProjectIssueQuickActions } from "components/issues"; +// helpers +import { orderArrayBy } from "helpers/array.helper"; // types import { IIssue } from "types"; // constants @@ -15,9 +17,9 @@ import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue"; export interface IKanBanLayout {} -export const KanBanLayout: FC = observer(() => { +export const KanBanLayout: React.FC = observer(() => { const router = useRouter(); - const { workspaceSlug } = router.query; + const { workspaceSlug, projectId } = router.query; const { project: projectStore, @@ -72,13 +74,18 @@ export const KanBanLayout: FC = observer(() => { issueKanBanViewStore.handleKanBanToggle(toggle, value); }; + 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 = projectStore?.projectStates || null; - const estimates = 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 (
@@ -103,9 +110,9 @@ export const KanBanLayout: FC = observer(() => { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} /> ) : ( { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} /> )} diff --git a/web/components/issues/issue-layouts/kanban/view-root.tsx b/web/components/issues/issue-layouts/kanban/roots/project-view-root.tsx similarity index 95% rename from web/components/issues/issue-layouts/kanban/view-root.tsx rename to web/components/issues/issue-layouts/kanban/roots/project-view-root.tsx index 78117da80..583835ba3 100644 --- a/web/components/issues/issue-layouts/kanban/view-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/project-view-root.tsx @@ -4,8 +4,8 @@ import { DragDropContext } from "@hello-pangea/dnd"; // mobx import { observer } from "mobx-react-lite"; // components -import { KanBanSwimLanes } from "./swimlanes"; -import { KanBan } from "./default"; +import { KanBanSwimLanes } from "../swimlanes"; +import { KanBan } from "../default"; // store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; @@ -14,7 +14,7 @@ import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue"; export interface IViewKanBanLayout {} -export const ViewKanBanLayout: React.FC = observer(() => { +export const ProjectViewKanBanLayout: React.FC = observer(() => { const { project: projectStore, issue: issueStore, diff --git a/web/components/issues/issue-layouts/kanban/swimlanes.tsx b/web/components/issues/issue-layouts/kanban/swimlanes.tsx index 9090162c0..c46c6290b 100644 --- a/web/components/issues/issue-layouts/kanban/swimlanes.tsx +++ b/web/components/issues/issue-layouts/kanban/swimlanes.tsx @@ -7,7 +7,7 @@ import { KanBanGroupByHeaderRoot } from "./headers/group-by-root"; import { KanBanSubGroupByHeaderRoot } from "./headers/sub-group-by-root"; import { KanBan } from "./default"; // types -import { IIssue } from "types"; +import { IEstimatePoint, IIssue, IIssueLabels, IProject, IState, IUserLite } from "types"; // constants import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES, getValueFromObject } from "constants/issue"; @@ -19,6 +19,11 @@ interface ISubGroupSwimlaneHeader { listKey: string; kanBanToggle: any; handleKanBanToggle: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + projects: IProject[] | null; + estimates: IEstimatePoint[] | null; } const SubGroupSwimlaneHeader: React.FC = ({ issues, @@ -71,13 +76,13 @@ interface ISubGroupSwimlane extends ISubGroupSwimlaneHeader { display_properties: any; kanBanToggle: any; handleKanBanToggle: any; - states: any; + states: IState[] | null; stateGroups: any; priorities: any; - labels: any; - members: any; - projects: any; - estimates: any; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + projects: IProject[] | null; + estimates: IEstimatePoint[] | null; } const SubGroupSwimlane: React.FC = observer((props) => { const { @@ -171,13 +176,13 @@ export interface IKanBanSwimLanes { display_properties: any; kanBanToggle: any; handleKanBanToggle: any; - states: any; + states: IState[] | null; stateGroups: any; priorities: any; - labels: any; - members: any; - projects: any; - estimates: any; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + projects: IProject[] | null; + estimates: IEstimatePoint[] | null; } export const KanBanSwimLanes: React.FC = observer((props) => { @@ -213,6 +218,11 @@ export const KanBanSwimLanes: React.FC = observer((props) => { listKey={`id`} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + projects={projects} + estimates={estimates} /> )} @@ -225,6 +235,11 @@ export const KanBanSwimLanes: React.FC = observer((props) => { listKey={`key`} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + projects={projects} + estimates={estimates} /> )} @@ -237,6 +252,11 @@ export const KanBanSwimLanes: React.FC = observer((props) => { listKey={`key`} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + projects={projects} + estimates={estimates} /> )} @@ -249,6 +269,11 @@ export const KanBanSwimLanes: React.FC = observer((props) => { listKey={`id`} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + projects={projects} + estimates={estimates} /> )} @@ -261,6 +286,11 @@ export const KanBanSwimLanes: React.FC = observer((props) => { listKey={`member.id`} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + projects={projects} + estimates={estimates} /> )} @@ -273,6 +303,11 @@ export const KanBanSwimLanes: React.FC = observer((props) => { listKey={`member.id`} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + states={states} + labels={labels} + members={members} + projects={projects} + estimates={estimates} /> )}
diff --git a/web/components/issues/issue-layouts/list/block.tsx b/web/components/issues/issue-layouts/list/block.tsx index 47a1a38f0..9777f9ba5 100644 --- a/web/components/issues/issue-layouts/list/block.tsx +++ b/web/components/issues/issue-layouts/list/block.tsx @@ -4,7 +4,7 @@ import { IssuePeekOverview } from "components/issues/issue-peek-overview"; // ui import { Tooltip } from "@plane/ui"; // types -import { IIssue } from "types"; +import { IEstimatePoint, IIssue, IIssueLabels, IState, IUserLite } from "types"; interface IssueBlockProps { columnId: string; @@ -12,18 +12,17 @@ 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; - states: any; - labels: any; - members: any; - priorities: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + estimates: IEstimatePoint[] | null; } export const IssueBlock: React.FC = (props) => { - const { columnId, issue, handleIssues, quickActions, display_properties, states, labels, members, priorities } = - props; + const { columnId, issue, handleIssues, quickActions, display_properties, states, labels, members, estimates } = props; const updateIssue = (group_by: string | null, issueToUpdate: IIssue) => { - if (issueToUpdate && handleIssues) handleIssues(group_by, issueToUpdate, "update"); + handleIssues(group_by, issueToUpdate, "update"); }; return ( @@ -55,7 +54,7 @@ export const IssueBlock: React.FC = (props) => { states={states} labels={labels} members={members} - priorities={priorities} + estimates={estimates} /> {quickActions(!columnId && columnId === "null" ? null : columnId, issue)}
diff --git a/web/components/issues/issue-layouts/list/blocks-list.tsx b/web/components/issues/issue-layouts/list/blocks-list.tsx index 33618505f..3267e221c 100644 --- a/web/components/issues/issue-layouts/list/blocks-list.tsx +++ b/web/components/issues/issue-layouts/list/blocks-list.tsx @@ -2,7 +2,7 @@ import { FC } from "react"; // components import { IssueBlock } from "components/issues"; // types -import { IIssue } from "types"; +import { IEstimatePoint, IIssue, IIssueLabels, IState, IUserLite } from "types"; interface Props { columnId: string; @@ -10,14 +10,14 @@ interface Props { handleIssues: (group_by: string | null, issue: IIssue, action: "update" | "delete") => void; quickActions: (group_by: string | null, issue: IIssue) => React.ReactNode; display_properties: any; - states: any; - labels: any; - members: any; - priorities: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + estimates: IEstimatePoint[] | null; } export const IssueBlocksList: FC = (props) => { - const { columnId, issues, handleIssues, quickActions, display_properties, states, labels, members, priorities } = + const { columnId, issues, handleIssues, quickActions, display_properties, states, labels, members, estimates } = props; return ( @@ -35,7 +35,7 @@ export const IssueBlocksList: FC = (props) => { states={states} labels={labels} members={members} - priorities={priorities} + estimates={estimates} /> ))} diff --git a/web/components/issues/issue-layouts/list/default.tsx b/web/components/issues/issue-layouts/list/default.tsx index 008e625ae..e1c6caa16 100644 --- a/web/components/issues/issue-layouts/list/default.tsx +++ b/web/components/issues/issue-layouts/list/default.tsx @@ -2,11 +2,11 @@ import React from "react"; import { observer } from "mobx-react-lite"; // components import { ListGroupByHeaderRoot } from "./headers/group-by-root"; -import { IssueBlock } from "./block"; +import { IssueBlocksList } from "components/issues"; +// types +import { IEstimatePoint, IIssue, IIssueLabels, IProject, IState, IUserLite } from "types"; // constants import { getValueFromObject } from "constants/issue"; -import { IIssue } from "types"; -import { IssueBlocksList } from "./blocks-list"; export interface IGroupByList { issues: any; @@ -17,13 +17,13 @@ export interface IGroupByList { quickActions: (group_by: string | null, issue: IIssue) => React.ReactNode; display_properties: any; is_list?: boolean; - states: any; - labels: any; - members: any; - projects: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + projects: IProject[] | null; stateGroups: any; priorities: any; - estimates: any; + estimates: IEstimatePoint[] | null; } const GroupByList: React.FC = observer((props) => { @@ -72,7 +72,7 @@ const GroupByList: React.FC = observer((props) => { states={states} labels={labels} members={members} - priorities={priorities} + estimates={estimates} /> )}
@@ -90,13 +90,13 @@ export interface IList { handleIssues: (group_by: string | null, issue: IIssue, action: "update" | "delete") => void; quickActions: (group_by: string | null, issue: IIssue) => React.ReactNode; display_properties: any; - states: any; - labels: any; - members: any; - projects: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + projects: IProject[] | null; stateGroups: any; priorities: any; - estimates: any; + estimates: IEstimatePoint[] | null; } export const List: React.FC = observer((props) => { diff --git a/web/components/issues/issue-layouts/list/index.ts b/web/components/issues/issue-layouts/list/index.ts index 3adfe5c26..de9129b8f 100644 --- a/web/components/issues/issue-layouts/list/index.ts +++ b/web/components/issues/issue-layouts/list/index.ts @@ -1,5 +1,3 @@ +export * from "./roots"; export * from "./block"; export * from "./blocks-list"; -export * from "./cycle-root"; -export * from "./module-root"; -export * from "./root"; diff --git a/web/components/issues/issue-layouts/list/properties.tsx b/web/components/issues/issue-layouts/list/properties.tsx index 86af82656..9c70f9fdd 100644 --- a/web/components/issues/issue-layouts/list/properties.tsx +++ b/web/components/issues/issue-layouts/list/properties.tsx @@ -11,49 +11,48 @@ import { IssuePropertyDate } from "../properties/date"; // ui import { Tooltip } from "@plane/ui"; // types -import { IIssue } from "types"; +import { IEstimatePoint, IIssue, IIssueLabels, IState, IUserLite, TIssuePriorities } from "types"; export interface IKanBanProperties { columnId: string; - issue: any; - handleIssues?: (group_by: string | null, issue: IIssue) => void; + issue: IIssue; + handleIssues: (group_by: string | null, issue: IIssue) => void; display_properties: any; - states: any; - labels: any; - members: any; - priorities: any; + states: IState[] | null; + labels: IIssueLabels[] | null; + members: IUserLite[] | null; + estimates: IEstimatePoint[] | null; } export const KanBanProperties: FC = observer((props) => { - const { columnId: group_id, issue, handleIssues, display_properties, states, labels, members, priorities } = props; + const { columnId: group_id, issue, handleIssues, display_properties, states, labels, members, estimates } = props; - const handleState = (id: string) => { - if (handleIssues) handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, state: id }); + const handleState = (state: IState) => { + handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, state: state.id }); }; - const handlePriority = (id: string) => { - if (handleIssues) handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, priority: id }); + const handlePriority = (value: TIssuePriorities) => { + handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, priority: value }); }; const handleLabel = (ids: string[]) => { - if (handleIssues) handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, labels: ids }); + handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, labels_list: ids }); }; const handleAssignee = (ids: string[]) => { - if (handleIssues) handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, assignees: ids }); + handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, assignees_list: ids }); }; const handleStartDate = (date: string) => { - if (handleIssues) handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, start_date: date }); + handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, start_date: date }); }; const handleTargetDate = (date: string) => { - if (handleIssues) handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, target_date: date }); + handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, target_date: date }); }; - const handleEstimate = (id: string) => { - if (handleIssues) - handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, estimate_point: id }); + const handleEstimate = (value: number | null) => { + handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, estimate_point: value }); }; return ( @@ -62,22 +61,21 @@ export const KanBanProperties: FC = observer((props) => { {/* state */} {display_properties && display_properties?.state && states && ( handleState(id)} + value={issue?.state_detail || null} + hideDropdownArrow={true} + onChange={handleState} disabled={false} - list={states} + states={states} /> )} {/* priority */} - {display_properties && display_properties?.priority && priorities && ( + {display_properties && display_properties?.priority && ( handlePriority(id)} + onChange={handlePriority} disabled={false} - list={priorities} + hideDropdownArrow={true} /> )} @@ -85,10 +83,10 @@ export const KanBanProperties: FC = observer((props) => { {display_properties && display_properties?.labels && labels && ( handleLabel(ids)} + onChange={handleLabel} + labels={labels} disabled={false} - list={labels} + hideDropdownArrow={true} /> )} @@ -96,10 +94,10 @@ export const KanBanProperties: FC = observer((props) => { {display_properties && display_properties?.assignee && members && ( handleAssignee(ids)} + hideDropdownArrow={true} + onChange={handleAssignee} disabled={false} - list={members} + members={members} /> )} @@ -109,7 +107,7 @@ export const KanBanProperties: FC = observer((props) => { value={issue?.start_date || null} onChange={(date: string) => handleStartDate(date)} disabled={false} - placeHolder={`Start date`} + placeHolder="Start date" /> )} @@ -119,31 +117,28 @@ export const KanBanProperties: FC = observer((props) => { value={issue?.target_date || null} onChange={(date: string) => handleTargetDate(date)} disabled={false} - placeHolder={`Target date`} + placeHolder="Target date" /> )} {/* estimates */} {display_properties && display_properties?.estimate && ( handleEstimate(id)} + value={issue?.estimate_point || null} + estimatePoints={estimates} + hideDropdownArrow={true} + onChange={handleEstimate} disabled={false} - workspaceSlug={issue?.workspace_detail?.slug || null} - projectId={issue?.project_detail?.id || null} /> )} {/* extra render properties */} {/* sub-issues */} {display_properties && display_properties?.sub_issue_count && ( - -
-
- -
-
{issue.sub_issues_count}
+ +
+ +
{issue.sub_issues_count}
)} @@ -151,11 +146,9 @@ export const KanBanProperties: FC = observer((props) => { {/* attachments */} {display_properties && display_properties?.attachment_count && ( -
-
- -
-
{issue.attachment_count}
+
+ +
{issue.attachment_count}
)} @@ -163,11 +156,9 @@ export const KanBanProperties: FC = observer((props) => { {/* link */} {display_properties && display_properties?.link && ( -
-
- -
-
{issue.link_count}
+
+ +
{issue.link_count}
)} diff --git a/web/components/issues/issue-layouts/list/cycle-root.tsx b/web/components/issues/issue-layouts/list/roots/cycle-root.tsx similarity index 80% rename from web/components/issues/issue-layouts/list/cycle-root.tsx rename to web/components/issues/issue-layouts/list/roots/cycle-root.tsx index 511336531..771186c84 100644 --- a/web/components/issues/issue-layouts/list/cycle-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/cycle-root.tsx @@ -4,8 +4,10 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { List } from "./default"; +import { List } from "../default"; import { CycleIssueQuickActions } from "components/issues"; +// helpers +import { orderArrayBy } from "helpers/array.helper"; // types import { IIssue } from "types"; // constants @@ -15,7 +17,7 @@ export interface ICycleListLayout {} export const CycleListLayout: React.FC = observer(() => { const router = useRouter(); - const { workspaceSlug, cycleId } = router.query; + const { workspaceSlug, projectId, cycleId } = router.query; const { project: projectStore, @@ -52,13 +54,18 @@ export const CycleListLayout: React.FC = observer(() => { [cycleIssueStore, issueDetailStore, cycleId, workspaceSlug] ); + 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 = projectStore?.projectStates || null; - const estimates = 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 (
@@ -79,9 +86,9 @@ export const CycleListLayout: React.FC = observer(() => { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + 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 new file mode 100644 index 000000000..139c09a7a --- /dev/null +++ b/web/components/issues/issue-layouts/list/roots/index.ts @@ -0,0 +1,5 @@ +export * from "./cycle-root"; +export * from "./module-root"; +export * from "./profile-issues-root"; +export * from "./project-root"; +export * from "./project-view-root"; diff --git a/web/components/issues/issue-layouts/list/module-root.tsx b/web/components/issues/issue-layouts/list/roots/module-root.tsx similarity index 80% rename from web/components/issues/issue-layouts/list/module-root.tsx rename to web/components/issues/issue-layouts/list/roots/module-root.tsx index 485e4e908..daa12e64a 100644 --- a/web/components/issues/issue-layouts/list/module-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/module-root.tsx @@ -4,8 +4,10 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { List } from "./default"; +import { List } from "../default"; import { ModuleIssueQuickActions } from "components/issues"; +// helpers +import { orderArrayBy } from "helpers/array.helper"; // types import { IIssue } from "types"; // constants @@ -15,7 +17,7 @@ export interface IModuleListLayout {} export const ModuleListLayout: React.FC = observer(() => { const router = useRouter(); - const { workspaceSlug, moduleId } = router.query; + const { workspaceSlug, projectId, moduleId } = router.query; const { project: projectStore, @@ -52,13 +54,18 @@ export const ModuleListLayout: React.FC = observer(() => { [moduleIssueStore, issueDetailStore, moduleId, workspaceSlug] ); + 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 = projectStore?.projectStates || null; - const estimates = 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 (
@@ -79,9 +86,9 @@ export const ModuleListLayout: React.FC = observer(() => { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} />
); diff --git a/web/components/issues/issue-layouts/list/profile-issues-root.tsx b/web/components/issues/issue-layouts/list/roots/profile-issues-root.tsx similarity index 95% rename from web/components/issues/issue-layouts/list/profile-issues-root.tsx rename to web/components/issues/issue-layouts/list/roots/profile-issues-root.tsx index b1fb86c6a..9e4937ffd 100644 --- a/web/components/issues/issue-layouts/list/profile-issues-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/profile-issues-root.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { List } from "./default"; +import { List } from "../default"; import { ProjectIssueQuickActions } from "components/issues"; // types import { IIssue } from "types"; @@ -50,7 +50,6 @@ export const ProfileIssuesListLayout: FC = observer(() => { const members = projectStore?.projectMembers || null; const stateGroups = ISSUE_STATE_GROUPS || null; const projects = projectStore?.workspaceProjects || null; - const estimates = null; return (
@@ -70,9 +69,9 @@ export const ProfileIssuesListLayout: FC = observer(() => { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={null} />
); diff --git a/web/components/issues/issue-layouts/list/root.tsx b/web/components/issues/issue-layouts/list/roots/project-root.tsx similarity index 77% rename from web/components/issues/issue-layouts/list/root.tsx rename to web/components/issues/issue-layouts/list/roots/project-root.tsx index a5b1baa64..677e2f11c 100644 --- a/web/components/issues/issue-layouts/list/root.tsx +++ b/web/components/issues/issue-layouts/list/roots/project-root.tsx @@ -4,8 +4,10 @@ import { observer } from "mobx-react-lite"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; // components -import { List } from "./default"; +import { List } from "../default"; import { ProjectIssueQuickActions } from "components/issues"; +// helpers +import { orderArrayBy } from "helpers/array.helper"; // types import { IIssue } from "types"; // constants @@ -13,7 +15,7 @@ import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue"; export const ListLayout: FC = observer(() => { const router = useRouter(); - const { workspaceSlug } = router.query; + const { workspaceSlug, projectId } = router.query; const { project: projectStore, @@ -41,13 +43,18 @@ export const ListLayout: FC = observer(() => { [issueStore, issueDetailStore, workspaceSlug] ); + 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 = projectStore?.projectStates || null; - const estimates = 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 (
@@ -67,9 +74,9 @@ export const ListLayout: FC = observer(() => { stateGroups={stateGroups} priorities={priorities} labels={labels} - members={members} + members={members?.map((m) => m.member) ?? null} projects={projects} - estimates={estimates} + estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} />
); diff --git a/web/components/issues/issue-layouts/list/view-root.tsx b/web/components/issues/issue-layouts/list/roots/project-view-root.tsx similarity index 94% rename from web/components/issues/issue-layouts/list/view-root.tsx rename to web/components/issues/issue-layouts/list/roots/project-view-root.tsx index aa7ab563a..85b8177b3 100644 --- a/web/components/issues/issue-layouts/list/view-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/project-view-root.tsx @@ -1,7 +1,7 @@ import React from "react"; import { observer } from "mobx-react-lite"; // components -import { List } from "./default"; +import { List } from "../default"; // store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; @@ -10,7 +10,7 @@ import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue"; export interface IViewListLayout {} -export const ViewListLayout: React.FC = observer(() => { +export const ProjectViewListLayout: React.FC = observer(() => { const { project: projectStore, issue: issueStore, issueFilter: issueFilterStore }: RootStore = useMobxStore(); const issues = issueStore?.getIssues; diff --git a/web/components/issues/issue-layouts/properties/assignee.tsx b/web/components/issues/issue-layouts/properties/assignee.tsx index a235ec5a2..6a209f3b6 100644 --- a/web/components/issues/issue-layouts/properties/assignee.tsx +++ b/web/components/issues/issue-layouts/properties/assignee.tsx @@ -1,252 +1,28 @@ -import { FC, useRef, useState } from "react"; -import { Combobox } from "@headlessui/react"; -import { ChevronDown, Search, X, Check } from "lucide-react"; import { observer } from "mobx-react-lite"; // components -import { Tooltip } from "@plane/ui"; -// hooks -import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; - -interface IFiltersOption { - id: string; - title: string; - avatar: string; -} +import { MembersSelect } from "components/project"; +// types +import { IUserLite } from "types"; export interface IIssuePropertyAssignee { - value?: any; - onChange?: (id: any, data: any) => void; + value: string[]; + onChange: (data: string[]) => void; + members: IUserLite[] | null; disabled?: boolean; - list?: any; - - className?: string; - buttonClassName?: string; - optionsClassName?: string; - dropdownArrow?: boolean; + hideDropdownArrow?: boolean; } -export const IssuePropertyAssignee: FC = observer((props) => { - const { value, onChange, disabled, list, className, buttonClassName, optionsClassName, dropdownArrow = true } = props; - - const dropdownBtn = useRef(null); - const dropdownOptions = useRef(null); - - const [isOpen, setIsOpen] = useState(false); - const [search, setSearch] = useState(""); - - const options: IFiltersOption[] | [] = - (list && - list?.length > 0 && - list.map((_member: any) => ({ - id: _member?.member?.id, - title: _member?.member?.display_name, - avatar: _member?.member?.avatar && _member?.member?.avatar !== "" ? _member?.member?.avatar : null, - }))) || - []; - - useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); - - const selectedOption: IFiltersOption[] = - (value && value?.length > 0 && options.filter((_member: IFiltersOption) => value.includes(_member.id))) || []; - - const filteredOptions: IFiltersOption[] = - search === "" - ? options && options.length > 0 - ? options - : [] - : options && options.length > 0 - ? options.filter((_member: IFiltersOption) => - _member.title.toLowerCase().replace(/\s+/g, "").includes(search.toLowerCase().replace(/\s+/g, "")) - ) - : []; - - const assigneeRenderLength = 5; +export const IssuePropertyAssignee: React.FC = observer((props) => { + const { value, onChange, members, disabled = false, hideDropdownArrow = false } = props; return ( - _member.id) as string[]} - onChange={(data: string[]) => { - if (onChange && selectedOption) onChange(data, selectedOption); - }} + - {({ open }: { open: boolean }) => { - if (open) { - if (!isOpen) setIsOpen(true); - } else if (isOpen) setIsOpen(false); - - return ( - <> - - {selectedOption && selectedOption?.length > 0 ? ( - <> - {selectedOption?.length > 1 ? ( - _label.title) || []).join(", ")} - > -
- {selectedOption.slice(0, assigneeRenderLength).map((_assignee) => ( -
- {_assignee && _assignee.avatar ? ( - {_assignee.title} - ) : ( - _assignee.title[0] - )} -
- ))} - {selectedOption.length > assigneeRenderLength && ( -
- +{selectedOption?.length - assigneeRenderLength} -
- )} -
-
- ) : ( - _label.title) || []).join(", ")} - > -
-
- {selectedOption[0] && selectedOption[0].avatar ? ( - {selectedOption[0].title} - ) : ( -
- {selectedOption[0].title[0]} -
- )} -
-
{selectedOption[0].title}
-
-
- )} - - ) : ( - -
Select Assignees
-
- )} - - {dropdownArrow && !disabled && ( -
- -
- )} -
- -
- - {options && options.length > 0 ? ( - <> -
-
- -
- -
- setSearch(e.target.value)} - placeholder="Search" - displayValue={(assigned: any) => assigned?.name} - /> -
- - {search && search.length > 0 && ( -
setSearch("")} - className="flex-shrink-0 flex justify-center items-center w-[16px] h-[16px] rounded-sm cursor-pointer hover:bg-custom-background-80" - > - -
- )} -
- -
- {filteredOptions ? ( - filteredOptions.length > 0 ? ( - filteredOptions.map((option) => ( - - `cursor-pointer select-none truncate rounded px-1 py-1.5 ${ - active || (value && value.length > 0 && value.includes(option?.id)) - ? "bg-custom-background-80" - : "" - } ${ - value && value.length > 0 && value.includes(option?.id) - ? "text-custom-text-100" - : "text-custom-text-200" - }` - } - > -
-
- {option && option.avatar ? ( - {option.title} - ) : ( -
- {option.title[0]} -
- )} -
-
{option.title}
- {value && value.length > 0 && value.includes(option?.id) && ( -
- -
- )} -
-
- )) - ) : ( - -

No matching results

-
- ) - ) : ( -

Loading...

- )} -
- - ) : ( -

No options available.

- )} -
-
- - ); - }} -
+ hideDropdownArrow={hideDropdownArrow} + multiple + /> ); }); diff --git a/web/components/issues/issue-layouts/properties/date.tsx b/web/components/issues/issue-layouts/properties/date.tsx index 48b6de507..dbcbc0eac 100644 --- a/web/components/issues/issue-layouts/properties/date.tsx +++ b/web/components/issues/issue-layouts/properties/date.tsx @@ -15,85 +15,81 @@ import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; import { renderDateFormat } from "helpers/date-time.helper"; export interface IIssuePropertyDate { - value?: any; - onChange?: (date: any) => void; + value: any; + onChange: (date: any) => void; disabled?: boolean; placeHolder?: string; } -export const IssuePropertyDate: React.FC = observer( - ({ value, onChange, disabled, placeHolder }) => { - const dropdownBtn = React.useRef(null); - const dropdownOptions = React.useRef(null); +export const IssuePropertyDate: React.FC = observer((props) => { + const { value, onChange, disabled, placeHolder } = props; - const [isOpen, setIsOpen] = React.useState(false); + const dropdownBtn = React.useRef(null); + const dropdownOptions = React.useRef(null); - useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); + const [isOpen, setIsOpen] = React.useState(false); - return ( - - {({ open }) => { - if (open) { - if (!isOpen) setIsOpen(true); - } else if (isOpen) setIsOpen(false); + useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); - return ( - <> - - -
-
- -
- {value ? ( - <> -
{value}
-
{ - if (onChange) onChange(null); - }} - > - -
- - ) : ( -
{placeHolder ? placeHolder : `Select date`}
- )} -
-
-
+ return ( + + {({ open }) => { + if (open) { + if (!isOpen) setIsOpen(true); + } else if (isOpen) setIsOpen(false); -
- - {({ close }) => ( - { - if (onChange && val) { - onChange(renderDateFormat(val)); - close(); - } - }} - dateFormat="dd-MM-yyyy" - calendarClassName="h-full" - inline - /> + return ( + <> + + +
+ + {value && ( + <> +
{value}
+
{ + if (onChange) onChange(null); + }} + > + +
+ )} - -
- - ); - }} - - ); - } -); +
+ + + +
+ + {({ close }) => ( + { + if (onChange && val) { + onChange(renderDateFormat(val)); + close(); + } + }} + dateFormat="dd-MM-yyyy" + calendarClassName="h-full" + inline + /> + )} + +
+ + ); + }} +
+ ); +}); diff --git a/web/components/issues/issue-layouts/properties/estimates.tsx b/web/components/issues/issue-layouts/properties/estimates.tsx index 80b3d9615..83de934cb 100644 --- a/web/components/issues/issue-layouts/properties/estimates.tsx +++ b/web/components/issues/issue-layouts/properties/estimates.tsx @@ -1,217 +1,28 @@ -import React from "react"; -// headless ui -import { Combobox } from "@headlessui/react"; -// lucide icons -import { ChevronDown, Search, X, Check, Triangle } from "lucide-react"; -// mobx import { observer } from "mobx-react-lite"; // components -import { Tooltip } from "@plane/ui"; -// hooks -import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; -// mobx -import { useMobxStore } from "lib/mobx/store-provider"; -import { RootStore } from "store/root"; - -interface IFiltersOption { - id: string; - title: string; - key: string; -} +import { EstimateSelect } from "components/estimates"; +// types +import { IEstimatePoint } from "types"; export interface IIssuePropertyEstimates { - value?: any; - onChange?: (id: any) => void; + value: number | null; + onChange: (value: number | null) => void; + estimatePoints: IEstimatePoint[] | null; disabled?: boolean; - - workspaceSlug?: string; - projectId?: string; - - className?: string; - buttonClassName?: string; - optionsClassName?: string; - dropdownArrow?: boolean; + hideDropdownArrow?: boolean; } -export const IssuePropertyEstimates: React.FC = observer( - ({ - value, - onChange, - disabled, +export const IssuePropertyEstimates: React.FC = observer((props) => { + const { value, onChange, estimatePoints, disabled, hideDropdownArrow = false } = props; - workspaceSlug, - projectId, - - className, - buttonClassName, - optionsClassName, - dropdownArrow = true, - }) => { - const { project: projectStore }: RootStore = useMobxStore(); - - const dropdownBtn = React.useRef(null); - const dropdownOptions = React.useRef(null); - - const [isOpen, setIsOpen] = React.useState(false); - const [search, setSearch] = React.useState(""); - - const projectDetail = - (workspaceSlug && projectId && projectStore?.getProjectById(workspaceSlug, projectId)) || null; - const projectEstimateId = (projectDetail && projectDetail?.estimate) || null; - const estimates = (projectEstimateId && projectStore?.getProjectEstimateById(projectEstimateId)) || null; - - const options: IFiltersOption[] | [] = - (estimates && - estimates.points && - estimates.points.length > 0 && - estimates.points.map((_estimate) => ({ - id: _estimate?.id, - title: _estimate?.value, - key: _estimate?.key.toString(), - }))) || - []; - - useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); - - const selectedOption: IFiltersOption | null | undefined = - (value && options.find((_estimate: IFiltersOption) => _estimate.key === value)) || null; - - const filteredOptions: IFiltersOption[] = - search === "" - ? options && options.length > 0 - ? options - : [] - : options && options.length > 0 - ? options.filter((_estimate: IFiltersOption) => - _estimate.title.toLowerCase().replace(/\s+/g, "").includes(search.toLowerCase().replace(/\s+/g, "")) - ) - : []; - - return ( - { - if (onChange) onChange(data); - }} - disabled={disabled} - > - {({ open }: { open: boolean }) => { - if (open) { - if (!isOpen) setIsOpen(true); - } else if (isOpen) setIsOpen(false); - - return ( - <> - - {selectedOption ? ( - -
-
- -
-
{selectedOption?.title}
-
-
- ) : ( - -
Select Estimates
-
- )} - - {dropdownArrow && !disabled && ( -
- -
- )} -
- -
- - {options && options.length > 0 ? ( - <> -
-
- -
- -
- setSearch(e.target.value)} - placeholder="Search" - displayValue={(assigned: any) => assigned?.name} - /> -
- - {search && search.length > 0 && ( -
setSearch("")} - className="flex-shrink-0 flex justify-center items-center w-[16px] h-[16px] rounded-sm cursor-pointer hover:bg-custom-background-80" - > - -
- )} -
- -
- {filteredOptions ? ( - filteredOptions.length > 0 ? ( - filteredOptions.map((option) => ( - - `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 }) => ( -
-
- -
-
{option.title}
- {selected && ( -
- -
- )} -
- )} -
- )) - ) : ( - -

No matching results

-
- ) - ) : ( -

Loading...

- )} -
- - ) : ( -

No options available.

- )} -
-
- - ); - }} -
- ); - } -); + return ( + + ); +}); diff --git a/web/components/issues/issue-layouts/properties/labels.tsx b/web/components/issues/issue-layouts/properties/labels.tsx index bc9930c72..dcc884b19 100644 --- a/web/components/issues/issue-layouts/properties/labels.tsx +++ b/web/components/issues/issue-layouts/properties/labels.tsx @@ -1,230 +1,28 @@ -import { FC, useRef, useState } from "react"; -import { Combobox } from "@headlessui/react"; -import { ChevronDown, Search, X, Check } from "lucide-react"; import { observer } from "mobx-react-lite"; // components -import { Tooltip } from "@plane/ui"; -// hooks -import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; - -interface IFiltersOption { - id: string; - title: string; - color: string | null; -} +import { LabelSelect } from "components/project"; +// types +import { IIssueLabels } from "types"; export interface IIssuePropertyLabels { - value?: any; - onChange?: (id: any, data: any) => void; + value: string[]; + onChange: (data: string[]) => void; + labels: IIssueLabels[] | null; disabled?: boolean; - list?: any; - - className?: string; - buttonClassName?: string; - optionsClassName?: string; - dropdownArrow?: boolean; + hideDropdownArrow?: boolean; } -export const IssuePropertyLabels: FC = observer((props) => { - const { - value, - onChange, - disabled, - list, - - className, - buttonClassName, - optionsClassName, - dropdownArrow = true, - } = props; - - const dropdownBtn = useRef(null); - const dropdownOptions = useRef(null); - - const [isOpen, setIsOpen] = useState(false); - const [search, setSearch] = useState(""); - - const options: IFiltersOption[] | [] = - (list && - list?.length > 0 && - list.map((_label: any) => ({ - id: _label?.id, - title: _label?.name, - color: _label?.color || null, - }))) || - []; - - useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); - - const selectedOption: IFiltersOption[] = - (value && value?.length > 0 && options.filter((_label: IFiltersOption) => value.includes(_label.id))) || []; - - const filteredOptions: IFiltersOption[] = - search === "" - ? options && options.length > 0 - ? options - : [] - : options && options.length > 0 - ? options.filter((_label: IFiltersOption) => - _label.title.toLowerCase().replace(/\s+/g, "").includes(search.toLowerCase().replace(/\s+/g, "")) - ) - : []; +export const IssuePropertyLabels: React.FC = observer((props) => { + const { value, onChange, labels, disabled, hideDropdownArrow = false } = props; return ( - _label.id) as string[]} - onChange={(data: string[]) => { - if (onChange && selectedOption) onChange(data, selectedOption); - }} + - {({ open }: { open: boolean }) => { - if (open) { - if (!isOpen) setIsOpen(true); - } else if (isOpen) setIsOpen(false); - - return ( - <> - - {selectedOption && selectedOption?.length > 0 ? ( - <> - {selectedOption?.length === 1 ? ( - _label.title) || []).join(", ")} - > -
-
-
{selectedOption[0]?.title}
-
- - ) : ( - _label.title) || []).join(", ")} - > -
-
-
{selectedOption?.length} Labels
-
- - )} - - ) : ( - -
Select Labels
-
- )} - - {dropdownArrow && !disabled && ( -
- -
- )} - - -
- - {options && options.length > 0 ? ( - <> -
-
- -
- -
- setSearch(e.target.value)} - placeholder="Search" - displayValue={(assigned: any) => assigned?.name} - /> -
- - {search && search.length > 0 && ( -
setSearch("")} - className="flex-shrink-0 flex justify-center items-center w-[16px] h-[16px] rounded-sm cursor-pointer hover:bg-custom-background-80" - > - -
- )} -
- -
- {filteredOptions ? ( - filteredOptions.length > 0 ? ( - filteredOptions.map((option) => ( - - `cursor-pointer select-none truncate rounded px-1 py-1.5 ${ - active || (value && value.length > 0 && value.includes(option?.id)) - ? "bg-custom-background-80" - : "" - } ${ - value && value.length > 0 && value.includes(option?.id) - ? "text-custom-text-100" - : "text-custom-text-200" - }` - } - > -
-
-
{option.title}
- {value && value.length > 0 && value.includes(option?.id) && ( -
- -
- )} -
- - )) - ) : ( - -

No matching results

-
- ) - ) : ( -

Loading...

- )} -
- - ) : ( -

No options available.

- )} - -
- - ); - }} - + hideDropdownArrow={hideDropdownArrow} + /> ); }); diff --git a/web/components/issues/issue-layouts/properties/priority.tsx b/web/components/issues/issue-layouts/properties/priority.tsx index 37404c11b..cbf6602eb 100644 --- a/web/components/issues/issue-layouts/properties/priority.tsx +++ b/web/components/issues/issue-layouts/properties/priority.tsx @@ -1,223 +1,25 @@ -import { FC, useRef, useState } from "react"; -import { Combobox } from "@headlessui/react"; -import { ChevronDown, Search, X, Check, AlertCircle, SignalHigh, SignalMedium, SignalLow, Ban } from "lucide-react"; +import { PrioritySelect } from "components/project"; import { observer } from "mobx-react-lite"; -// components -import { Tooltip } from "@plane/ui"; -// hooks -import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; - -interface IFiltersOption { - id: string; - title: string; -} +// types +import { TIssuePriorities } from "types"; export interface IIssuePropertyPriority { - value?: any; - onChange?: (id: any, data: IFiltersOption) => void; + value: TIssuePriorities; + onChange: (value: TIssuePriorities) => void; disabled?: boolean; - list?: any; - - className?: string; - buttonClassName?: string; - optionsClassName?: string; - dropdownArrow?: boolean; + hideDropdownArrow?: boolean; } -const Icon = ({ priority }: any) => ( -
- {priority === "urgent" ? ( -
- -
- ) : priority === "high" ? ( -
- -
- ) : priority === "medium" ? ( -
- -
- ) : priority === "low" ? ( -
- -
- ) : ( -
- -
- )} -
-); - -export const IssuePropertyPriority: FC = observer((props) => { - const { - value, - onChange, - disabled, - list, - - className, - buttonClassName, - optionsClassName, - dropdownArrow = true, - } = props; - - const dropdownBtn = useRef(null); - const dropdownOptions = useRef(null); - - const [isOpen, setIsOpen] = useState(false); - const [search, setSearch] = useState(""); - - const options: IFiltersOption[] | [] = - (list && - list?.length > 0 && - list.map((_priority: any) => ({ - id: _priority?.key, - title: _priority?.title, - }))) || - []; - - useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); - - const selectedOption: IFiltersOption | null | undefined = - (value && options.find((_priority: IFiltersOption) => _priority.id === value)) || null; - - const filteredOptions: IFiltersOption[] = - search === "" - ? options && options.length > 0 - ? options - : [] - : options && options.length > 0 - ? options.filter((_priority: IFiltersOption) => - _priority.title.toLowerCase().replace(/\s+/g, "").includes(search.toLowerCase().replace(/\s+/g, "")) - ) - : []; +export const IssuePropertyPriority: React.FC = observer((props) => { + const { value, onChange, disabled, hideDropdownArrow = false } = props; return ( - { - if (onChange && selectedOption) onChange(data, selectedOption); - }} + - {({ open }: { open: boolean }) => { - if (open) { - if (!isOpen) setIsOpen(true); - } else if (isOpen) setIsOpen(false); - - return ( - <> - - {selectedOption ? ( - -
-
- -
-
{selectedOption?.title}
-
-
- ) : ( - -
Select Priority
-
- )} - - {dropdownArrow && !disabled && ( -
- -
- )} -
- -
- - {options && options.length > 0 ? ( - <> -
-
- -
- -
- setSearch(e.target.value)} - placeholder="Search" - displayValue={(assigned: any) => assigned?.name} - /> -
- - {search && search.length > 0 && ( -
setSearch("")} - className="flex-shrink-0 flex justify-center items-center w-[16px] h-[16px] rounded-sm cursor-pointer hover:bg-custom-background-80" - > - -
- )} -
- -
- {filteredOptions ? ( - filteredOptions.length > 0 ? ( - filteredOptions.map((option) => ( - - `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 }) => ( -
-
- -
-
{option.title}
- {selected && ( -
- -
- )} -
- )} -
- )) - ) : ( - -

No matching results

-
- ) - ) : ( -

Loading...

- )} -
- - ) : ( -

No options available.

- )} -
-
- - ); - }} -
+ hideDropdownArrow={hideDropdownArrow} + /> ); }); diff --git a/web/components/issues/issue-layouts/properties/state.tsx b/web/components/issues/issue-layouts/properties/state.tsx index 05cb375ad..9264b3084 100644 --- a/web/components/issues/issue-layouts/properties/state.tsx +++ b/web/components/issues/issue-layouts/properties/state.tsx @@ -1,214 +1,28 @@ -import { FC, useRef, useState } from "react"; -import { Combobox } from "@headlessui/react"; -import { ChevronDown, Search, X, Check } from "lucide-react"; import { observer } from "mobx-react-lite"; // components -import { Tooltip, StateGroupIcon } from "@plane/ui"; -// hooks -import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; - +import { StateSelect } from "components/states"; // types import { IState } from "types"; -interface IFiltersOption { - id: string; - title: string; - group: string; - color: string | null; -} - export interface IIssuePropertyState { - value?: any; - onChange?: (id: any, data: IFiltersOption) => void; + value: IState; + onChange: (state: IState) => void; + states: IState[] | null; disabled?: boolean; - list?: any; - - className?: string; - buttonClassName?: string; - optionsClassName?: string; - dropdownArrow?: boolean; + hideDropdownArrow?: boolean; } -export const IssuePropertyState: FC = observer((props) => { - const { - value, - onChange, - disabled, - list, - - className, - buttonClassName, - optionsClassName, - dropdownArrow = true, - } = props; - - const dropdownBtn = useRef(null); - const dropdownOptions = useRef(null); - - const [isOpen, setIsOpen] = useState(false); - const [search, setSearch] = useState(""); - - const options: IFiltersOption[] | [] = - (list && - list?.length > 0 && - list.map((_state: IState) => ({ - id: _state?.id, - title: _state?.name, - group: _state?.group, - color: _state?.color || null, - }))) || - []; - - useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); - - const selectedOption: IFiltersOption | null | undefined = - (value && options.find((_state: IFiltersOption) => _state.id === value)) || null; - - const filteredOptions: IFiltersOption[] = - search === "" - ? options && options.length > 0 - ? options - : [] - : options && options.length > 0 - ? options.filter((_state: IFiltersOption) => - _state.title.toLowerCase().replace(/\s+/g, "").includes(search.toLowerCase().replace(/\s+/g, "")) - ) - : []; +export const IssuePropertyState: React.FC = observer((props) => { + const { value, onChange, states, disabled, hideDropdownArrow = false } = props; return ( - { - if (onChange && selectedOption) onChange(data, selectedOption); - }} + - {({ open }: { open: boolean }) => { - if (open) { - if (!isOpen) setIsOpen(true); - } else if (isOpen) setIsOpen(false); - - return ( - <> - - {selectedOption ? ( - -
-
- -
-
{selectedOption?.title}
-
-
- ) : ( - -
Select State
-
- )} - - {dropdownArrow && !disabled && ( -
- -
- )} -
- -
- - {options && options.length > 0 ? ( - <> -
-
- -
- -
- setSearch(e.target.value)} - placeholder="Search" - displayValue={(assigned: any) => assigned?.name} - /> -
- - {search && search.length > 0 && ( -
setSearch("")} - className="flex-shrink-0 flex justify-center items-center w-[16px] h-[16px] rounded-sm cursor-pointer hover:bg-custom-background-80" - > - -
- )} -
- -
- {filteredOptions ? ( - filteredOptions.length > 0 ? ( - filteredOptions.map((option) => ( - - `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 }) => ( -
-
- -
-
{option.title}
- {selected && ( -
- -
- )} -
- )} -
- )) - ) : ( - -

No matching results

-
- ) - ) : ( -

Loading...

- )} -
- - ) : ( -

No options available.

- )} -
-
- - ); - }} -
+ hideDropdownArrow={hideDropdownArrow} + /> ); }); diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/state-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/state-column.tsx index 7873ebe02..81f45d04f 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/state-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/state-column.tsx @@ -4,6 +4,8 @@ import React from "react"; import { StateSelect } from "components/states"; // hooks import useSubIssue from "hooks/use-sub-issue"; +// helpers +import { getStatesList } from "helpers/state.helper"; // types import { IIssue, IStateResponse } from "types"; @@ -22,12 +24,14 @@ export const SpreadsheetStateColumn: React.FC = (props) => { const { subIssues, isLoading } = useSubIssue(issue.project_detail.id, issue.id, isExpanded); + const statesList = getStatesList(states); + return ( <> onChange({ state: data.id, state_detail: data })} - stateGroups={states} + states={statesList} buttonClassName="!shadow-none !border-0" hideDropdownArrow disabled={disabled} diff --git a/web/components/issues/issue-peek-overview/properties.tsx b/web/components/issues/issue-peek-overview/properties.tsx index f24a58302..bd087e10b 100644 --- a/web/components/issues/issue-peek-overview/properties.tsx +++ b/web/components/issues/issue-peek-overview/properties.tsx @@ -8,38 +8,37 @@ import { IssuePropertyPriority } from "components/issues/issue-layouts/propertie import { IssuePropertyAssignee } from "components/issues/issue-layouts/properties/assignee"; import { IssuePropertyDate } from "components/issues/issue-layouts/properties/date"; // types -import { IIssue } from "types"; +import { IIssue, IState, IUserLite, TIssuePriorities } from "types"; interface IPeekOverviewProperties { issue: IIssue; issueUpdate: (issue: Partial) => void; - - states: any; - members: any; + states: IState[] | null; + members: IUserLite[] | null; priorities: any; } export const PeekOverviewProperties: FC = (props) => { const { issue, issueUpdate, states, members, priorities } = props; - const handleState = (_state: string) => { - if (issueUpdate) issueUpdate({ ...issue, state: _state }); + const handleState = (_state: IState) => { + issueUpdate({ ...issue, state: _state.id }); }; - const handlePriority = (_priority: any) => { - if (issueUpdate) issueUpdate({ ...issue, priority: _priority }); + const handlePriority = (_priority: TIssuePriorities) => { + issueUpdate({ ...issue, priority: _priority }); }; const handleAssignee = (_assignees: string[]) => { - if (issueUpdate) issueUpdate({ ...issue, assignees: _assignees }); + issueUpdate({ ...issue, assignees: _assignees }); }; const handleStartDate = (_startDate: string) => { - if (issueUpdate) issueUpdate({ ...issue, start_date: _startDate }); + issueUpdate({ ...issue, start_date: _startDate }); }; const handleTargetDate = (_targetDate: string) => { - if (issueUpdate) issueUpdate({ ...issue, target_date: _targetDate }); + issueUpdate({ ...issue, target_date: _targetDate }); }; return ( @@ -54,11 +53,11 @@ export const PeekOverviewProperties: FC = (props) => {
handleState(id)} + value={issue?.state_detail || null} + onChange={handleState} + states={states} disabled={false} - list={states} + hideDropdownArrow={true} />
@@ -74,10 +73,10 @@ export const PeekOverviewProperties: FC = (props) => {
handleAssignee(ids)} disabled={false} - list={members} + hideDropdownArrow={true} + members={members} />
@@ -93,10 +92,9 @@ export const PeekOverviewProperties: FC = (props) => {
handlePriority(id)} + onChange={handlePriority} disabled={false} - list={priorities} + hideDropdownArrow={true} />
diff --git a/web/components/issues/sub-issues/properties.tsx b/web/components/issues/sub-issues/properties.tsx index ca0a08600..ce84d92c5 100644 --- a/web/components/issues/sub-issues/properties.tsx +++ b/web/components/issues/sub-issues/properties.tsx @@ -10,6 +10,8 @@ import { TrackEventService } from "services/track_event.service"; import { ViewDueDateSelect, ViewStartDateSelect } from "components/issues"; import { MembersSelect, PrioritySelect } from "components/project"; import { StateSelect } from "components/states"; +// helpers +import { getStatesList } from "helpers/state.helper"; // types import { IUser, IIssue, IState } from "types"; // fetch-keys @@ -115,6 +117,8 @@ export const IssueProperty: React.FC = observer((props) => { ); }; + const statesList = getStatesList(projectStore.states?.[issue.project]); + return (
{displayProperties.priority && ( @@ -132,7 +136,7 @@ export const IssueProperty: React.FC = observer((props) => {
handleStateChange(data)} hideDropdownArrow disabled={!editable} diff --git a/web/components/project/label-select.tsx b/web/components/project/label-select.tsx index f715793cb..ebf7f4776 100644 --- a/web/components/project/label-select.tsx +++ b/web/components/project/label-select.tsx @@ -3,9 +3,6 @@ import { usePopper } from "react-popper"; import { Placement } from "@popperjs/core"; import { Combobox } from "@headlessui/react"; import { Check, ChevronDown, PlusIcon, Search } from "lucide-react"; - -// components -import { CreateLabelModal } from "components/labels"; // ui import { Tooltip } from "components/ui"; // types @@ -14,7 +11,7 @@ import { IIssueLabels } from "types"; type Props = { value: string[]; onChange: (data: string[]) => void; - labels: IIssueLabels[]; + labels: IIssueLabels[] | undefined; className?: string; buttonClassName?: string; optionsClassName?: string; @@ -41,10 +38,16 @@ export const LabelSelect: React.FC = ({ const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState(null); - const [labelModal, setLabelModal] = useState(false); - const { styles, attributes } = usePopper(referenceElement, popperElement, { placement: placement ?? "bottom-start", + modifiers: [ + { + name: "preventOverflow", + options: { + padding: 12, + }, + }, + ], }); const options = labels?.map((label) => ({ @@ -66,149 +69,126 @@ export const LabelSelect: React.FC = ({ const filteredOptions = query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); - const footerOption = ( - - ); - return ( - <> - {/* TODO: update this logic */} - {/* {projectId && ( - setLabelModal(false)} - projectId={projectId} - user={user} - /> - )} */} - - - - - - -
-
- - setQuery(e.target.value)} - placeholder="Search" - displayValue={(assigned: any) => assigned?.name} - /> -
-
- {filteredOptions ? ( - filteredOptions.length > 0 ? ( - filteredOptions.map((option) => ( - - `flex items-center justify-between gap-2 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 }) => ( - <> - {option.content} - {selected && } - - )} - - )) - ) : ( - -

No matching results

-
- ) - ) : ( -

Loading...

- )} -
- {footerOption} +
+ value.includes(l.id)) + .map((l) => l.name) + .join(", ")} + > +
+ + {`${value.length} Labels`} +
+
+
+ ) + ) : ( +
+ Select labels +
+ )}
-
-
- + {!hideDropdownArrow && !disabled &&
diff --git a/web/components/issues/issue-layouts/calendar/day-tile.tsx b/web/components/issues/issue-layouts/calendar/day-tile.tsx index 03d797522..2dacc03ee 100644 --- a/web/components/issues/issue-layouts/calendar/day-tile.tsx +++ b/web/components/issues/issue-layouts/calendar/day-tile.tsx @@ -4,7 +4,7 @@ import { Droppable } from "@hello-pangea/dnd"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { CalendarIssueBlocks, ICalendarDate } from "components/issues"; +import { CalendarIssueBlocks, ICalendarDate, CalendarInlineCreateIssueForm } from "components/issues"; // helpers import { renderDateFormat } from "helpers/date-time.helper"; // types @@ -17,10 +17,11 @@ type Props = { date: ICalendarDate; issues: IIssueGroupedStructure | null; quickActions: (issue: IIssue) => React.ReactNode; + enableQuickIssueCreate?: boolean; }; export const CalendarDayTile: React.FC = observer((props) => { - const { date, issues, quickActions } = props; + const { date, issues, quickActions, enableQuickIssueCreate } = props; const { issueFilter: issueFilterStore } = useMobxStore(); @@ -30,7 +31,7 @@ export const CalendarDayTile: React.FC = observer((props) => { return ( <> -
+
{/* header */}
= observer((props) => { ref={provided.innerRef} > + {enableQuickIssueCreate && ( +
+ +
+ )} {provided.placeholder}
)} diff --git a/web/components/issues/issue-layouts/calendar/index.ts b/web/components/issues/issue-layouts/calendar/index.ts index be4383954..a33cf557b 100644 --- a/web/components/issues/issue-layouts/calendar/index.ts +++ b/web/components/issues/issue-layouts/calendar/index.ts @@ -7,3 +7,4 @@ export * from "./header"; export * from "./issue-blocks"; export * from "./week-days"; export * from "./week-header"; +export * from "./inline-create-issue-form"; diff --git a/web/components/issues/issue-layouts/calendar/inline-create-issue-form.tsx b/web/components/issues/issue-layouts/calendar/inline-create-issue-form.tsx new file mode 100644 index 000000000..3ab74c368 --- /dev/null +++ b/web/components/issues/issue-layouts/calendar/inline-create-issue-form.tsx @@ -0,0 +1,234 @@ +import { useEffect, useRef, useState } from "react"; +import { useRouter } from "next/router"; +import { Transition } from "@headlessui/react"; +import { useForm } from "react-hook-form"; + +// store +import { observer } from "mobx-react-lite"; +import { useMobxStore } from "lib/mobx/store-provider"; + +// hooks +import useToast from "hooks/use-toast"; +import useKeypress from "hooks/use-keypress"; +import useProjectDetails from "hooks/use-project-details"; +import useOutsideClickDetector from "hooks/use-outside-click-detector"; + +// constants +import { createIssuePayload } from "constants/issue"; + +// icons +import { PlusIcon } from "lucide-react"; + +// types +import { IIssue } from "types"; + +type Props = { + groupId?: string; + dependencies?: any[]; + prePopulatedData?: Partial; + onSuccess?: (data: IIssue) => Promise | void; +}; + +const useCheckIfThereIsSpaceOnRight = (ref: React.RefObject, deps: any[]) => { + const [isThereSpaceOnRight, setIsThereSpaceOnRight] = useState(true); + + const router = useRouter(); + const { moduleId, cycleId, viewId } = router.query; + + const container = document.getElementById(`calendar-view-${cycleId ?? moduleId ?? viewId}`); + + useEffect(() => { + if (!ref.current) return; + + const { right } = ref.current.getBoundingClientRect(); + + const width = right; + + const innerWidth = container?.getBoundingClientRect().width ?? window.innerWidth; + + if (width > innerWidth) setIsThereSpaceOnRight(false); + else setIsThereSpaceOnRight(true); + }, [ref, deps, container]); + + return isThereSpaceOnRight; +}; + +const defaultValues: Partial = { + name: "", +}; + +const Inputs = (props: any) => { + const { register, setFocus, projectDetails } = props; + + useEffect(() => { + setFocus("name"); + }, [setFocus]); + + return ( + <> +

{projectDetails?.identifier ?? "..."}

+ + + ); +}; + +export const CalendarInlineCreateIssueForm: React.FC = observer((props) => { + const { prePopulatedData, dependencies = [], groupId } = props; + + // router + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + // store + const { workspace: workspaceStore, quickAddIssue: quickAddStore } = useMobxStore(); + + // ref + const ref = useRef(null); + + // states + const [isOpen, setIsOpen] = useState(false); + + const { setToastAlert } = useToast(); + + const { projectDetails } = useProjectDetails(); + + const { + reset, + handleSubmit, + register, + setFocus, + formState: { errors, isSubmitting }, + } = useForm({ defaultValues }); + + const handleClose = () => { + setIsOpen(false); + }; + + useKeypress("Escape", handleClose); + useOutsideClickDetector(ref, handleClose); + + // derived values + const workspaceDetail = workspaceStore.getWorkspaceBySlug(workspaceSlug?.toString()!); + + useEffect(() => { + if (!isOpen) reset({ ...defaultValues }); + }, [isOpen, reset]); + + useEffect(() => { + if (!errors) return; + + Object.keys(errors).forEach((key) => { + const error = errors[key as keyof IIssue]; + + setToastAlert({ + type: "error", + title: "Error!", + message: error?.message?.toString() || "Some error occurred. Please try again.", + }); + }); + }, [errors, setToastAlert]); + + const isSpaceOnRight = useCheckIfThereIsSpaceOnRight(ref, dependencies); + + const onSubmitHandler = async (formData: IIssue) => { + if (isSubmitting || !workspaceSlug || !projectId) return; + + // resetting the form so that user can add another issue quickly + reset({ ...defaultValues, ...(prePopulatedData ?? {}) }); + + const payload = createIssuePayload(workspaceDetail!, projectDetails!, { + ...(prePopulatedData ?? {}), + ...formData, + labels_list: + formData.labels_list?.length !== 0 + ? formData.labels_list + : prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none" + ? [prePopulatedData.labels as any] + : [], + assignees_list: + formData.assignees_list?.length !== 0 + ? formData.assignees_list + : prePopulatedData?.assignees && prePopulatedData?.assignees.toString() !== "none" + ? [prePopulatedData.assignees as any] + : [], + }); + + try { + quickAddStore.createIssue( + workspaceSlug.toString(), + projectId.toString(), + { + group_id: groupId ?? null, + sub_group_id: null, + }, + payload + ); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Issue created successfully.", + }); + } catch (err: any) { + Object.keys(err || {}).forEach((key) => { + const error = err?.[key]; + const errorTitle = error ? (Array.isArray(error) ? error.join(", ") : error) : null; + + setToastAlert({ + type: "error", + title: "Error!", + message: errorTitle || "Some error occurred. Please try again.", + }); + }); + } + }; + + return ( + <> + +
+
+ + +
+
+ + {!isOpen && ( +
+ +
+ )} + + ); +}); diff --git a/web/components/issues/issue-layouts/calendar/issue-blocks.tsx b/web/components/issues/issue-layouts/calendar/issue-blocks.tsx index eac2ef43d..cddc30c68 100644 --- a/web/components/issues/issue-layouts/calendar/issue-blocks.tsx +++ b/web/components/issues/issue-layouts/calendar/issue-blocks.tsx @@ -22,11 +22,14 @@ export const CalendarIssueBlocks: React.FC = observer((props) => { {(provided, snapshot) => ( diff --git a/web/components/issues/issue-layouts/calendar/week-days.tsx b/web/components/issues/issue-layouts/calendar/week-days.tsx index 2d6d5d09a..3923acb62 100644 --- a/web/components/issues/issue-layouts/calendar/week-days.tsx +++ b/web/components/issues/issue-layouts/calendar/week-days.tsx @@ -15,10 +15,11 @@ type Props = { issues: IIssueGroupedStructure | null; week: ICalendarWeek | undefined; quickActions: (issue: IIssue) => React.ReactNode; + enableQuickIssueCreate?: boolean; }; export const CalendarWeekDays: React.FC = observer((props) => { - const { issues, week, quickActions } = props; + const { issues, week, quickActions, enableQuickIssueCreate } = props; const { issueFilter: issueFilterStore } = useMobxStore(); @@ -37,7 +38,13 @@ export const CalendarWeekDays: React.FC = observer((props) => { if (!showWeekends && (date.date.getDay() === 0 || date.date.getDay() === 6)) return null; return ( - + ); })}
diff --git a/web/components/issues/issue-layouts/gantt/index.ts b/web/components/issues/issue-layouts/gantt/index.ts index d8cfadd48..87899ae83 100644 --- a/web/components/issues/issue-layouts/gantt/index.ts +++ b/web/components/issues/issue-layouts/gantt/index.ts @@ -3,3 +3,4 @@ export * from "./cycle-root"; export * from "./module-root"; export * from "./project-view-root"; export * from "./root"; +export * from "./inline-create-issue-form"; diff --git a/web/components/issues/issue-layouts/gantt/inline-create-issue-form.tsx b/web/components/issues/issue-layouts/gantt/inline-create-issue-form.tsx new file mode 100644 index 000000000..b4edddbd1 --- /dev/null +++ b/web/components/issues/issue-layouts/gantt/inline-create-issue-form.tsx @@ -0,0 +1,196 @@ +import { useEffect, useState, useRef } from "react"; +import { useRouter } from "next/router"; +import { useForm } from "react-hook-form"; +import { Transition } from "@headlessui/react"; +import { PlusIcon } from "lucide-react"; + +// store +import { observer } from "mobx-react-lite"; +import { useMobxStore } from "lib/mobx/store-provider"; + +// constants +import { createIssuePayload } from "constants/issue"; + +// hooks +import useToast from "hooks/use-toast"; +import useKeypress from "hooks/use-keypress"; +import useProjectDetails from "hooks/use-project-details"; +import useOutsideClickDetector from "hooks/use-outside-click-detector"; + +// types +import { IIssue } from "types"; +import { renderDateFormat } from "helpers/date-time.helper"; + +type Props = { + prePopulatedData?: Partial; + onSuccess?: (data: IIssue) => Promise | void; +}; + +const defaultValues: Partial = { + name: "", +}; + +const Inputs = (props: any) => { + const { register, setFocus } = props; + + useEffect(() => { + setFocus("name"); + }, [setFocus]); + + return ( + + ); +}; + +export const GanttInlineCreateIssueForm: React.FC = observer((props) => { + const { prePopulatedData } = props; + + // router + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + // store + const { workspace: workspaceStore, quickAddIssue: quickAddStore } = useMobxStore(); + + const { projectDetails } = useProjectDetails(); + + const { + reset, + handleSubmit, + setFocus, + register, + formState: { errors, isSubmitting }, + } = useForm({ defaultValues }); + + // ref + const ref = useRef(null); + + // states + const [isOpen, setIsOpen] = useState(false); + + const handleClose = () => setIsOpen(false); + + // hooks + useKeypress("Escape", handleClose); + useOutsideClickDetector(ref, handleClose); + const { setToastAlert } = useToast(); + + // derived values + const workspaceDetail = workspaceStore.getWorkspaceBySlug(workspaceSlug?.toString()!); + + useEffect(() => { + if (!isOpen) reset({ ...defaultValues }); + }, [isOpen, reset]); + + useEffect(() => { + if (!errors) return; + + Object.keys(errors).forEach((key) => { + const error = errors[key as keyof IIssue]; + + setToastAlert({ + type: "error", + title: "Error!", + message: error?.message?.toString() || "Some error occurred. Please try again.", + }); + }); + }, [errors, setToastAlert]); + + const onSubmitHandler = async (formData: IIssue) => { + if (isSubmitting || !workspaceSlug || !projectId) return; + + // resetting the form so that user can add another issue quickly + reset({ ...defaultValues, ...(prePopulatedData ?? {}) }); + + const payload = createIssuePayload(workspaceDetail!, projectDetails!, { + ...(prePopulatedData ?? {}), + ...formData, + labels_list: + formData.labels_list?.length !== 0 + ? formData.labels_list + : prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none" + ? [prePopulatedData.labels as any] + : [], + start_date: renderDateFormat(new Date()), + target_date: renderDateFormat(new Date(new Date().getTime() + 24 * 60 * 60 * 1000)), + }); + + try { + quickAddStore.createIssue( + workspaceSlug.toString(), + projectId.toString(), + { + group_id: null, + sub_group_id: null, + }, + payload + ); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Issue created successfully.", + }); + } catch (err: any) { + Object.keys(err || {}).forEach((key) => { + const error = err?.[key]; + const errorTitle = error ? (Array.isArray(error) ? error.join(", ") : error) : null; + + setToastAlert({ + type: "error", + title: "Error!", + message: errorTitle || "Some error occurred. Please try again.", + }); + }); + } + }; + + return ( + <> + +
+
+

{projectDetails?.identifier ?? "..."}

+ + + + + {isOpen && ( +

+ Press {"'"}Enter{"'"} to add another issue +

+ )} + + {!isOpen && ( + + )} + + ); +}); diff --git a/web/components/issues/issue-layouts/kanban/block.tsx b/web/components/issues/issue-layouts/kanban/block.tsx index 505da1da3..3cbb4e7d5 100644 --- a/web/components/issues/issue-layouts/kanban/block.tsx +++ b/web/components/issues/issue-layouts/kanban/block.tsx @@ -54,6 +54,9 @@ export const KanbanIssueBlock: React.FC = (props) => { {...provided.dragHandleProps} ref={provided.innerRef} > + {issue.tempId !== undefined && ( +
+ )}
{quickActions( !sub_group_id && sub_group_id === "null" ? null : sub_group_id, diff --git a/web/components/issues/issue-layouts/kanban/default.tsx b/web/components/issues/issue-layouts/kanban/default.tsx index dd781a289..354cf011f 100644 --- a/web/components/issues/issue-layouts/kanban/default.tsx +++ b/web/components/issues/issue-layouts/kanban/default.tsx @@ -5,7 +5,7 @@ import { Droppable } from "@hello-pangea/dnd"; import { useMobxStore } from "lib/mobx/store-provider"; // components import { KanBanGroupByHeaderRoot } from "./headers/group-by-root"; -import { KanbanIssueBlocksList } from "components/issues"; +import { KanbanIssueBlocksList, BoardInlineCreateIssueForm } from "components/issues"; // types import { IEstimatePoint, IIssue, IIssueLabels, IProject, IState, IUserLite } from "types"; // constants @@ -29,6 +29,7 @@ export interface IGroupByKanBan { display_properties: any; kanBanToggle: any; handleKanBanToggle: any; + enableQuickIssueCreate?: boolean; states: IState[] | null; labels: IIssueLabels[] | null; members: IUserLite[] | null; @@ -55,6 +56,7 @@ const GroupByKanBan: React.FC = observer((props) => { members, priorities, estimates, + enableQuickIssueCreate, } = props; const verticalAlignPosition = (_list: any) => @@ -120,6 +122,16 @@ const GroupByKanBan: React.FC = observer((props) => { )}
+ {enableQuickIssueCreate && ( + + )}
))}
@@ -149,6 +161,7 @@ export interface IKanBan { members: IUserLite[] | null; projects: IProject[] | null; estimates: IEstimatePoint[] | null; + enableQuickIssueCreate?: boolean; } export const KanBan: React.FC = observer((props) => { @@ -169,6 +182,7 @@ export const KanBan: React.FC = observer((props) => { members, projects, estimates, + enableQuickIssueCreate, } = props; const { project: projectStore, issueKanBanView: issueKanBanViewStore } = useMobxStore(); @@ -189,6 +203,7 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + enableQuickIssueCreate={enableQuickIssueCreate} states={states} labels={labels} members={members} @@ -211,6 +226,7 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + enableQuickIssueCreate={enableQuickIssueCreate} states={states} labels={labels} members={members} @@ -233,6 +249,7 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + enableQuickIssueCreate={enableQuickIssueCreate} states={states} labels={labels} members={members} @@ -255,6 +272,7 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + enableQuickIssueCreate={enableQuickIssueCreate} states={states} labels={labels} members={members} @@ -277,6 +295,7 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + enableQuickIssueCreate={enableQuickIssueCreate} states={states} labels={labels} members={members} @@ -299,6 +318,7 @@ export const KanBan: React.FC = observer((props) => { display_properties={display_properties} kanBanToggle={kanBanToggle} handleKanBanToggle={handleKanBanToggle} + enableQuickIssueCreate={enableQuickIssueCreate} states={states} labels={labels} members={members} diff --git a/web/components/issues/issue-layouts/kanban/index.ts b/web/components/issues/issue-layouts/kanban/index.ts index f84f7c8af..761f32a77 100644 --- a/web/components/issues/issue-layouts/kanban/index.ts +++ b/web/components/issues/issue-layouts/kanban/index.ts @@ -1,3 +1,4 @@ export * from "./block"; export * from "./roots"; export * from "./blocks-list"; +export * from "./inline-create-issue-form"; diff --git a/web/components/issues/issue-layouts/kanban/inline-create-issue-form.tsx b/web/components/issues/issue-layouts/kanban/inline-create-issue-form.tsx new file mode 100644 index 000000000..cad0814b8 --- /dev/null +++ b/web/components/issues/issue-layouts/kanban/inline-create-issue-form.tsx @@ -0,0 +1,202 @@ +import { useEffect, useState, useRef } from "react"; +import { useRouter } from "next/router"; +import { useForm } from "react-hook-form"; +import { Transition } from "@headlessui/react"; +import { PlusIcon } from "lucide-react"; +// store +import { observer } from "mobx-react-lite"; +import { useMobxStore } from "lib/mobx/store-provider"; + +// hooks +import useToast from "hooks/use-toast"; +import useKeypress from "hooks/use-keypress"; +import useProjectDetails from "hooks/use-project-details"; +import useOutsideClickDetector from "hooks/use-outside-click-detector"; + +// constants +import { createIssuePayload } from "constants/issue"; + +// types +import { IIssue } from "types"; + +type Props = { + groupId?: string; + subGroupId?: string; + prePopulatedData?: Partial; + onSuccess?: (data: IIssue) => Promise | void; +}; + +const defaultValues: Partial = { + name: "", +}; + +const Inputs = (props: any) => { + const { register, setFocus, projectDetails } = props; + + useEffect(() => { + setFocus("name"); + }, [setFocus]); + + return ( +
+

{projectDetails?.identifier ?? "..."}

+ +
+ ); +}; + +export const BoardInlineCreateIssueForm: React.FC = observer((props) => { + const { prePopulatedData, groupId, subGroupId } = props; + + // router + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + // store + const { workspace: workspaceStore, quickAddIssue: quickAddStore } = useMobxStore(); + + // ref + const ref = useRef(null); + + // states + const [isOpen, setIsOpen] = useState(false); + + const { setToastAlert } = useToast(); + + const { projectDetails } = useProjectDetails(); + + const { + reset, + handleSubmit, + register, + setFocus, + formState: { errors, isSubmitting }, + } = useForm({ defaultValues }); + + const handleClose = () => { + setIsOpen(false); + }; + + useKeypress("Escape", handleClose); + useOutsideClickDetector(ref, handleClose); + + // derived values + const workspaceDetail = workspaceStore.getWorkspaceBySlug(workspaceSlug?.toString()!); + + useEffect(() => { + if (!isOpen) reset({ ...defaultValues }); + }, [isOpen, reset]); + + useEffect(() => { + if (!errors) return; + + Object.keys(errors).forEach((key) => { + const error = errors[key as keyof IIssue]; + + setToastAlert({ + type: "error", + title: "Error!", + message: error?.message?.toString() || "Some error occurred. Please try again.", + }); + }); + }, [errors, setToastAlert]); + + const onSubmitHandler = async (formData: IIssue) => { + if (isSubmitting || !workspaceSlug || !projectId) return; + + // resetting the form so that user can add another issue quickly + reset({ ...defaultValues, ...(prePopulatedData ?? {}) }); + + const payload = createIssuePayload(workspaceDetail!, projectDetails!, { + ...(prePopulatedData ?? {}), + ...formData, + labels_list: + formData.labels_list && formData.labels_list.length !== 0 + ? formData.labels_list + : prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none" + ? [prePopulatedData.labels as any] + : [], + assignees_list: + formData.assignees_list && formData.assignees_list.length !== 0 + ? formData.assignees_list + : prePopulatedData?.assignees && prePopulatedData?.assignees.toString() !== "none" + ? [prePopulatedData.assignees as any] + : [], + }); + + try { + quickAddStore.createIssue( + workspaceSlug.toString(), + projectId.toString(), + { + group_id: groupId ?? null, + sub_group_id: subGroupId ?? null, + }, + payload + ); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Issue created successfully.", + }); + } catch (err: any) { + Object.keys(err || {}).forEach((key) => { + const error = err?.[key]; + const errorTitle = error ? (Array.isArray(error) ? error.join(", ") : error) : null; + + setToastAlert({ + type: "error", + title: "Error!", + message: errorTitle || "Some error occurred. Please try again.", + }); + }); + } + }; + + return ( +
+ +
+ + +
+ + {isOpen && ( +

+ Press {"'"}Enter{"'"} to add another issue +

+ )} + + {!isOpen && ( + + )} +
+ ); +}); diff --git a/web/components/issues/issue-layouts/kanban/roots/project-root.tsx b/web/components/issues/issue-layouts/kanban/roots/project-root.tsx index fb375b382..ab087e5c8 100644 --- a/web/components/issues/issue-layouts/kanban/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/project-root.tsx @@ -112,6 +112,7 @@ export const KanBanLayout: React.FC = observer(() => { labels={labels} members={members?.map((m) => m.member) ?? null} projects={projects} + enableQuickIssueCreate estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} /> ) : ( diff --git a/web/components/issues/issue-layouts/kanban/swimlanes.tsx b/web/components/issues/issue-layouts/kanban/swimlanes.tsx index c46c6290b..7a3126cb2 100644 --- a/web/components/issues/issue-layouts/kanban/swimlanes.tsx +++ b/web/components/issues/issue-layouts/kanban/swimlanes.tsx @@ -153,6 +153,7 @@ const SubGroupSwimlane: React.FC = observer((props) => { members={members} projects={projects} estimates={estimates} + enableQuickIssueCreate />
)} diff --git a/web/components/issues/issue-layouts/list/block.tsx b/web/components/issues/issue-layouts/list/block.tsx index 9777f9ba5..5a84c5f9e 100644 --- a/web/components/issues/issue-layouts/list/block.tsx +++ b/web/components/issues/issue-layouts/list/block.tsx @@ -27,12 +27,15 @@ export const IssueBlock: React.FC = (props) => { return ( <> -
+
{display_properties && display_properties?.key && (
{issue?.project_detail?.identifier}-{issue.sequence_id}
)} + {issue?.tempId !== undefined && ( +
+ )} = observer((props) => { stateGroups, priorities, estimates, + enableQuickIssueCreate, } = props; return ( @@ -76,6 +78,14 @@ const GroupByList: React.FC = observer((props) => { /> )}
+ {enableQuickIssueCreate && ( + + )}
))}
@@ -96,6 +106,7 @@ export interface IList { projects: IProject[] | null; stateGroups: any; priorities: any; + enableQuickIssueCreate?: boolean; estimates: IEstimatePoint[] | null; } @@ -113,6 +124,7 @@ export const List: React.FC = observer((props) => { stateGroups, priorities, estimates, + enableQuickIssueCreate, } = props; return ( @@ -134,6 +146,7 @@ export const List: React.FC = observer((props) => { stateGroups={stateGroups} priorities={priorities} estimates={estimates} + enableQuickIssueCreate={enableQuickIssueCreate} /> )} @@ -153,6 +166,7 @@ export const List: React.FC = observer((props) => { stateGroups={stateGroups} priorities={priorities} estimates={estimates} + enableQuickIssueCreate={enableQuickIssueCreate} /> )} @@ -172,6 +186,7 @@ export const List: React.FC = observer((props) => { stateGroups={stateGroups} priorities={priorities} estimates={estimates} + enableQuickIssueCreate={enableQuickIssueCreate} /> )} @@ -191,6 +206,7 @@ export const List: React.FC = observer((props) => { stateGroups={stateGroups} priorities={priorities} estimates={estimates} + enableQuickIssueCreate={enableQuickIssueCreate} /> )} @@ -210,6 +226,7 @@ export const List: React.FC = observer((props) => { stateGroups={stateGroups} priorities={priorities} estimates={estimates} + enableQuickIssueCreate={enableQuickIssueCreate} /> )} @@ -229,6 +246,7 @@ export const List: React.FC = observer((props) => { stateGroups={stateGroups} priorities={priorities} estimates={estimates} + enableQuickIssueCreate={enableQuickIssueCreate} /> )} @@ -248,6 +266,7 @@ export const List: React.FC = observer((props) => { stateGroups={stateGroups} priorities={priorities} estimates={estimates} + enableQuickIssueCreate={enableQuickIssueCreate} /> )} @@ -267,6 +286,7 @@ export const List: React.FC = observer((props) => { stateGroups={stateGroups} priorities={priorities} estimates={estimates} + enableQuickIssueCreate={enableQuickIssueCreate} /> )}
diff --git a/web/components/issues/issue-layouts/list/index.ts b/web/components/issues/issue-layouts/list/index.ts index de9129b8f..e557fe022 100644 --- a/web/components/issues/issue-layouts/list/index.ts +++ b/web/components/issues/issue-layouts/list/index.ts @@ -1,3 +1,4 @@ export * from "./roots"; export * from "./block"; export * from "./blocks-list"; +export * from "./inline-create-issue-form"; diff --git a/web/components/issues/issue-layouts/list/inline-create-issue-form.tsx b/web/components/issues/issue-layouts/list/inline-create-issue-form.tsx new file mode 100644 index 000000000..a6ac218e7 --- /dev/null +++ b/web/components/issues/issue-layouts/list/inline-create-issue-form.tsx @@ -0,0 +1,201 @@ +import { useEffect, useState, useRef } from "react"; +import { useRouter } from "next/router"; +import { useForm } from "react-hook-form"; +import { Transition } from "@headlessui/react"; + +// hooks +import useToast from "hooks/use-toast"; +import useKeypress from "hooks/use-keypress"; +import useProjectDetails from "hooks/use-project-details"; +import useOutsideClickDetector from "hooks/use-outside-click-detector"; + +// store +import { observer } from "mobx-react-lite"; +import { useMobxStore } from "lib/mobx/store-provider"; + +// constants +import { createIssuePayload } from "constants/issue"; + +// types +import { IIssue } from "types"; +import { PlusIcon } from "lucide-react"; + +type Props = { + groupId?: string; + prePopulatedData?: Partial; + onSuccess?: (data: IIssue) => Promise | void; +}; + +const defaultValues: Partial = { + name: "", +}; + +const Inputs = (props: any) => { + const { register, setFocus, projectDetails } = props; + + useEffect(() => { + setFocus("name"); + }, [setFocus]); + + return ( + <> +

{projectDetails?.identifier ?? "..."}

+ + + ); +}; + +export const ListInlineCreateIssueForm: React.FC = observer((props) => { + const { prePopulatedData, groupId } = props; + + // router + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + // store + const { workspace: workspaceStore, quickAddIssue: quickAddStore } = useMobxStore(); + + const { projectDetails } = useProjectDetails(); + + const { + reset, + handleSubmit, + setFocus, + register, + formState: { errors, isSubmitting }, + } = useForm({ defaultValues }); + + // ref + const ref = useRef(null); + + // states + const [isOpen, setIsOpen] = useState(false); + + const handleClose = () => setIsOpen(false); + + // hooks + useKeypress("Escape", handleClose); + useOutsideClickDetector(ref, handleClose); + const { setToastAlert } = useToast(); + + // derived values + const workspaceDetail = workspaceStore.getWorkspaceBySlug(workspaceSlug?.toString()!); + + useEffect(() => { + if (!isOpen) reset({ ...defaultValues }); + }, [isOpen, reset]); + + useEffect(() => { + if (!errors) return; + + Object.keys(errors).forEach((key) => { + const error = errors[key as keyof IIssue]; + + setToastAlert({ + type: "error", + title: "Error!", + message: error?.message?.toString() || "Some error occurred. Please try again.", + }); + }); + }, [errors, setToastAlert]); + + const onSubmitHandler = async (formData: IIssue) => { + if (isSubmitting || !workspaceSlug || !projectId) return; + + // resetting the form so that user can add another issue quickly + reset({ ...defaultValues }); + + const payload = createIssuePayload(workspaceDetail!, projectDetails!, { + ...(prePopulatedData ?? {}), + ...formData, + labels_list: + formData.labels_list?.length !== 0 + ? formData.labels_list + : prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none" + ? [prePopulatedData.labels as any] + : [], + assignees_list: + formData.assignees_list?.length !== 0 + ? formData.assignees_list + : prePopulatedData?.assignees && prePopulatedData?.assignees.toString() !== "none" + ? [prePopulatedData.assignees as any] + : [], + }); + + try { + quickAddStore.createIssue( + workspaceSlug.toString(), + projectId.toString(), + { + group_id: groupId ?? null, + sub_group_id: null, + }, + payload + ); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Issue created successfully.", + }); + } catch (err: any) { + Object.keys(err || {}).forEach((key) => { + const error = err?.[key]; + const errorTitle = error ? (Array.isArray(error) ? error.join(", ") : error) : null; + + setToastAlert({ + type: "error", + title: "Error!", + message: errorTitle || "Some error occurred. Please try again.", + }); + }); + } + }; + + return ( +
+ +
+ + +
+ + {isOpen && ( +

+ Press {"'"}Enter{"'"} to add another issue +

+ )} + + {!isOpen && ( + + )} +
+ ); +}); diff --git a/web/components/issues/issue-layouts/list/roots/project-root.tsx b/web/components/issues/issue-layouts/list/roots/project-root.tsx index 677e2f11c..47c1753c6 100644 --- a/web/components/issues/issue-layouts/list/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/project-root.tsx @@ -76,6 +76,7 @@ export const ListLayout: FC = observer(() => { labels={labels} members={members?.map((m) => m.member) ?? null} projects={projects} + enableQuickIssueCreate estimates={estimates?.points ? orderArrayBy(estimates.points, "key") : null} />
diff --git a/web/components/issues/issue-layouts/spreadsheet/index.ts b/web/components/issues/issue-layouts/spreadsheet/index.ts index 64b02a766..5b14a2dab 100644 --- a/web/components/issues/issue-layouts/spreadsheet/index.ts +++ b/web/components/issues/issue-layouts/spreadsheet/index.ts @@ -2,3 +2,4 @@ export * from "./columns"; export * from "./roots"; export * from "./spreadsheet-column"; export * from "./spreadsheet-view"; +export * from "./inline-create-issue-form"; diff --git a/web/components/issues/issue-layouts/spreadsheet/inline-create-issue-form.tsx b/web/components/issues/issue-layouts/spreadsheet/inline-create-issue-form.tsx new file mode 100644 index 000000000..20105a67e --- /dev/null +++ b/web/components/issues/issue-layouts/spreadsheet/inline-create-issue-form.tsx @@ -0,0 +1,207 @@ +import { useEffect, useState, useRef } from "react"; +import { useRouter } from "next/router"; +import { useForm } from "react-hook-form"; +import { Transition } from "@headlessui/react"; + +// hooks +import useToast from "hooks/use-toast"; +import useKeypress from "hooks/use-keypress"; +import useProjectDetails from "hooks/use-project-details"; +import useOutsideClickDetector from "hooks/use-outside-click-detector"; + +// store +import { observer } from "mobx-react-lite"; +import { useMobxStore } from "lib/mobx/store-provider"; + +// constants +import { createIssuePayload } from "constants/issue"; + +// types +import { IIssue } from "types"; +import { PlusIcon } from "lucide-react"; + +type Props = { + groupId?: string; + prePopulatedData?: Partial; + onSuccess?: (data: IIssue) => Promise | void; +}; + +const defaultValues: Partial = { + name: "", +}; + +const Inputs = (props: any) => { + const { register, setFocus, projectDetails } = props; + + useEffect(() => { + setFocus("name"); + }, [setFocus]); + + return ( + <> +

{projectDetails?.identifier ?? "..."}

+ + + ); +}; + +export const SpreadsheetInlineCreateIssueForm: React.FC = observer((props) => { + const { prePopulatedData, groupId } = props; + + // router + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + // store + const { workspace: workspaceStore, quickAddIssue: quickAddStore } = useMobxStore(); + + const { projectDetails } = useProjectDetails(); + + const { + reset, + handleSubmit, + setFocus, + register, + formState: { errors, isSubmitting }, + } = useForm({ defaultValues }); + + // ref + const ref = useRef(null); + + // states + const [isOpen, setIsOpen] = useState(false); + + const handleClose = () => setIsOpen(false); + + // hooks + useKeypress("Escape", handleClose); + useOutsideClickDetector(ref, handleClose); + const { setToastAlert } = useToast(); + + // derived values + const workspaceDetail = workspaceStore.getWorkspaceBySlug(workspaceSlug?.toString()!); + + useEffect(() => { + setFocus("name"); + }, [setFocus, isOpen]); + + useEffect(() => { + if (!isOpen) reset({ ...defaultValues }); + }, [isOpen, reset]); + + useEffect(() => { + if (!errors) return; + + Object.keys(errors).forEach((key) => { + const error = errors[key as keyof IIssue]; + + setToastAlert({ + type: "error", + title: "Error!", + message: error?.message?.toString() || "Some error occurred. Please try again.", + }); + }); + }, [errors, setToastAlert]); + + const onSubmitHandler = async (formData: IIssue) => { + if (isSubmitting || !workspaceSlug || !projectId) return; + + // resetting the form so that user can add another issue quickly + reset({ ...defaultValues }); + + const payload = createIssuePayload(workspaceDetail!, projectDetails!, { + ...(prePopulatedData ?? {}), + ...formData, + labels_list: + formData.labels_list && formData.labels_list?.length !== 0 + ? formData.labels_list + : prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none" + ? [prePopulatedData.labels as any] + : [], + assignees_list: + formData.assignees_list && formData.assignees_list?.length !== 0 + ? formData.assignees_list + : prePopulatedData?.assignees && prePopulatedData?.assignees.toString() !== "none" + ? [prePopulatedData.assignees as any] + : [], + }); + + try { + quickAddStore.createIssue( + workspaceSlug.toString(), + projectId.toString(), + { + group_id: groupId ?? null, + sub_group_id: null, + }, + payload + ); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Issue created successfully.", + }); + } catch (err: any) { + Object.keys(err || {}).forEach((key) => { + const error = err?.[key]; + const errorTitle = error ? (Array.isArray(error) ? error.join(", ") : error) : null; + + setToastAlert({ + type: "error", + title: "Error!", + message: errorTitle || "Some error occurred. Please try again.", + }); + }); + } + }; + + return ( +
+ +
+
+ + +
+
+ + {isOpen && ( +

+ Press {"'"}Enter{"'"} to add another issue +

+ )} + + {!isOpen && ( + + )} +
+ ); +}); diff --git a/web/components/issues/issue-layouts/spreadsheet/roots/project-root.tsx b/web/components/issues/issue-layouts/spreadsheet/roots/project-root.tsx index 78940ceaf..a3856f5fb 100644 --- a/web/components/issues/issue-layouts/spreadsheet/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/roots/project-root.tsx @@ -66,6 +66,7 @@ export const ProjectSpreadsheetLayout: React.FC = observer(() => { handleIssueAction={() => {}} handleUpdateIssue={handleUpdateIssue} disableUserActions={false} + enableQuickCreateIssue /> ); }); diff --git a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx index 521773f6b..4d2a7cd04 100644 --- a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx @@ -3,11 +3,7 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { PlusIcon } from "lucide-react"; // components -import { - SpreadsheetColumnsList, - // ListInlineCreateIssueForm, - SpreadsheetIssuesColumn, -} from "components/issues"; +import { SpreadsheetColumnsList, SpreadsheetIssuesColumn, SpreadsheetInlineCreateIssueForm } from "components/issues"; import { CustomMenu, Spinner } from "@plane/ui"; // types import { @@ -31,6 +27,7 @@ type Props = { handleUpdateIssue: (issue: IIssue, data: Partial) => void; openIssuesListModal?: (() => void) | null; disableUserActions: boolean; + enableQuickCreateIssue?: boolean; }; export const SpreadsheetView: React.FC = observer((props) => { @@ -46,6 +43,7 @@ export const SpreadsheetView: React.FC = observer((props) => { handleUpdateIssue, openIssuesListModal, disableUserActions, + enableQuickCreateIssue, } = props; const [expandedIssues, setExpandedIssues] = useState([]); @@ -138,17 +136,10 @@ export const SpreadsheetView: React.FC = observer((props) => {
- {/* setIsInlineCreateIssueFormOpen(false)} - prePopulatedData={{ - ...(cycleId && { cycle: cycleId.toString() }), - ...(moduleId && { module: moduleId.toString() }), - }} - /> */} + {enableQuickCreateIssue && }
- {!disableUserActions && + {/* {!disableUserActions && !isInlineCreateIssueFormOpen && (type === "issue" ? (
diff --git a/web/constants/issue.ts b/web/constants/issue.ts index 505f3bbdd..2e7983c11 100644 --- a/web/constants/issue.ts +++ b/web/constants/issue.ts @@ -1,3 +1,4 @@ +import { v4 as uuidv4 } from "uuid"; // icons import { Calendar, GanttChart, Kanban, List, Sheet } from "lucide-react"; // types @@ -11,6 +12,9 @@ import { TIssuePriorities, TIssueTypeFilters, TStateGroups, + IIssue, + IProject, + IWorkspace, } from "types"; export const ISSUE_PRIORITIES: { @@ -415,3 +419,74 @@ export const groupReactionEmojis = (reactions: any) => { return _groupedEmojis; }; + +/** + * + * @param workspaceDetail workspace detail to be added in the issue payload + * @param projectDetail project detail to be added in the issue payload + * @param formData partial issue data from the form. This will override the default values + * @returns full issue payload with some default values + */ + +export const createIssuePayload: ( + workspaceDetail: IWorkspace, + projectDetail: IProject, + formData: Partial +) => IIssue = (workspaceDetail: IWorkspace, projectDetail: IProject, formData: Partial) => { + const payload = { + archived_at: null, + assignees: [], + assignee_details: [], + assignees_list: [], + attachment_count: 0, + attachments: [], + issue_relations: [], + related_issues: [], + bridge_id: null, + completed_at: new Date(), + created_at: "", + created_by: "", + cycle: null, + cycle_id: null, + cycle_detail: null, + description: {}, + description_html: "", + description_stripped: "", + estimate_point: null, + issue_cycle: null, + issue_link: [], + issue_module: null, + labels: [], + label_details: [], + is_draft: false, + labels_list: [], + links_list: [], + link_count: 0, + module: null, + module_id: null, + name: "", + parent: null, + parent_detail: null, + priority: "none", + project: projectDetail.id, + project_detail: projectDetail, + sequence_id: 0, + sort_order: 0, + sprints: null, + start_date: null, + state: projectDetail.default_state, + state_detail: {} as any, + sub_issues_count: 0, + target_date: null, + updated_at: "", + updated_by: "", + workspace: workspaceDetail.id, + workspace_detail: workspaceDetail, + id: uuidv4(), + tempId: uuidv4(), + // to be overridden by the form data + ...formData, + } as IIssue; + + return payload; +}; diff --git a/web/store/issue/index.ts b/web/store/issue/index.ts index 7b6cb4f34..c66d617e1 100644 --- a/web/store/issue/index.ts +++ b/web/store/issue/index.ts @@ -4,3 +4,4 @@ export * from "./issue_filters.store"; export * from "./issue_kanban_view.store"; export * from "./issue_calendar_view.store"; export * from "./issue.store"; +export * from "./issue_quick_add.store"; diff --git a/web/store/issue/issue.store.ts b/web/store/issue/issue.store.ts index ec337abcb..85d726f78 100644 --- a/web/store/issue/issue.store.ts +++ b/web/store/issue/issue.store.ts @@ -34,6 +34,7 @@ export interface IIssueStore { // action fetchIssues: (workspaceSlug: string, projectId: string) => Promise; updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void; + removeIssueFromStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void; deleteIssue: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void; updateGanttIssueStructure: (workspaceSlug: string, issue: IIssue, payload: IBlockUpdateData) => void; } @@ -70,6 +71,7 @@ export class IssueStore implements IIssueStore { // actions fetchIssues: action, updateIssueStructure: action, + removeIssueFromStructure: action, deleteIssue: action, updateGanttIssueStructure: action, }); @@ -129,24 +131,33 @@ export class IssueStore implements IIssueStore { if (issueType === "grouped" && group_id) { issues = issues as IIssueGroupedStructure; + const _currentIssueId = issues?.[group_id]?.find((_i) => _i?.id === issue.id); issues = { ...issues, - [group_id]: issues[group_id].map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)), + [group_id]: _currentIssueId + ? issues[group_id]?.map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)) + : [...(issues?.[group_id] ?? []), issue], }; } if (issueType === "groupWithSubGroups" && group_id && sub_group_id) { issues = issues as IIssueGroupWithSubGroupsStructure; + const _currentIssueId = issues?.[sub_group_id]?.[group_id]?.find((_i) => _i?.id === issue.id); issues = { ...issues, [sub_group_id]: { ...issues[sub_group_id], - [group_id]: issues[sub_group_id][group_id].map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)), + [group_id]: _currentIssueId + ? issues?.[sub_group_id]?.[group_id]?.map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)) + : [...(issues?.[sub_group_id]?.[group_id] ?? []), issue], }, }; } if (issueType === "ungrouped") { issues = issues as IIssueUnGroupedStructure; - issues = issues.map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)); + const _currentIssueId = issues?.find((_i) => _i?.id === issue.id); + issues = _currentIssueId + ? issues?.map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)) + : [...(issues ?? []), issue]; } const orderBy = this.rootStore?.issueFilter?.userDisplayFilters?.order_by || ""; @@ -168,6 +179,43 @@ export class IssueStore implements IIssueStore { }); }; + removeIssueFromStructure = (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), + }, + }; + } + if (issueType === "ungrouped") { + issues = issues as IIssueUnGroupedStructure; + issues = issues.filter((i) => i?.id !== issue?.id); + } + + runInAction(() => { + this.issues = { ...this.issues, [projectId]: { ...this.issues[projectId], [issueType]: issues } }; + }); + }; + updateGanttIssueStructure = async (workspaceSlug: string, issue: IIssue, payload: IBlockUpdateData) => { if (!issue || !workspaceSlug) return; diff --git a/web/store/issue/issue_detail.store.ts b/web/store/issue/issue_detail.store.ts index b5acfa534..77f11d87b 100644 --- a/web/store/issue/issue_detail.store.ts +++ b/web/store/issue/issue_detail.store.ts @@ -6,6 +6,8 @@ import { RootStore } from "../root"; import { IIssue } from "types"; // constants import { groupReactionEmojis } from "constants/issue"; +// uuid +import { v4 as uuidv4 } from "uuid"; export interface IIssueDetailStore { loader: boolean; @@ -39,6 +41,7 @@ export interface IIssueDetailStore { fetchIssueDetails: (workspaceSlug: string, projectId: string, issueId: string) => Promise; // creating issue createIssue: (workspaceSlug: string, projectId: string, data: Partial) => Promise; + optimisticallyCreateIssue: (workspaceSlug: string, projectId: string, data: Partial) => Promise; // updating issue updateIssue: (workspaceId: string, projectId: string, issueId: string, data: Partial) => Promise; // deleting issue @@ -129,6 +132,7 @@ export class IssueDetailStore implements IIssueDetailStore { fetchIssueDetails: action, createIssue: action, + optimisticallyCreateIssue: action, updateIssue: action, deleteIssue: action, @@ -208,6 +212,44 @@ export class IssueDetailStore implements IIssueDetailStore { } }; + optimisticallyCreateIssue = async (workspaceSlug: string, projectId: string, data: Partial) => { + const tempId = data?.id || uuidv4(); + + runInAction(() => { + this.loader = true; + this.error = null; + this.issues = { + ...this.issues, + [tempId]: data as IIssue, + }; + }); + + try { + const response = await this.issueService.createIssue( + workspaceSlug, + projectId, + data, + this.rootStore.user.currentUser! + ); + + runInAction(() => { + this.loader = false; + this.error = null; + this.issues = { + ...this.issues, + [response.id]: response, + }; + }); + + return response; + } catch (error) { + this.loader = false; + this.error = error; + + throw error; + } + }; + createIssue = async (workspaceSlug: string, projectId: string, data: Partial) => { try { runInAction(() => { diff --git a/web/store/issue/issue_quick_add.store.ts b/web/store/issue/issue_quick_add.store.ts new file mode 100644 index 000000000..44683b578 --- /dev/null +++ b/web/store/issue/issue_quick_add.store.ts @@ -0,0 +1,227 @@ +import { observable, action, makeObservable, runInAction } from "mobx"; +// services +import { IssueService } from "services/issue"; +// types +import { RootStore } from "../root"; +import { IIssue } from "types"; +// uuid +import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers"; +import { IIssueGroupWithSubGroupsStructure, IIssueGroupedStructure, IIssueUnGroupedStructure } from "./issue.store"; + +export interface IIssueQuickAddStore { + loader: boolean; + error: any | null; + + createIssue: ( + workspaceSlug: string, + projectId: string, + grouping: { + group_id: string | null; + sub_group_id: string | null; + }, + data: Partial + ) => Promise; + updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void; + updateQuickAddIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void; +} + +export class IssueQuickAddStore implements IIssueQuickAddStore { + loader: boolean = false; + error: any | null = null; + + // root store + rootStore; + // service + issueService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable.ref, + error: observable.ref, + + createIssue: action, + updateIssueStructure: action, + }); + + this.rootStore = _rootStore; + this.issueService = new IssueService(); + } + + createIssue = async ( + workspaceSlug: string, + projectId: string, + grouping: { + group_id: string | null; + sub_group_id: string | null; + }, + data: Partial + ) => { + runInAction(() => { + this.loader = true; + this.error = null; + }); + + const { group_id, sub_group_id } = grouping; + + try { + this.updateIssueStructure(group_id, sub_group_id, data as IIssue); + + const response = await this.issueService.createIssue( + workspaceSlug, + projectId, + data, + this.rootStore.user.currentUser! + ); + + this.updateQuickAddIssueStructure(group_id, sub_group_id, { + ...data, + ...response, + }); + + runInAction(() => { + this.loader = false; + this.error = null; + }); + + return response; + } catch (error) { + this.loader = false; + this.error = error; + + throw error; + } + }; + + updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => { + const projectId: string | null = issue?.project; + const issueType = this.rootStore.issue.getIssueType; + if (!projectId || !issueType) return null; + + let issues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null = + this.rootStore.issue.getIssues; + if (!issues) return null; + + if (group_id === "null") group_id = null; + if (sub_group_id === "null") sub_group_id = null; + + if (issueType === "grouped" && group_id) { + issues = issues as IIssueGroupedStructure; + const _currentIssueId = issues?.[group_id]?.find((_i) => _i?.id === issue.id); + issues = { + ...issues, + [group_id]: _currentIssueId + ? issues[group_id]?.map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)) + : [...(issues?.[group_id] ?? []), issue], + }; + } + if (issueType === "groupWithSubGroups" && group_id && sub_group_id) { + issues = issues as IIssueGroupWithSubGroupsStructure; + const _currentIssueId = issues?.[sub_group_id]?.[group_id]?.find((_i) => _i?.id === issue.id); + issues = { + ...issues, + [sub_group_id]: { + ...issues[sub_group_id], + [group_id]: _currentIssueId + ? issues?.[sub_group_id]?.[group_id]?.map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)) + : [...(issues?.[sub_group_id]?.[group_id] ?? []), issue], + }, + }; + } + if (issueType === "ungrouped") { + issues = issues as IIssueUnGroupedStructure; + const _currentIssueId = issues?.find((_i) => _i?.id === issue.id); + issues = _currentIssueId + ? issues?.map((i: IIssue) => (i?.id === issue?.id ? { ...i, ...issue } : i)) + : [...(issues ?? []), issue]; + } + + const orderBy = this.rootStore?.issueFilter?.userDisplayFilters?.order_by || ""; + if (orderBy === "-created_at") { + issues = sortArrayByDate(issues as any, "created_at"); + } + if (orderBy === "-updated_at") { + issues = sortArrayByDate(issues as any, "updated_at"); + } + if (orderBy === "start_date") { + issues = sortArrayByDate(issues as any, "updated_at"); + } + if (orderBy === "priority") { + issues = sortArrayByPriority(issues as any, "priority"); + } + + runInAction(() => { + this.rootStore.issue.issues = { + ...this.rootStore.issue.issues, + [projectId]: { ...this.rootStore.issue.issues[projectId], [issueType]: issues }, + }; + }); + }; + + // same as above function but will use temp id instead of real id + updateQuickAddIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => { + const projectId: string | null = issue?.project; + const issueType = this.rootStore.issue.getIssueType; + if (!projectId || !issueType) return null; + + let issues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null = + this.rootStore.issue.getIssues; + if (!issues) return null; + + if (issueType === "grouped" && group_id) { + issues = issues as IIssueGroupedStructure; + const _currentIssueId = issues?.[group_id]?.find((_i) => _i?.tempId === issue.tempId); + issues = { + ...issues, + [group_id]: _currentIssueId + ? issues[group_id]?.map((i: IIssue) => + i?.tempId === issue?.tempId ? { ...i, ...issue, tempId: undefined } : i + ) + : [...(issues?.[group_id] ?? []), issue], + }; + } + if (issueType === "groupWithSubGroups" && group_id && sub_group_id) { + issues = issues as IIssueGroupWithSubGroupsStructure; + const _currentIssueId = issues?.[sub_group_id]?.[group_id]?.find((_i) => _i?.tempId === issue.tempId); + issues = { + ...issues, + [sub_group_id]: { + ...issues[sub_group_id], + [group_id]: _currentIssueId + ? issues?.[sub_group_id]?.[group_id]?.map((i: IIssue) => + i?.tempId === issue?.tempId ? { ...i, ...issue, tempId: undefined } : i + ) + : [...(issues?.[sub_group_id]?.[group_id] ?? []), issue], + }, + }; + } + if (issueType === "ungrouped") { + issues = issues as IIssueUnGroupedStructure; + const _currentIssueId = issues?.find((_i) => _i?.tempId === issue.tempId); + issues = _currentIssueId + ? issues?.map((i: IIssue) => (i?.tempId === issue?.tempId ? { ...i, ...issue, tempId: undefined } : i)) + : [...(issues ?? []), issue]; + } + + const orderBy = this.rootStore?.issueFilter?.userDisplayFilters?.order_by || ""; + if (orderBy === "-created_at") { + issues = sortArrayByDate(issues as any, "created_at"); + } + if (orderBy === "-updated_at") { + issues = sortArrayByDate(issues as any, "updated_at"); + } + if (orderBy === "start_date") { + issues = sortArrayByDate(issues as any, "updated_at"); + } + if (orderBy === "priority") { + issues = sortArrayByPriority(issues as any, "priority"); + } + + runInAction(() => { + this.rootStore.issue.issues = { + ...this.rootStore.issue.issues, + [projectId]: { ...this.rootStore.issue.issues[projectId], [issueType]: issues }, + }; + }); + }; +} diff --git a/web/store/root.ts b/web/store/root.ts index 1a85185d6..fabf7ed9d 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -15,6 +15,8 @@ import { IIssueCalendarViewStore, IssueCalendarViewStore, IssueStore, + IIssueQuickAddStore, + IssueQuickAddStore, } from "store/issue"; import { IWorkspaceFilterStore, IWorkspaceStore, WorkspaceFilterStore, WorkspaceStore } from "store/workspace"; import { IProjectPublishStore, IProjectStore, ProjectPublishStore, ProjectStore } from "store/project"; @@ -121,6 +123,7 @@ export class RootStore { issueKanBanView: IIssueKanBanViewStore; issueCalendarView: IIssueCalendarViewStore; draftIssuesStore: DraftIssuesStore; + quickAddIssue: IIssueQuickAddStore; calendar: ICalendarStore; @@ -176,6 +179,7 @@ export class RootStore { this.issueKanBanView = new IssueKanBanViewStore(this); this.issueCalendarView = new IssueCalendarViewStore(this); this.draftIssuesStore = new DraftIssuesStore(this); + this.quickAddIssue = new IssueQuickAddStore(this); this.calendar = new CalendarStore(this); diff --git a/web/types/issues.d.ts b/web/types/issues.d.ts index 2e242df8c..164718237 100644 --- a/web/types/issues.d.ts +++ b/web/types/issues.d.ts @@ -97,6 +97,8 @@ export interface IIssue { description_stripped: any; estimate_point: number | null; id: string; + // tempId is used for optimistic updates. It is not a part of the API response. + tempId?: string; issue_cycle: IIssueCycle | null; issue_link: linkDetails[]; issue_module: IIssueModule | null; diff --git a/yarn.lock b/yarn.lock index 1490d6ac0..e95d031bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44,38 +44,38 @@ "@babel/highlight" "^7.22.13" chalk "^2.4.2" -"@babel/compat-data@^7.22.20", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" - integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9", "@babel/compat-data@^7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.2.tgz#6a12ced93455827037bfb5ed8492820d60fc32cc" + integrity sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ== "@babel/core@^7.11.1": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.20.tgz#e3d0eed84c049e2a2ae0a64d27b6a37edec385b7" - integrity sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA== + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.2.tgz#ed10df0d580fff67c5f3ee70fd22e2e4c90a9f94" + integrity sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" + "@babel/generator" "^7.23.0" "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-module-transforms" "^7.22.20" - "@babel/helpers" "^7.22.15" - "@babel/parser" "^7.22.16" + "@babel/helper-module-transforms" "^7.23.0" + "@babel/helpers" "^7.23.2" + "@babel/parser" "^7.23.0" "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.20" - "@babel/types" "^7.22.19" - convert-source-map "^1.7.0" + "@babel/traverse" "^7.23.2" + "@babel/types" "^7.23.0" + convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" - integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== +"@babel/generator@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" + integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== dependencies: - "@babel/types" "^7.22.15" + "@babel/types" "^7.23.0" "@jridgewell/gen-mapping" "^0.3.2" "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" @@ -129,10 +129,10 @@ regexpu-core "^5.3.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz#82c825cadeeeee7aad237618ebbe8fa1710015d7" - integrity sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw== +"@babel/helper-define-polyfill-provider@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz#a71c10f7146d809f4a256c373f462d9bba8cf6ba" + integrity sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug== dependencies: "@babel/helper-compilation-targets" "^7.22.6" "@babel/helper-plugin-utils" "^7.22.5" @@ -145,13 +145,13 @@ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== -"@babel/helper-function-name@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" - integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== +"@babel/helper-function-name@^7.22.5", "@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: - "@babel/template" "^7.22.5" - "@babel/types" "^7.22.5" + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" "@babel/helper-hoist-variables@^7.22.5": version "7.22.5" @@ -161,11 +161,11 @@ "@babel/types" "^7.22.5" "@babel/helper-member-expression-to-functions@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz#b95a144896f6d491ca7863576f820f3628818621" - integrity sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA== + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz#9263e88cc5e41d39ec18c9a3e0eced59a3e7d366" + integrity sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA== dependencies: - "@babel/types" "^7.22.15" + "@babel/types" "^7.23.0" "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.22.5": version "7.22.15" @@ -174,10 +174,10 @@ dependencies: "@babel/types" "^7.22.15" -"@babel/helper-module-transforms@^7.22.15", "@babel/helper-module-transforms@^7.22.20", "@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz#da9edc14794babbe7386df438f3768067132f59e" - integrity sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A== +"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" + integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw== dependencies: "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-module-imports" "^7.22.15" @@ -197,7 +197,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== -"@babel/helper-remap-async-to-generator@^7.22.5", "@babel/helper-remap-async-to-generator@^7.22.9": +"@babel/helper-remap-async-to-generator@^7.22.20", "@babel/helper-remap-async-to-generator@^7.22.5": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz#7b68e1cb4fa964d2996fd063723fb48eca8498e0" integrity sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw== @@ -241,7 +241,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== -"@babel/helper-validator-identifier@^7.22.19", "@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.22.5": +"@babel/helper-validator-identifier@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== @@ -260,14 +260,14 @@ "@babel/template" "^7.22.15" "@babel/types" "^7.22.19" -"@babel/helpers@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1" - integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw== +"@babel/helpers@^7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.2.tgz#2832549a6e37d484286e15ba36a5330483cac767" + integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ== dependencies: "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.15" - "@babel/types" "^7.22.15" + "@babel/traverse" "^7.23.2" + "@babel/types" "^7.23.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.22.13": version "7.22.20" @@ -278,10 +278,10 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.22.15", "@babel/parser@^7.22.16": - version "7.22.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" - integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== +"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.15": version "7.22.15" @@ -438,14 +438,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-async-generator-functions@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz#3b153af4a6b779f340d5b80d3f634f55820aefa3" - integrity sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w== +"@babel/plugin-transform-async-generator-functions@^7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.2.tgz#054afe290d64c6f576f371ccc321772c8ea87ebb" + integrity sha512-BBYVGxbDVHfoeXbOwcagAkOQAm9NxoTdMGfTqghu1GrvadSaw6iW3Je6IcL5PNOw8VwjxqBECXy50/iCQSY/lQ== dependencies: - "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-remap-async-to-generator" "^7.22.9" + "@babel/helper-remap-async-to-generator" "^7.22.20" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-transform-async-to-generator@^7.22.5": @@ -464,10 +464,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-block-scoping@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz#494eb82b87b5f8b1d8f6f28ea74078ec0a10a841" - integrity sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw== +"@babel/plugin-transform-block-scoping@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz#8744d02c6c264d82e1a4bc5d2d501fd8aff6f022" + integrity sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -511,10 +511,10 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/template" "^7.22.5" -"@babel/plugin-transform-destructuring@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz#e7404ea5bb3387073b9754be654eecb578324694" - integrity sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ== +"@babel/plugin-transform-destructuring@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz#6447aa686be48b32eaf65a73e0e2c0bd010a266c" + integrity sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -603,32 +603,32 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-amd@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz#4e045f55dcf98afd00f85691a68fc0780704f526" - integrity sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ== +"@babel/plugin-transform-modules-amd@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.0.tgz#05b2bc43373faa6d30ca89214731f76f966f3b88" + integrity sha512-xWT5gefv2HGSm4QHtgc1sYPbseOyf+FFDo2JbpE25GWl5BqTGO9IMwTYJRoIdjsF85GE+VegHxSCUt5EvoYTAw== dependencies: - "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-module-transforms" "^7.23.0" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-commonjs@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz#b11810117ed4ee7691b29bd29fd9f3f98276034f" - integrity sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg== +"@babel/plugin-transform-modules-commonjs@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz#b3dba4757133b2762c00f4f94590cf6d52602481" + integrity sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ== dependencies: - "@babel/helper-module-transforms" "^7.22.15" + "@babel/helper-module-transforms" "^7.23.0" "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-simple-access" "^7.22.5" -"@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== +"@babel/plugin-transform-modules-systemjs@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.0.tgz#77591e126f3ff4132a40595a6cccd00a6b60d160" + integrity sha512-qBej6ctXZD2f+DhlOC9yO47yEYgUh5CZNz/aBoH4j/3NOlRfJXJbY7xDQCqQVf9KbrqGzIWER1f23doHGrIHFg== dependencies: "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-module-transforms" "^7.22.9" + "@babel/helper-module-transforms" "^7.23.0" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" "@babel/plugin-transform-modules-umd@^7.22.5": version "7.22.5" @@ -696,10 +696,10 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-transform-optional-chaining@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz#d7a5996c2f7ca4ad2ad16dbb74444e5c4385b1ba" - integrity sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A== +"@babel/plugin-transform-optional-chaining@^7.22.15", "@babel/plugin-transform-optional-chaining@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.0.tgz#73ff5fc1cf98f542f09f29c0631647d8ad0be158" + integrity sha512-sBBGXbLJjxTzLBF5rFWaikMnOGOk/BmK6vVByIdEggZ7Vn6CvWXZyRkkLFK6WE0IF8jSliyOkUN6SScFgzCM0g== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" @@ -820,11 +820,11 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/preset-env@^7.11.0": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.20.tgz#de9e9b57e1127ce0a2f580831717f7fb677ceedb" - integrity sha512-11MY04gGC4kSzlPHRfvVkNAZhUxOvm7DCJ37hPDnUENwe06npjIRAfInEMTGSb4LZK5ZgDFkv5hw0lGebHeTyg== + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.23.2.tgz#1f22be0ff0e121113260337dbc3e58fafce8d059" + integrity sha512-BW3gsuDD+rvHL2VO2SjAUNTBe5YrjsTiDyqamPDWY723na3/yPQ65X5oQkFVJZ0o50/2d+svm1rkPoJeR1KxVQ== dependencies: - "@babel/compat-data" "^7.22.20" + "@babel/compat-data" "^7.23.2" "@babel/helper-compilation-targets" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-validator-option" "^7.22.15" @@ -850,15 +850,15 @@ "@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.15" + "@babel/plugin-transform-async-generator-functions" "^7.23.2" "@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.15" + "@babel/plugin-transform-block-scoping" "^7.23.0" "@babel/plugin-transform-class-properties" "^7.22.5" "@babel/plugin-transform-class-static-block" "^7.22.11" "@babel/plugin-transform-classes" "^7.22.15" "@babel/plugin-transform-computed-properties" "^7.22.5" - "@babel/plugin-transform-destructuring" "^7.22.15" + "@babel/plugin-transform-destructuring" "^7.23.0" "@babel/plugin-transform-dotall-regex" "^7.22.5" "@babel/plugin-transform-duplicate-keys" "^7.22.5" "@babel/plugin-transform-dynamic-import" "^7.22.11" @@ -870,9 +870,9 @@ "@babel/plugin-transform-literals" "^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.15" - "@babel/plugin-transform-modules-systemjs" "^7.22.11" + "@babel/plugin-transform-modules-amd" "^7.23.0" + "@babel/plugin-transform-modules-commonjs" "^7.23.0" + "@babel/plugin-transform-modules-systemjs" "^7.23.0" "@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" @@ -881,7 +881,7 @@ "@babel/plugin-transform-object-rest-spread" "^7.22.15" "@babel/plugin-transform-object-super" "^7.22.5" "@babel/plugin-transform-optional-catch-binding" "^7.22.11" - "@babel/plugin-transform-optional-chaining" "^7.22.15" + "@babel/plugin-transform-optional-chaining" "^7.23.0" "@babel/plugin-transform-parameters" "^7.22.15" "@babel/plugin-transform-private-methods" "^7.22.5" "@babel/plugin-transform-private-property-in-object" "^7.22.11" @@ -898,10 +898,10 @@ "@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.19" - babel-plugin-polyfill-corejs2 "^0.4.5" - babel-plugin-polyfill-corejs3 "^0.8.3" - babel-plugin-polyfill-regenerator "^0.5.2" + "@babel/types" "^7.23.0" + babel-plugin-polyfill-corejs2 "^0.4.6" + babel-plugin-polyfill-corejs3 "^0.8.5" + babel-plugin-polyfill-regenerator "^0.5.3" core-js-compat "^3.31.0" semver "^6.3.1" @@ -919,17 +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.15", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8" - integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.12.1", "@babel/runtime@^7.22.5": - version "7.23.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d" - integrity sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g== +"@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": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" + integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== dependencies: regenerator-runtime "^0.14.0" @@ -942,29 +935,29 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.20.tgz#db572d9cb5c79e02d83e5618b82f6991c07584c9" - integrity sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw== +"@babel/traverse@^7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== dependencies: "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" + "@babel/generator" "^7.23.0" "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.22.5" + "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.22.16" - "@babel/types" "^7.22.19" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.4.4": - version "7.22.19" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684" - integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg== +"@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.4.4": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== dependencies: "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.19" + "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" "@blueprintjs/colors@^4.2.1": @@ -974,10 +967,10 @@ dependencies: tslib "~2.5.0" -"@blueprintjs/colors@^5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@blueprintjs/colors/-/colors-5.0.2.tgz#c1308fbf156b6ebc3e22e88eaad47dc274c2a4b4" - integrity sha512-icP/d5sheRT8ReRy6jf6WunvLmDQWXFjFU97/xKsqF5SMOWIYC92I0b/705dmc+z5lAXntkU67pCMRuNWSZ9lQ== +"@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== dependencies: tslib "~2.5.0" @@ -998,13 +991,13 @@ react-transition-group "^4.4.5" tslib "~2.5.0" -"@blueprintjs/core@^5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-5.3.0.tgz#5e4d00797c684f6e417e3d1707ac2141f67f70a0" - integrity sha512-Pzd/ptszeX/Vt5rMa7AFSRlxw8sMs2xhCs4Xje2tTsQUaElbmH1oJbzDyAjSs50na6ncKEmPIvkhXz5ggB1rrA== +"@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== dependencies: - "@blueprintjs/colors" "^5.0.2" - "@blueprintjs/icons" "^5.1.6" + "@blueprintjs/colors" "^5.0.4" + "@blueprintjs/icons" "^5.2.1" "@popperjs/core" "^2.11.7" classnames "^2.3.1" normalize.css "^8.0.1" @@ -1021,10 +1014,10 @@ classnames "^2.3.1" tslib "~2.5.0" -"@blueprintjs/icons@^5.1.6": - version "5.1.6" - resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-5.1.6.tgz#3882cd3a01a1f83dbe584851955a7459d0a78704" - integrity sha512-W87oUP082sZ+dh5oxbgARCHGDyELVKXC+ffxkMYeK3M3hDn0UBSCUZgWZMLltf0qGfFRXlkY+Vn3G08at6xXSw== +"@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== dependencies: change-case "^4.1.2" classnames "^2.3.1" @@ -1044,11 +1037,11 @@ tslib "~2.5.0" "@blueprintjs/popover2@^2.0.10": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@blueprintjs/popover2/-/popover2-2.0.10.tgz#916718688a7d2a9dfc6a5af0a806a8ecef8273f6" - integrity sha512-NE6lgzu6MXfI4lruTw0sXkQ0i7H4RyEWJ0nCEAW1FGdy2KJOkJ7U5RNtBKjT/F4ChaKmoHVL94CaCwqQtB7yOQ== + version "2.0.16" + resolved "https://registry.yarnpkg.com/@blueprintjs/popover2/-/popover2-2.0.16.tgz#208d248efd6e129ba5580707fffde57cb2527365" + integrity sha512-WFQdvhybzVHbkwFt0TdQ285XGP1PN3XH+x0TgMby3j5xBUPBd6UDZ6pZup2ZCMfxB9GGglyAip5ZFM7tRWW6Vg== dependencies: - "@blueprintjs/core" "^5.3.0" + "@blueprintjs/core" "^5.5.1" classnames "^2.3.1" tslib "~2.5.0" @@ -1077,9 +1070,9 @@ "@egjs/list-differ" "^1.0.0" "@egjs/component@^3.0.2": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@egjs/component/-/component-3.0.4.tgz#ad7b53794b2a612806179a188ad828acb9525f61" - integrity sha512-sXA7bGbIeLF2OAw/vpka66c6QBBUPcA4UUhR4WGJfnp2XWdiI8QrnJGJMr/UxpE/xnevX9tN3jvNPlW8WkHl3g== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@egjs/component/-/component-3.0.5.tgz#2dc86e835d5dc5055cdf46c7cd794eb45330e1b6" + integrity sha512-cLcGizTrrUNA2EYE3MBmEDt2tQv1joVP1Q3oDisZ5nw0MZDx2kcgEXM+/kZpfa/PAkFvYVhRUZwytIQWoN3V/w== "@egjs/list-differ@^1.0.0": version "1.0.1" @@ -1316,9 +1309,9 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.1.tgz#8c4bb756cc2aa7eaf13cfa5e69c83afb3260c20c" - integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ== + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" + integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== "@eslint/eslintrc@^0.4.3": version "0.4.3" @@ -1370,10 +1363,10 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== -"@eslint/js@8.49.0": - version "8.49.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" - integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== +"@eslint/js@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" + integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== "@floating-ui/core@^1.4.2": version "1.5.0" @@ -1398,9 +1391,9 @@ "@floating-ui/dom" "^1.5.1" "@floating-ui/utils@^0.1.3": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.4.tgz#19654d1026cc410975d46445180e70a5089b3e7d" - integrity sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA== + version "0.1.6" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9" + integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A== "@headlessui/react@^1.7.13", "@headlessui/react@^1.7.17", "@headlessui/react@^1.7.3": version "1.7.17" @@ -1422,12 +1415,12 @@ redux "^4.2.1" use-memo-one "^1.1.3" -"@humanwhocodes/config-array@^0.11.11", "@humanwhocodes/config-array@^0.11.8": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@humanwhocodes/config-array@^0.11.13", "@humanwhocodes/config-array@^0.11.8": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" + "@humanwhocodes/object-schema" "^2.0.1" debug "^4.1.1" minimatch "^3.0.5" @@ -1445,11 +1438,16 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.0", "@humanwhocodes/object-schema@^1.2.1": +"@humanwhocodes/object-schema@^1.2.0": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== + "@hypnosphi/create-react-context@^0.3.1": version "0.3.1" resolved "https://registry.yarnpkg.com/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz#f8bfebdc7665f5d426cba3753e0e9c7d3154d7c6" @@ -1509,9 +1507,9 @@ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" @@ -1521,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.16": - version "5.0.0-beta.16" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.16.tgz#5869b8cc83ea5da0083bb11790bda007c2384564" - integrity sha512-OYxhC81c9bO0wobGcM8rrY5bRwpCXAI21BL0P2wz/2vTv4ek7ALz9+U5M8wgdmtRNUhmCmAB4L2WRwFRf5Cd8Q== +"@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== dependencies: - "@babel/runtime" "^7.22.15" + "@babel/runtime" "^7.23.2" "@floating-ui/react-dom" "^2.0.2" - "@mui/types" "^7.2.4" - "@mui/utils" "^5.14.10" + "@mui/types" "^7.2.7" + "@mui/utils" "^5.14.15" "@popperjs/core" "^2.11.8" clsx "^2.0.0" prop-types "^15.8.1" -"@mui/core-downloads-tracker@^5.14.10": - version "5.14.10" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.10.tgz#32a8581be98344bbda5ed31fc7b41788bd2e3bc5" - integrity sha512-kPHu/NhZq1k+vSZR5wq3AyUfD4bnfWAeuKpps0+8PS7ZHQ2Lyv1cXJh+PlFdCIOa0PK98rk3JPwMzS8BMhdHwQ== +"@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/material@^5.14.1": - version "5.14.10" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.10.tgz#b8c6ba17c25c0df54053cb0f1bb35083bc91dace" - integrity sha512-ejFMppnO+lzBXpzju+N4SSz0Mhmi5sihXUGcr5FxpgB6bfUP0Lpe32O0Sw/3s8xlmLEvG1fqVT0rRyAVMlCA+A== + version "5.14.15" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.15.tgz#dadc58588aef4556a0ed6a2d70ad70922df5264f" + integrity sha512-Gq65rHjvLzkxmhG8bvag851Oqsmru7qkUb/cCI2xu7dQzmY345f9xJRJi72sRGjhaqHXWeRKw/yIwp/7oQoeXg== dependencies: - "@babel/runtime" "^7.22.15" - "@mui/base" "5.0.0-beta.16" - "@mui/core-downloads-tracker" "^5.14.10" - "@mui/system" "^5.14.10" - "@mui/types" "^7.2.4" - "@mui/utils" "^5.14.10" - "@types/react-transition-group" "^4.4.6" + "@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" 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.10": - version "5.14.10" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.14.10.tgz#42b176b27435931aff40d50833413d10150ac007" - integrity sha512-f67xOj3H06wWDT9xBg7hVL/HSKNF+HG1Kx0Pm23skkbEqD2Ef2Lif64e5nPdmWVv+7cISCYtSuE2aeuzrZe78w== +"@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== dependencies: - "@babel/runtime" "^7.22.15" - "@mui/utils" "^5.14.10" + "@babel/runtime" "^7.23.2" + "@mui/utils" "^5.14.15" prop-types "^15.8.1" -"@mui/styled-engine@^5.14.10": - version "5.14.10" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.14.10.tgz#2ec443031e48425cd6fda63be498cfa262c1d3a0" - integrity sha512-EJckxmQHrsBvDbFu1trJkvjNw/1R7jfNarnqPSnL+jEQawCkQIqVELWLrlOa611TFtxSJGkdUfCFXeJC203HVg== +"@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== dependencies: - "@babel/runtime" "^7.22.15" + "@babel/runtime" "^7.23.2" "@emotion/cache" "^11.11.0" csstype "^3.1.2" prop-types "^15.8.1" -"@mui/system@^5.14.10": - version "5.14.10" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.10.tgz#b125f8370c1c92af04f1839c40e034d4edc4ad29" - integrity sha512-QQmtTG/R4gjmLiL5ECQ7kRxLKDm8aKKD7seGZfbINtRVJDyFhKChA1a+K2bfqIAaBo1EMDv+6FWNT1Q5cRKjFA== +"@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== dependencies: - "@babel/runtime" "^7.22.15" - "@mui/private-theming" "^5.14.10" - "@mui/styled-engine" "^5.14.10" - "@mui/types" "^7.2.4" - "@mui/utils" "^5.14.10" + "@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" clsx "^2.0.0" csstype "^3.1.2" prop-types "^15.8.1" -"@mui/types@^7.2.4": - version "7.2.4" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328" - integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA== +"@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/utils@^5.14.10": - version "5.14.10" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.10.tgz#4b0a2a26f1ee12323010daa9d7aecf3384acfc3c" - integrity sha512-Rn+vYQX7FxkcW0riDX/clNUwKuOJFH45HiULxwmpgnzQoQr3A0lb+QYwaZ+FAkZrR7qLoHKmLQlcItu6LT0y/Q== +"@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== dependencies: - "@babel/runtime" "^7.22.15" - "@types/prop-types" "^15.7.5" + "@babel/runtime" "^7.23.2" + "@types/prop-types" "^15.7.8" prop-types "^15.8.1" react-is "^18.2.0" @@ -2160,18 +2158,18 @@ picomatch "^2.2.2" "@rollup/pluginutils@^5.0.1": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.4.tgz#74f808f9053d33bafec0cc98e7b835c9667d32ba" - integrity sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g== + version "5.0.5" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.5.tgz#bbb4c175e19ebfeeb8c132c2eea0ecb89941a66c" + integrity sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q== dependencies: "@types/estree" "^1.0.0" estree-walker "^2.0.2" picomatch "^2.3.1" "@rushstack/eslint-patch@^1.1.3": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.4.0.tgz#77e948b9760bd22736a5d26e335a690f76fda37b" - integrity sha512-cEjvTPU32OM9lUFegJagO0mRnIn+rbqrG89vV8/xLnLFX0DoR0r1oy5IlTga71Q7uT3Qus7qm7wgeiMT/+Irlg== + version "1.5.1" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz#5f1b518ec5fa54437c0b7c4a821546c64fed6922" + integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA== "@scena/dragscroll@^1.4.0": version "1.4.0" @@ -2195,27 +2193,25 @@ dependencies: "@daybrush/utils" "^1.4.0" -"@sentry-internal/tracing@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.69.0.tgz#8d8eb740b72967b6ba3fdc0a5173aa55331b7d35" - integrity sha512-4BgeWZUj9MO6IgfO93C9ocP3+AdngqujF/+zB2rFdUe+y9S6koDyUC7jr9Knds/0Ta72N/0D6PwhgSCpHK8s0Q== +"@sentry-internal/tracing@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.75.0.tgz#0d6cb4d3ff4ea6dd456f64455b2d505d7eb27656" + integrity sha512-/j4opF/jB9j8qnSiQK75/lFLtkfqXS5/MoOKc2KWK/pOaf15W+6uJzGQ8jRBHLYd9dDg6AyqsF48Wqy561/mNg== dependencies: - "@sentry/core" "7.69.0" - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" - tslib "^2.4.1 || ^1.9.3" + "@sentry/core" "7.75.0" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" -"@sentry/browser@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.69.0.tgz#65427c90fb71c1775e2c1e38431efb7f4aec1e34" - integrity sha512-5ls+zu2PrMhHCIIhclKQsWX5u6WH0Ez5/GgrCMZTtZ1d70ukGSRUvpZG9qGf5Cw1ezS1LY+1HCc3whf8x8lyPw== +"@sentry/browser@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.75.0.tgz#7ea88f335c7bbaf3b5eecbf4e12590785abc0ee7" + integrity sha512-DXH/69vzp2j8xjydX+lrUYasrk7a1mpbXFGA9GtnII7shMCy55+QkVxpa6cLojYUaG2K/8yFDMcrP9N395LnWg== dependencies: - "@sentry-internal/tracing" "7.69.0" - "@sentry/core" "7.69.0" - "@sentry/replay" "7.69.0" - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" - tslib "^2.4.1 || ^1.9.3" + "@sentry-internal/tracing" "7.75.0" + "@sentry/core" "7.75.0" + "@sentry/replay" "7.75.0" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" "@sentry/cli@^1.74.6": version "1.75.2" @@ -2229,89 +2225,94 @@ proxy-from-env "^1.1.0" which "^2.0.2" -"@sentry/core@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.69.0.tgz#ebbe01df573f438f8613107020a4e18eb9adca4d" - integrity sha512-V6jvK2lS8bhqZDMFUtvwe2XvNstFQf5A+2LMKCNBOV/NN6eSAAd6THwEpginabjet9dHsNRmMk7WNKvrUfQhZw== +"@sentry/core@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.75.0.tgz#d5477faf9afdfbf45b4ff46b809729f14d4e1b80" + integrity sha512-vXg3cdJgwzP24oTS9zFCgLW4MgTkMZqXx+ESRq7gTD9qJTpcmAmYT+Ckmvebg8K6DBThV6+0v61r50na2+XdrA== dependencies: - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" - tslib "^2.4.1 || ^1.9.3" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" -"@sentry/integrations@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.69.0.tgz#04c0206d9436ec7b79971e3bde5d6e1e9194595f" - integrity sha512-FEFtFqXuCo9+L7bENZxFpEAlIODwHl6FyW/DwLfniy9jOXHU7BhP/oICLrFE5J7rh1gNY7N/8VlaiQr3hCnS/g== +"@sentry/integrations@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.75.0.tgz#0dcee498b34b4075856d67698d317f8e3c0b96f0" + integrity sha512-dnKZvPJBj+KiOIteYJEVuZcB3Hcd6NYdQ3xJhGk5FD4+gGOHTF+8kMdBC6q+Rnkyc63IB0vPRMhhs/T5XbWByg== dependencies: - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" + "@sentry/core" "7.75.0" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" localforage "^1.8.1" - tslib "^2.4.1 || ^1.9.3" "@sentry/nextjs@^7.36.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.69.0.tgz#371db2b66de43873e185f6e813567a6e635dfc42" - integrity sha512-PLgVL07pJafRZZ1parTK6g1GKfdZU/afN/6hs5HrdLeovcpSunEwj3guoHHrewFEbDjj021+0JaG16qnNeAPgQ== + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.75.0.tgz#5f93743fbbe6add7b7a01fb3aebdb844c37ee2ec" + integrity sha512-EKdTUe5Q48qRgFM7T9s9sXwOEMvaouepHF5m343jSuTugTQ7CCJIR9jLGgUuRPgaUdE0F+PyJWopgVAZpaVFSg== dependencies: "@rollup/plugin-commonjs" "24.0.0" - "@sentry/core" "7.69.0" - "@sentry/integrations" "7.69.0" - "@sentry/node" "7.69.0" - "@sentry/react" "7.69.0" - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" + "@sentry/core" "7.75.0" + "@sentry/integrations" "7.75.0" + "@sentry/node" "7.75.0" + "@sentry/react" "7.75.0" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" + "@sentry/vercel-edge" "7.75.0" "@sentry/webpack-plugin" "1.20.0" chalk "3.0.0" + resolve "1.22.8" rollup "2.78.0" stacktrace-parser "^0.1.10" - tslib "^2.4.1 || ^1.9.3" -"@sentry/node@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.69.0.tgz#938200095a17f41a2445fec168df293db7c24836" - integrity sha512-T0NgPcmDQvEuz5hy6aEhXghTHHTWsiP3IWoeEAakDBHAXmtpT6lYFQZgb5AiEOt9F5KO/G/1yH3YYdpDAnKhPw== +"@sentry/node@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.75.0.tgz#49f851d49e1c5cdaca64933ca5a9214edeed5e82" + integrity sha512-z5Xanf9QeTd4YrEuZiJfvtAy2C874Zg4KpurEo3okJ8uYjnbXMsQ3EwVHbKEoYSwE3ExTrqOggPfk2NNSJIECA== dependencies: - "@sentry-internal/tracing" "7.69.0" - "@sentry/core" "7.69.0" - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" - cookie "^0.4.1" + "@sentry-internal/tracing" "7.75.0" + "@sentry/core" "7.75.0" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^2.4.1 || ^1.9.3" -"@sentry/react@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.69.0.tgz#b9931ac590d8dad3390a9a03a516f1b1bd75615e" - integrity sha512-J+DciRRVuruf1nMmBOi2VeJkOLGeCb4vTOFmHzWTvRJNByZ0flyo8E/fyROL7+23kBq1YbcVY6IloUlH73hneQ== +"@sentry/react@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.75.0.tgz#5299ad2f42832cb7fd733a5bc09edc1ca47d2251" + integrity sha512-v3293R4YSF4HXLf0AKr5Oa0+cctXiGAHlygiqatMdOrEh/HqjTm2YGIoE8uYUM3/aI+xsr7ZmJ1KS6o0WWR6yA== dependencies: - "@sentry/browser" "7.69.0" - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" + "@sentry/browser" "7.75.0" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" hoist-non-react-statics "^3.3.2" - tslib "^2.4.1 || ^1.9.3" -"@sentry/replay@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.69.0.tgz#d727f96292d2b7c25df022fa53764fd39910fcda" - integrity sha512-oUqWyBPFUgShdVvgJtV65EQH9pVDmoYVQMOu59JI6FHVeL3ald7R5Mvz6GaNLXsirvvhp0yAkcAd2hc5Xi6hDw== +"@sentry/replay@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.75.0.tgz#0b1d9e9a6954ecc004597456f2c82e7630b8139c" + integrity sha512-TAAlj7JCMF6hFFL71RmPzVX89ltyPYFWR+t4SuWaBmU6HmTliI2eJvK+M36oE+N7s3CkyRVTaXXRe0YMwRMuZQ== dependencies: - "@sentry/core" "7.69.0" - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" + "@sentry-internal/tracing" "7.75.0" + "@sentry/core" "7.75.0" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" -"@sentry/types@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.69.0.tgz#012b8d90d270a473cc2a5cf58a56870542739292" - integrity sha512-zPyCox0mzitzU6SIa1KIbNoJAInYDdUpdiA+PoUmMn2hFMH1llGU/cS7f4w/mAsssTlbtlBi72RMnWUCy578bw== +"@sentry/types@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.75.0.tgz#e171f1680785a155cb828942af890ad4ee657ca3" + integrity sha512-xG8OLADxG7HpGhMxrF4v4tKq/v/gqmLsTZ858R51pz0xCWM8SK6ZSWOKudkAGBIpRjI6RUHMnkBtRAN2aKDOkQ== -"@sentry/utils@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.69.0.tgz#b7594e4eb2a88b9b25298770b841dd3f81bd2aa4" - integrity sha512-4eBixe5Y+0EGVU95R4NxH3jkkjtkE4/CmSZD4In8SCkWGSauogePtq6hyiLsZuP1QHdpPb9Kt0+zYiBb2LouBA== +"@sentry/utils@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.75.0.tgz#7a638c4c027ca2018518ee8d2eead1397cb97d66" + integrity sha512-UHWKeevhUNRp+mAWDbMVFOMgseoq8t/xFgdUywO/2PC14qZKRBH+0k1BKoNkp5sOzDT06ETj2w6wYoYhy6i+dA== dependencies: - "@sentry/types" "7.69.0" - tslib "^2.4.1 || ^1.9.3" + "@sentry/types" "7.75.0" + +"@sentry/vercel-edge@7.75.0": + version "7.75.0" + resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-7.75.0.tgz#ef3cda5807b76692b210c3b89781116789af6504" + integrity sha512-A1ydzbyxoqgLidvgEW6saP2yts8xGTcxEcnETBI/8j95gQfQRwdtqWrYfYKHoTGMbMdGnE/UR4e+H1n1jL1CyQ== + dependencies: + "@sentry/core" "7.75.0" + "@sentry/types" "7.75.0" + "@sentry/utils" "7.75.0" "@sentry/webpack-plugin@1.20.0": version "1.20.0" @@ -2348,196 +2349,186 @@ lodash.merge "^4.6.2" postcss-selector-parser "6.0.10" -"@tiptap/core@^2.1.10", "@tiptap/core@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.10.tgz#6d8f3c777f1700dcc6c903b1185576754175e366" - integrity sha512-yhUKsac6nlqbPQfwQnp+4Jb110EqmzocXKoZacLwzHpM7JVsr2+LXMDu9kahtrvHNJErJljhnQvDHRsrrYeJkQ== +"@tiptap/core@^2.1.12", "@tiptap/core@^2.1.7": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.12.tgz#904fdf147e91b5e60561c76e7563c1b5a32f54ab" + integrity sha512-ZGc3xrBJA9KY8kln5AYTj8y+GDrKxi7u95xIl2eccrqTY5CQeRu6HRNM1yT4mAjuSaG9jmazyjGRlQuhyxCKxQ== -"@tiptap/extension-blockquote@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.10.tgz#dc475bef70dd460fc730a14b3b4cc18f37cd1b2d" - integrity sha512-lpBF/a+qgv4Bdf7HYisTkMFdFdGfn2SqspsydvG8UI7N9B/PfnCCrtoMaC3bqTaT6u8ZVxyM3Y3vnq2AxXJvBw== +"@tiptap/extension-blockquote@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.12.tgz#97b43419606acf9bfd93b9f482a1827dcac8c3e9" + integrity sha512-Qb3YRlCfugx9pw7VgLTb+jY37OY4aBJeZnqHzx4QThSm13edNYjasokbX0nTwL1Up4NPTcY19JUeHt6fVaVVGg== -"@tiptap/extension-bold@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.10.tgz#fb71c2575087d3d2a9c6d214b3c1587da931cc61" - integrity sha512-I43WCwc7pyz5vtKGj24Rjv7HN0EK5S4PlADQPBuhC1qQvfCTFvjrBB6ZmsekUMGmllW0qMOFVLSjtffpckqshA== +"@tiptap/extension-bold@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.12.tgz#5dbf41105fc0fbde8adbff629312187fbebc39b0" + integrity sha512-AZGxIxcGU1/y6V2YEbKsq6BAibL8yQrbRm6EdcBnby41vj1WziewEKswhLGmZx5IKM2r2ldxld03KlfSIlKQZg== -"@tiptap/extension-bubble-menu@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.10.tgz#551e93219b98f097331b30865123d36e95c37404" - integrity sha512-XxgJajXkfAj/fChXkIwKBs7/3pd7OxV1uGc6Opx1qW/nSRYx/rr97654Sx/sg6auwIlbpRoqTmyqjbykGX1/yA== +"@tiptap/extension-bubble-menu@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.12.tgz#4103a21a6433e58690c8f742ece39fad78dc26eb" + integrity sha512-gAGi21EQ4wvLmT7klgariAc2Hf+cIjaNU2NWze3ut6Ku9gUo5ZLqj1t9SKHmNf4d5JG63O8GxpErqpA7lHlRtw== dependencies: tippy.js "^6.3.7" -"@tiptap/extension-bullet-list@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.10.tgz#e7d7fb578502da6c6208a4daa3e2fe4249ae6280" - integrity sha512-e6aFr29OSOmXsjFZB2zt3p8aeCWOx0C9Ayrpdf4QBUCOUJtt6FQPxxiYc+XZcdrYbLGLznA7QJlulCK9SGv2Fw== +"@tiptap/extension-bullet-list@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.12.tgz#7c905a577ce30ef2cb335870a23f9d24fd26f6aa" + integrity sha512-vtD8vWtNlmAZX8LYqt2yU9w3mU9rPCiHmbp4hDXJs2kBnI0Ju/qAyXFx6iJ3C3XyuMnMbJdDI9ee0spAvFz7cQ== "@tiptap/extension-code-block-lowlight@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.11.tgz#6eec38c3b8662fae81ec2f117a2d18564f1fbb1a" - integrity sha512-k3olDvsRYO32JR9hyNa6VLqUdhwcpLwvR4Z6tJ66jHag5rsfP/7JZxJhrX9A1AF/jRCILdTiq9DTKybHieFjsw== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.12.tgz#ccbca5d0d92bee373dc8e2e2ae6c27f62f66437c" + integrity sha512-dtIbpI9QrWa9TzNO4v5q/zf7+d83wpy5i9PEccdJAVtRZ0yOI8JIZAWzG5ex3zAoCA0CnQFdsPSVykYSDdxtDA== -"@tiptap/extension-code-block@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.10.tgz#a125a12f716728b271a130178c6fc60237ed46f5" - integrity sha512-M+s89V9mP3tOoS6p/X2Dzw/Z7Fcg9EF0ZXlsMNifdlpwJlhAIYxI7vjPBmkMAFXTDB5eMZblXyNQaZ7v6V2Yeg== +"@tiptap/extension-code-block@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.12.tgz#20416baef1b5fc839490a8416e97fdcbb5fdf918" + integrity sha512-RXtSYCVsnk8D+K80uNZShClfZjvv1EgO42JlXLVGWQdIgaNyuOv/6I/Jdf+ZzhnpsBnHufW+6TJjwP5vJPSPHA== -"@tiptap/extension-code@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.10.tgz#704798f90a32d6166ce96dc65ef4a541f424f895" - integrity sha512-1yy/kR0FAeMkDdAt1LW/FH6vlyZLqLZqY6BM+wBCiGrr+XeA5FTXih9iT/4gbTRuIzG0EPqx18nvroG7hUsWBg== +"@tiptap/extension-code@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.12.tgz#86d2eb5f63725af472c5fd858e5a9c7ccae06ef3" + integrity sha512-CRiRq5OTC1lFgSx6IMrECqmtb93a0ZZKujEnaRhzWliPBjLIi66va05f/P1vnV6/tHaC3yfXys6dxB5A4J8jxw== "@tiptap/extension-color@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.11.tgz#be6989bb2d6630fc8f8e3c81add6fdfe1b77c790" - integrity sha512-xfSfZRnNd40YtFfrXvzpGa2OZsRAZapq0Ce09q7bCEpudhiD7yIIVOjOjggagllOFnafKTwKkFaDLIA0K0eIwg== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.12.tgz#1076833f061c3eabf59aef32cd15f103fd6ec710" + integrity sha512-Myd6iSbPJvvclr+NRBEdE0k52QlQrXZnJljk4JKn0b25cl60ERA40FH9QLBjkpTed7SDbI3oX7LWIzTUoCj39w== -"@tiptap/extension-document@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.10.tgz#6d2ab2301c86139d711fa460a311aa2c8bb343f8" - integrity sha512-jNlNGQIGg471DvzhADaEoRINa3LNghowrBbKK9d5wGVnbKRykNEPwjCf8zNl+m5NBmCZl3lsdznlwBk5zyh5Bg== +"@tiptap/extension-document@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.12.tgz#e19e4716dfad60cbeb6abaf2f362fed759963529" + integrity sha512-0QNfAkCcFlB9O8cUNSwTSIQMV9TmoEhfEaLz/GvbjwEq4skXK3bU+OQX7Ih07waCDVXIGAZ7YAZogbvrn/WbOw== -"@tiptap/extension-dropcursor@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.10.tgz#490c9aa82656592c9820c55214381fb9bfea92f2" - integrity sha512-GhsWsCq6wLb8HJ32BeAm7ndv4lPyu1F7FFwmnARzEF5q54FV20kWSv2zC+Dv0dTvynXR3quXybdUM92xeNDovw== +"@tiptap/extension-dropcursor@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.12.tgz#9da0c275291c9d47497d3db41b4d70d96366b4ff" + integrity sha512-0tT/q8nL4NBCYPxr9T0Brck+RQbWuczm9nV0bnxgt0IiQXoRHutfPWdS7GA65PTuVRBS/3LOco30fbjFhkfz/A== -"@tiptap/extension-floating-menu@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.10.tgz#82914a02e04e019d8b5da5158b32ffb29d4cce80" - integrity sha512-uChrDrY3usnF9wSegqq+YGaqd229p9gmaB5xyOyMERDs972hKj4Ul95rXzBBiMKAWUMw9eM09i7+ijTzz4KDUw== +"@tiptap/extension-floating-menu@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.12.tgz#68a658b2b9bdd3a0fc1afc5165231838061a8fde" + integrity sha512-uo0ydCJNg6AWwLT6cMUJYVChfvw2PY9ZfvKRhh9YJlGfM02jS4RUG/bJBts6R37f+a5FsOvAVwg8EvqPlNND1A== dependencies: tippy.js "^6.3.7" -"@tiptap/extension-gapcursor@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.10.tgz#712853ce82642108e50a37014d585ff72af6758d" - integrity sha512-WSBT9X7dzg0HyMoMP/Yyxl28QwIJO90YzobI9z5mav86BQv7C5wU0fQSpbpAbsN3s7lxKhPwNrXkwkpnXT4ZCA== +"@tiptap/extension-gapcursor@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.12.tgz#63844c3abd1a38af915839cf0c097b6d2e5a86fe" + integrity sha512-zFYdZCqPgpwoB7whyuwpc8EYLYjUE5QYKb8vICvc+FraBUDM51ujYhFSgJC3rhs8EjI+8GcK8ShLbSMIn49YOQ== -"@tiptap/extension-hard-break@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.10.tgz#e885e83d936b45891bf4dc40c713d042f84eb8c4" - integrity sha512-sYrzpPoV5jQri+duGb50nDTs+hOBQDxXTKlJuZNFfZMwgx6epwxb8xICcGAUJFShuuW8UAWCNcB4jG9tMqgvyw== +"@tiptap/extension-hard-break@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.12.tgz#54d0c9996e1173594852394975a9356eec98bc9a" + integrity sha512-nqKcAYGEOafg9D+2cy1E4gHNGuL12LerVa0eS2SQOb+PT8vSel9OTKU1RyZldsWSQJ5rq/w4uIjmLnrSR2w6Yw== -"@tiptap/extension-heading@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.10.tgz#1b32726551466c29987861181966e5675417b28c" - integrity sha512-1OgmrRPMcY52WI7I4799xd4eIsEX/bI813B8mZvNYXLzZI75pLW1hmz1mUvBYyMwlcek74zVTGYgPy11o+2JEg== +"@tiptap/extension-heading@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.12.tgz#05ae4684d6f29ae611495ab114038e14a5d1dff6" + integrity sha512-MoANP3POAP68Ko9YXarfDKLM/kXtscgp6m+xRagPAghRNujVY88nK1qBMZ3JdvTVN6b/ATJhp8UdrZX96TLV2w== -"@tiptap/extension-history@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.10.tgz#efa60d657a76818361a3af14769660672d4bc227" - integrity sha512-tApuN8MIJMzc0dxvkYJPt3t5cea9NuZBGNiuVedJwMMUF6hbFpMZAt20GW2qwjBaZ76rQwbLp1s3KnImFsPe5A== +"@tiptap/extension-history@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.12.tgz#03bcb9422e8ea2b82dc45207d1a1b0bc0241b055" + integrity sha512-6b7UFVkvPjq3LVoCTrYZAczt5sQrQUaoDWAieVClVZoFLfjga2Fwjcfgcie8IjdPt8YO2hG/sar/c07i9vM0Sg== -"@tiptap/extension-horizontal-rule@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz#cfdb67530be100054fc8511942d4ec3534acf828" - integrity sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ== - -"@tiptap/extension-horizontal-rule@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.11.tgz#e423a2b41123ef7f8d778a1cd026e6606e7be28b" - integrity sha512-uvHPa2YCKnDhtSBSZB3lk5U4H3wRKP0DNvVx4Y2F7MdQianVzcyOd1pZYO9BQs+lUB1aZots6doE69Zqz3mU2Q== +"@tiptap/extension-horizontal-rule@^2.1.11", "@tiptap/extension-horizontal-rule@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.12.tgz#2191d4ff68ed39381d65971ad8e2aa1be43e6d6b" + integrity sha512-RRuoK4KxrXRrZNAjJW5rpaxjiP0FJIaqpi7nFbAua2oHXgsCsG8qbW2Y0WkbIoS8AJsvLZ3fNGsQ8gpdliuq3A== "@tiptap/extension-image@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.10.tgz#6c597ad02285f1f3508fd4aa21e30213657cbd7c" - integrity sha512-d7+d4J2TJ99+phFbVTpsFhi208jAgcrfbdwUDkkwjdF+PQhax5pounSt/8eZPWdyCXj+EWYjCjx0znwsD6+SCA== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.12.tgz#ab035db82f0961b1d906c4d426bf68be563fdcd3" + integrity sha512-VCgOTeNLuoR89WoCESLverpdZpPamOd7IprQbDIeG14sUySt7RHNgf2AEfyTYJEHij12rduvAwFzerPldVAIJg== -"@tiptap/extension-italic@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.10.tgz#7183119c8c61beb2ac635ca3c2066624530b4a56" - integrity sha512-ebw5m+rWx6K5UoBVXSkz3fpvDJh/wScfYmwl6pkbjc2jNbZiln2LSiLHYc2eIYJ2aTsVxcw/n0Azfk5Lb19InA== +"@tiptap/extension-italic@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.12.tgz#e99480eb77f8b4e5444fc236add8a831d5aa2343" + integrity sha512-/XYrW4ZEWyqDvnXVKbgTXItpJOp2ycswk+fJ3vuexyolO6NSs0UuYC6X4f+FbHYL5VuWqVBv7EavGa+tB6sl3A== "@tiptap/extension-link@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.10.tgz#c2a33fdf33dd2d97f29381ae2163c10318dc371f" - integrity sha512-dXxPTWzJzpbDRAewM4P8jN/n9h8uUH83lOLwweuODYCqHRdjQL/uGkQworFFrgqmRHs+9JjHZ4DETILZVawJ+Q== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.12.tgz#a18f83a0b54342e6274ff9e5a5907ef7f15aa723" + integrity sha512-Sti5hhlkCqi5vzdQjU/gbmr8kb578p+u0J4kWS+SSz3BknNThEm/7Id67qdjBTOQbwuN07lHjDaabJL0hSkzGQ== dependencies: linkifyjs "^4.1.0" -"@tiptap/extension-list-item@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.10.tgz#0615e4fb68161e6457e6041e195f454bfd537d44" - integrity sha512-rRRyB14vOcSjTMAh8Y+50TRC/jO469CelGwFjOLrK1ZSEag5wmLDaqpWOOb52BFYnvCHuIm1HqZtdL5bTI/J1w== +"@tiptap/extension-list-item@^2.1.11", "@tiptap/extension-list-item@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.12.tgz#3eb28dc998490a98f14765783770b3cf6587d39e" + integrity sha512-Gk7hBFofAPmNQ8+uw8w5QSsZOMEGf7KQXJnx5B022YAUJTYYxO3jYVuzp34Drk9p+zNNIcXD4kc7ff5+nFOTrg== -"@tiptap/extension-list-item@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.11.tgz#466e4d1dcad153b4e52678b08d2bf073339c2dc9" - integrity sha512-YhwHaPGhffsFsg/zjCu1G24//j/BTRDRZbZXmMwp77m1yEqPULcWyoWrI+gUzetQxJRD/ruAucqjLtoLLfICmQ== +"@tiptap/extension-ordered-list@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.12.tgz#f41a45bc66b4d19e379d4833f303f2e0cd6b9d60" + integrity sha512-tF6VGl+D2avCgn9U/2YLJ8qVmV6sPE/iEzVAFZuOSe6L0Pj7SQw4K6AO640QBob/d8VrqqJFHCb6l10amJOnXA== -"@tiptap/extension-ordered-list@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.10.tgz#ef5d5ba68baf86e9b66c1b2c1cec458aa111ad44" - integrity sha512-jouo3RHUMxU4dPzZcfZdUzmsLVp1KHrLIAD2YAxBuqArACrBNfJpIhtkTKuGLlaFhKqGr+EmNdNQnK8JOBhLtQ== - -"@tiptap/extension-paragraph@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.10.tgz#ee1238d2d6e9460b2a929b05a5fd43cfb58a6017" - integrity sha512-kzuHbrxcxpWkha5P+JFzCKT54pNqb4IBKMU5qT9YGhZSdNTtU63ncdCHM+Ad1ukLuvXAv95zh1IQC5j+Z1Qk4A== +"@tiptap/extension-paragraph@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.12.tgz#922447b2aa1c7184787d351ceec593a74d24ed03" + integrity sha512-hoH/uWPX+KKnNAZagudlsrr4Xu57nusGekkJWBcrb5MCDE91BS+DN2xifuhwXiTHxnwOMVFjluc0bPzQbkArsw== "@tiptap/extension-placeholder@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.11.tgz#ba115f714dd48d5bbc65df277b74f357ff3b100e" - integrity sha512-laHYRFxJWj6m72Yf1v6Q5nF2nvwWpQlKUj6Yu/yluOOoVE92HpLqCAvA8RamqLtPiw5VxR3v3oCY0WNeQRvyIg== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.12.tgz#f6267a563d17a5ae8a04da32231eac8d8868519e" + integrity sha512-K52o7B1zkP4vaVy3z4ZwHn+tQy6KlXtedj1skLg+796ImwH2GYS5z6MFOTfKzBO2hLncUzLco/s0C5PLCD6SDw== -"@tiptap/extension-strike@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz#ec311395d16af15345b63d2dac2d459b9ad5fa9e" - integrity sha512-KW63lZLPFIir5AIeh2I7UK6Tx1O3jetD7JIPUzEqp1I1BfJlHGHVQxV8VXAmJl0hTOzjQBsHW42PmBxSC97NUg== +"@tiptap/extension-strike@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.12.tgz#2b049aedf2985e9c9e3c3f1cc0b203a574c85bd8" + integrity sha512-HlhrzIjYUT8oCH9nYzEL2QTTn8d1ECnVhKvzAe6x41xk31PjLMHTUy8aYjeQEkWZOWZ34tiTmslV1ce6R3Dt8g== "@tiptap/extension-table-cell@^2.1.6": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.1.10.tgz#e594b55622435c43a95edf6f2adfaca402f5cbed" - integrity sha512-NQOTKjPOTJrkI7VaR9wFF3UKB9N2THD8zJZJDcECKQxLR740udF6/6jWm1uwkTwdkBekVKHBMQvKKK9W1bOBiw== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.1.12.tgz#b13938d345065a3750610c66a81ea107edbbcea7" + integrity sha512-hextcfVTdwX8G7s8Q/V6LW2aUhGvPgu1dfV+kVVO42AFHxG+6PIkDOUuHphGajG3Nrs129bjMDWb8jphj38dUg== "@tiptap/extension-table-header@^2.1.6": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.1.10.tgz#6250676a26946e5b7186198a06990ea70f578a87" - integrity sha512-NSC0Y10kXDvPGiJckJY/QU8VA7HHU0tI20Dj7/r1oD9itBWSnWP0zAOXzHVlQt9GpThhFNo2nu3fAaVQNfKoTg== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.1.12.tgz#87ac2efa073a212c6114e0b137cf4afc3d75c35f" + integrity sha512-a4WZ5Z7gqQ/QlK8cK2d1ONYdma/J5+yH/0SNtQhkfELoS45GsLJh89OyKO0W0FnY6Mg0RoH1FsoBD+cqm0yazA== "@tiptap/extension-table-row@^2.1.6": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.1.10.tgz#e7a1ca8342b623a400848b437c82d57680e551e3" - integrity sha512-yMOnAaXE7vK7MwULuVUO8v6AYZu6wxTfHAWQe/FqPeMf9tG0HL6+gyt1audremw0xBFMGPx6v4t8vlqPXW9p2g== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.1.12.tgz#27bee7d046b2bea4fe6bf46260e0d89305b75663" + integrity sha512-0kPr+zngQC1YQRcU6+Fl3CpIW/SdJhVJ5qOLpQleXrLPdjmZQd3Z1DXvOSDphYjXCowGPCxeUa++6bo7IoEMJw== "@tiptap/extension-table@^2.1.6": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.1.10.tgz#5654426366b547631c647ffc5dacf040e65307e1" - integrity sha512-fsf0c6qA+R6NzbFx+tm1l5POZsgadHjREsedvq5q1i8rCq1Gt1AK+lR7WQsaXlSeIRsWtg4RT0eUjAYNCmKkug== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.1.12.tgz#173cc4eac75c650b440dfcae433d3c74e78aa1bc" + integrity sha512-q/DuKZ4j1ycRfuFdb9rBJ3MglGNxlM2BQ1csScX/BrVIsAQI5B8sdzy1BrIlepQ6DRu4DCzHcKMI8u4/edUSWA== "@tiptap/extension-task-item@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.10.tgz#8eb0d3e8b1234fa44205dd91619f3f1937ca3254" - integrity sha512-jiH37e8c41T/UKWXzznOg325huAkAiFtjNkvfQfS23a7UDfIM90IJ+VjvFt/5EEgJ2mozBweQan4yIzlC6uWaQ== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.12.tgz#944eacf6f0ed1a430d807217d62b49ccef3956e1" + integrity sha512-uqrDTO4JwukZUt40GQdvB6S+oDhdp4cKNPMi0sbteWziQugkSMLlkYvxU0Hfb/YeziaWWwFI7ssPu/hahyk6dQ== "@tiptap/extension-task-list@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.10.tgz#faf2d520c5f5b7b5084a0804b8e65f69fea361be" - integrity sha512-1nLI81lQ/HYrcxVRSv3EyG8kcWygtaQcOZ9p6PeQjwN+z5D5PoQVHK4+8zOO1Lpz4BDR3mc4nolA7q/Li0ilOw== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.12.tgz#adbfb5a5b990d6f189c776b45de2d2c5bb77e963" + integrity sha512-BUpYlEWK+Q3kw9KIiOqvhd0tUPhMcOf1+fJmCkluJok+okAxMbP1umAtCEQ3QkoCwLr+vpHJov7h3yi9+dwgeQ== "@tiptap/extension-text-style@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.11.tgz#b2fbea4f52b68f339b4941103ea2e03d1ac996a3" - integrity sha512-+JDWmcSUyFKzMDm/1xqlk7e0qPJ1nQ/UKIRuDeRtqgbxTyEw4fNlkV2k7GHCoELXqxUoplzweLID+kM1Vk2OaA== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.12.tgz#ec6a025fc6785246c9fcf78e34088759c1d2b213" + integrity sha512-nfjWXX0JSRHLcscfiMESh+RN+Z7bG8nio/C9+8yQASM90VxU9f8oKgF8HnnSYsSrD4lLf44Q6XjmB7aMVUuikg== -"@tiptap/extension-text@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.10.tgz#db297fb5d2ee50ef7a14650539e3d335f772f755" - integrity sha512-ubU/WQwNB0MVKyMAHr8ka3Nu3jCR03HARGKUwNRzppZYtRXWyXHNlAaJdplNb1NMGb8hd0ElBJmwFlVqmh8haQ== +"@tiptap/extension-text@^2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.12.tgz#466e3244bdd9b2db2304c0c9a1d51ce59f5327d0" + integrity sha512-rCNUd505p/PXwU9Jgxo4ZJv4A3cIBAyAqlx/dtcY6cjztCQuXJhuQILPhjGhBTOLEEL4kW2wQtqzCmb7O8i2jg== "@tiptap/extension-underline@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.10.tgz#d7a3ac39c2363da94651a960abe3a16bb24de398" - integrity sha512-f+rJKviGNqORGv4/1pTLZuVTb9VsKMZMLucL8423M6s8TdrH//sBB8QeU92JSnO9PjAGwxWjS1f23/KtufxP8g== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.12.tgz#abd59c4b6c8434dbadb4ff9bff23eefcc6bc095e" + integrity sha512-NwwdhFT8gDD0VUNLQx85yFBhP9a8qg8GPuxlGzAP/lPTV8Ubh3vSeQ5N9k2ZF/vHlEvnugzeVCbmYn7wf8vn1g== "@tiptap/pm@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.10.tgz#84d5ae574568dca00ee62698559523d77e980620" - integrity sha512-Y+AqizKnjQpx4pSaA6m/cCD5QHQRPtALhO4ZO4YFZV1idYmsJA3/S5lgJI3ZL5eAHKHcGk6Vv3/8Y+eej5YIPw== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.12.tgz#88a4b19be0eabb13d42ddd540c19ba1bbe74b322" + integrity sha512-Q3MXXQABG4CZBesSp82yV84uhJh/W0Gag6KPm2HRWPimSFELM09Z9/5WK9RItAYE0aLhe4Krnyiczn9AAa1tQQ== dependencies: prosemirror-changeset "^2.2.0" prosemirror-collab "^1.3.0" @@ -2559,59 +2550,59 @@ prosemirror-view "^1.28.2" "@tiptap/react@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.10.tgz#51cd96462e61f6fffa0ca4eb359d8d7d15ebf422" - integrity sha512-kzCWzbV2dnD5NmHjN8GiS+k0GOmoEhKnMuMzuuU6FjtOALhJzPTrIXITzWDpU3jL+r/4eeXYhAt64Wp7PVwscg== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.12.tgz#23566c7992b9642137171b282335e646922ae559" + integrity sha512-RMO4QmmpL7sPR7w8o1Wq0hrUe/ttHzsn5I/eWwqg1d3fGx5y9mOdfCoQ9XBtm49Xzdejy3QVzt4zYp9fX0X/xg== dependencies: - "@tiptap/extension-bubble-menu" "^2.1.10" - "@tiptap/extension-floating-menu" "^2.1.10" + "@tiptap/extension-bubble-menu" "^2.1.12" + "@tiptap/extension-floating-menu" "^2.1.12" "@tiptap/starter-kit@^2.1.10": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.10.tgz#5f19c199c79d90ef5e3b8990ca3aa76ce625d68c" - integrity sha512-h5mH1qv7SDFXWZPbOWC8zpGZ62EnDizRNtM45Gani0HYWJXcbPFpgN1qJmESP/jP+v+0hxtnVEkgfpiy3LRm6A== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.12.tgz#2bf28091ed08dc8f7b903ba92925e4ffe06257ea" + integrity sha512-+RoP1rWV7rSCit2+3wl2bjvSRiePRJE/7YNKbvH8Faz/+AMO23AFegHoUFynR7U0ouGgYDljGkkj35e0asbSDA== dependencies: - "@tiptap/core" "^2.1.10" - "@tiptap/extension-blockquote" "^2.1.10" - "@tiptap/extension-bold" "^2.1.10" - "@tiptap/extension-bullet-list" "^2.1.10" - "@tiptap/extension-code" "^2.1.10" - "@tiptap/extension-code-block" "^2.1.10" - "@tiptap/extension-document" "^2.1.10" - "@tiptap/extension-dropcursor" "^2.1.10" - "@tiptap/extension-gapcursor" "^2.1.10" - "@tiptap/extension-hard-break" "^2.1.10" - "@tiptap/extension-heading" "^2.1.10" - "@tiptap/extension-history" "^2.1.10" - "@tiptap/extension-horizontal-rule" "^2.1.10" - "@tiptap/extension-italic" "^2.1.10" - "@tiptap/extension-list-item" "^2.1.10" - "@tiptap/extension-ordered-list" "^2.1.10" - "@tiptap/extension-paragraph" "^2.1.10" - "@tiptap/extension-strike" "^2.1.10" - "@tiptap/extension-text" "^2.1.10" + "@tiptap/core" "^2.1.12" + "@tiptap/extension-blockquote" "^2.1.12" + "@tiptap/extension-bold" "^2.1.12" + "@tiptap/extension-bullet-list" "^2.1.12" + "@tiptap/extension-code" "^2.1.12" + "@tiptap/extension-code-block" "^2.1.12" + "@tiptap/extension-document" "^2.1.12" + "@tiptap/extension-dropcursor" "^2.1.12" + "@tiptap/extension-gapcursor" "^2.1.12" + "@tiptap/extension-hard-break" "^2.1.12" + "@tiptap/extension-heading" "^2.1.12" + "@tiptap/extension-history" "^2.1.12" + "@tiptap/extension-horizontal-rule" "^2.1.12" + "@tiptap/extension-italic" "^2.1.12" + "@tiptap/extension-list-item" "^2.1.12" + "@tiptap/extension-ordered-list" "^2.1.12" + "@tiptap/extension-paragraph" "^2.1.12" + "@tiptap/extension-strike" "^2.1.12" + "@tiptap/extension-text" "^2.1.12" "@tiptap/suggestion@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.10.tgz#fe6dd160ea93f8135c0831ae4accc7a708bac019" - integrity sha512-k9WTTWT81UkHaxZksjp+wE31E85QL0jyLd0ZEKAs+btW148Pon1KwBeLnODNHILcdQaRPxRvb28a47cRHEKTiw== + version "2.1.12" + resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.12.tgz#a13782d1e625ec03b3f61b6839ecc95b6b685d3f" + integrity sha512-rhlLWwVkOodBGRMK0mAmE34l2a+BqM2Y7q1ViuQRBhs/6sZ8d83O4hARHKVwqT5stY4i1l7d7PoemV3uAGI6+g== "@types/debug@^4.0.0": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317" - integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ== + version "4.1.10" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.10.tgz#f23148a6eb771a34c466a4fc28379d8101e84494" + integrity sha512-tOSCru6s732pofZ+sMv9o4o3Zc+Sa8l3bxd/tweTQudFn06vAzb13ZX46Zi6m6EJ+RUbRTHvgQJ1gBtSgkaUYA== dependencies: "@types/ms" "*" "@types/dom4@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.2.tgz#6495303f049689ce936ed328a3e5ede9c51408ee" - integrity sha512-Rt4IC1T7xkCWa0OG1oSsPa0iqnxlDeQqKXZAHrQGLb7wFGncWm85MaxKUjAGejOrUynOgWlFi4c6S6IyJwoK4g== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.3.tgz#bd084dbd4c15bee49442c5cd231acdcd14efbe90" + integrity sha512-xQT2XxtDGP1WFfTB/Lti629HpguNrfZ3dg84bWXASd6JUay6WgR73Wb6DG3kmr2/iGAWZ7NNLceGVWYWfgPX0g== "@types/estree@*", "@types/estree@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" - integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.3.tgz#2be19e759a3dd18c79f9f436bd7363556c1a73dd" + integrity sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ== "@types/estree@0.0.39": version "0.0.39" @@ -2627,36 +2618,36 @@ "@types/node" "*" "@types/hast@^2.0.0": - version "2.3.6" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.6.tgz#bb8b05602112a26d22868acb70c4b20984ec7086" - integrity sha512-47rJE80oqPmFdVDCD7IheXBrVdwuBgsYwoczFvKmwfo2Mzsnt+V9OONsYauFmICb6lQPpCuXYJWejBNs4pDJRg== + version "2.3.7" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.7.tgz#5e9bd7ab4452d5313aeec9d38fbc193a70f8d810" + integrity sha512-EVLigw5zInURhzfXUM65eixfadfsHKomGKUakToXo84t8gGIJuTcD2xooM2See7GyQ7DRtYjhCHnSUQez8JaLw== dependencies: "@types/unist" "^2" "@types/hast@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.1.tgz#e1705ec9258ac4885659c2d50bac06b4fcd16466" - integrity sha512-hs/iBJx2aydugBQx5ETV3ZgeSS0oIreQrFJ4bjBl0XvM4wAmDjFEALY7p0rTSLt2eL+ibjRAAs9dTPiCLtmbqQ== + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.2.tgz#e6c1126a33955cb9493a5074ddf1873fb48248c7" + integrity sha512-B5hZHgHsXvfCoO3xgNJvBnX7N8p86TqQeGKXcokW4XXi+qY4vxxPSFYofytvVmpFxzPv7oxDQzjg5Un5m2/xiw== dependencies: "@types/unist" "*" "@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a" - integrity sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw== + version "3.3.4" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.4.tgz#cc477ce0283bb9d19ea0cbfa2941fe2c8493a1be" + integrity sha512-ZchYkbieA+7tnxwX/SCBySx9WwvWR8TaP5tb2jRAzwvLb/rWchGw3v0w3pqUbUvj0GCwW2Xz/AVPSk6kUGctXQ== dependencies: "@types/react" "*" hoist-non-react-statics "^3.3.0" "@types/js-cookie@^3.0.2", "@types/js-cookie@^3.0.3": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.4.tgz#23475b6d3b03acc84192e7c24da88eb38c1039ef" - integrity sha512-vMMnFF+H5KYqdd/myCzq6wLDlPpteJK+jGFgBus3Da7lw+YsDmx2C8feGTzY2M3Fo823yON+HC2CL240j4OV+w== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.5.tgz#5eba4033a4f17fb2b29d975892694315194eca33" + integrity sha512-dtLshqoiGRDHbHueIT9sjkd2F4tW1qPSX2xKAQK8p1e6pM+Z913GM1shv7dOqqasEMYbC5zEaClJomQe8OtQLA== "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.13" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" - integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== + version "7.0.14" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.14.tgz#74a97a5573980802f32c8e47b663530ab3b6b7d1" + integrity sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw== "@types/json5@^0.0.29": version "0.0.29" @@ -2664,21 +2655,21 @@ integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/linkify-it@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.3.tgz#15a0712296c5041733c79efe233ba17ae5a7587b" - integrity sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g== + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.4.tgz#def6a9bb0ce78140860602f16ace37a9997f086a" + integrity sha512-hPpIeeHb/2UuCw06kSNAOVWgehBLXEo0/fUs0mw3W2qhqX89PI2yvok83MnuctYGCPrabGIoi0fFso4DQ+sNUQ== "@types/lodash.debounce@^4.0.7": - version "4.0.7" - resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz#0285879defb7cdb156ae633cecd62d5680eded9f" - integrity sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.8.tgz#d5fe36a35aa57773e05d960b3e3c703fd9ffb8b3" + integrity sha512-REumepIJjQFSOaBUoj81U5ZzF9YIhovzE2Lm6ejUbycmwx597k2ivG1cVfPtAj4eVuSbGoZDkJR0sRIahsE6/Q== dependencies: "@types/lodash" "*" "@types/lodash@*": - version "4.14.198" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.198.tgz#4d27465257011aedc741a809f1269941fa2c5d4c" - integrity sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg== + version "4.14.200" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.200.tgz#435b6035c7eba9cdf1e039af8212c9e9281e7149" + integrity sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q== "@types/markdown-it@^12.2.3": version "12.2.3" @@ -2689,16 +2680,16 @@ "@types/mdurl" "*" "@types/mdast@^3.0.0": - version "3.0.12" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.12.tgz#beeb511b977c875a5b0cc92eab6fcac2f0895514" - integrity sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg== + version "3.0.14" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.14.tgz#0735473a5b35be032b9f2685b7413cbab1b8a639" + integrity sha512-gVZ04PGgw1qLZKsnWnyFv4ORnaJ+DXLdHTVSFbU8yX6xZ34Bjg4Q32yPkmveUP1yItXReKfB0Aknlh/3zxTKAw== dependencies: "@types/unist" "^2" "@types/mdurl@*": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" - integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.4.tgz#574bfbec51eb41ab5f444116c8555bc4347feba5" + integrity sha512-ARVxjAEX5TARFRzpDRVC6cEk0hUIXCCwaMhz8y7S1/PxU6zZS1UMjyobz7q4w/D/R552r4++EhwmXK1N2rAy0A== "@types/minimatch@*": version "5.1.2" @@ -2706,14 +2697,16 @@ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/ms@*": - version "0.7.31" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" - integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + version "0.7.33" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.33.tgz#80bf1da64b15f21fd8c1dc387c31929317d99ee9" + integrity sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ== -"@types/node@*": - version "20.6.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.3.tgz#5b763b321cd3b80f6b8dde7a37e1a77ff9358dd9" - integrity sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA== +"@types/node@*", "@types/node@^20.5.2": + version "20.8.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.8.tgz#adee050b422061ad5255fc38ff71b2bb96ea2a0e" + integrity sha512-YRsdVxq6OaLfmR9Hy816IMp33xOBjfyOgUd77ehqg96CFywxAPbDbXvAsuN2KVg2HOT8Eh6uAfU+l4WffwPVrQ== + dependencies: + undici-types "~5.25.1" "@types/node@18.0.6": version "18.0.6" @@ -2730,55 +2723,50 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== -"@types/node@^20.5.2": - version "20.8.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.2.tgz#d76fb80d87d0d8abfe334fc6d292e83e5524efc4" - integrity sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w== - "@types/nprogress@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.0.tgz#86c593682d4199212a0509cc3c4d562bbbd6e45f" - integrity sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A== + version "0.2.2" + resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.2.tgz#c73bf540ac7926fb1b6d03f9d2725e07b3848d65" + integrity sha512-2wLrSJXLztGmr7wXwM0hA/wuIOY9DznVdd+ZFofHOiXcj9JnVt+2ZeLRJ7v5ZVlmheSkUOSg3Q3O4Ce7yji79A== "@types/object.omit@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/object.omit/-/object.omit-3.0.1.tgz#1b9de058cf94344b9284308a41b17e3a356ed18e" - integrity sha512-24XD34UeRWw505TsMNBrQ4bES2s8IxiFC59mmNUFhTz9IX2hAtA7gQ8wVww1i17QmhBYILg5iqYP2y7aqA3pwQ== + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/object.omit/-/object.omit-3.0.2.tgz#13d23915cc16fa54b0d4cfbcb79840f4fe1474d9" + integrity sha512-BxWU36cMP+FKD3OLFluQaj2cBev2sx2LJaHELuphHwnleq+xnEhTmuYYYx4pOT/1U/ZoR6B+RdvxWh2FD6lGGA== "@types/object.pick@^1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/object.pick/-/object.pick-1.3.2.tgz#9eb28118240ad8f658b9c9c6caf35359fdb37150" - integrity sha512-sn7L+qQ6RLPdXRoiaE7bZ/Ek+o4uICma/lBFPyJEKDTPTBP1W8u0c4baj3EiS4DiqLs+Hk+KUGvMVJtAw3ePJg== + version "1.3.3" + resolved "https://registry.yarnpkg.com/@types/object.pick/-/object.pick-1.3.3.tgz#f4d4a76e9ef1161e965b963d2bb33c3f6c300125" + integrity sha512-qZqHmdGEALeSATMB1djT1S5szv6Wtpb7DKpHrt2XG4iyKlV7C2Xk8GmDXr1KXakOqUfX6ohw7ceruYt4NVmB1Q== "@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + version "4.0.1" + 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.5": - version "15.7.6" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.6.tgz#bbf819813d6be21011b8f5801058498bec555572" - integrity sha512-RK/kBbYOQQHLYj9Z95eh7S6t7gq4Ojt/NT8HTk8bWVhA5DaF+5SMnxHKkP4gPNN3wAZkKP+VjAf0ebtYzf+fxg== +"@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.8": + version "15.7.9" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d" + integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g== "@types/react-beautiful-dnd@^13.1.2": - version "13.1.4" - resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.4.tgz#bcec72da719c18c0d8b4a7cb00e7fb443211d6d7" - integrity sha512-4bIBdzOr0aavN+88q3C7Pgz+xkb7tz3whORYrmSj77wfVEMfiWiooIwVWFR7KM2e+uGTe5BVrXqSfb0aHeflJA== + version "13.1.6" + resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.6.tgz#a616443903bfc370fee298b0144dbce7234d5561" + integrity sha512-FXAuaa52ux7HWQDumi3MFSAAsW8OKfDImy1pSZPKe85nV9mZ1f4spVzW0a2boYvkIhphjbWUi5EwUiRG8Rq/Qg== dependencies: "@types/react" "*" "@types/react-color@^3.0.6": - version "3.0.6" - resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.6.tgz#602fed023802b2424e7cd6ff3594ccd3d5055f9a" - integrity sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w== + version "3.0.9" + resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.9.tgz#8dbb0d798f2979c3d7e2e26dd46321e80da950b4" + integrity sha512-Ojyc6jySSKvM6UYQrZxaYe0JZXtgHHXwR2q9H4MhcNCswFdeZH1owYZCvPtdHtMOfh7t8h1fY0Gd0nvU1JGDkQ== dependencies: "@types/react" "*" "@types/reactcss" "*" "@types/react-datepicker@^4.8.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.15.0.tgz#24a9c03e79ab4b232b346edd006cfb6060b0fb43" - integrity sha512-kr10s8ex4+MmCJmzdhA9kfmoMQBmsW5uDYDlH+8f/PgStrp7rRaz23Y/cvTiMgvESVq8ujDh4SOo6jlSwEw13g== + version "4.19.1" + resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.19.1.tgz#c7102c015eb0f63b0f1707e34799d289408654be" + integrity sha512-HV52yjxuRi49psAVuHTFXXr+RSrCbIFDn9ayei0YH8xVVAXCO+5GwHAGKeREAmNbneweN0ySGoByr90yJCAnrQ== dependencies: "@popperjs/core" "^2.9.2" "@types/react" "*" @@ -2807,19 +2795,19 @@ "@types/react" "*" "@types/react-redux@^7.1.20": - version "7.1.26" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.26.tgz#84149f5614e40274bb70fcbe8f7cae6267d548b1" - integrity sha512-UKPo7Cm7rswYU6PH6CmTNCRv5NYF3HrgKuHEYTK8g/3czYLrUux50gQ2pkxc9c7ZpQZi+PNhgmI8oNIRoiVIxg== + version "7.1.28" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.28.tgz#30a44303c7daceb6ede9cfb4aaf72e64f1dde4de" + integrity sha512-EQr7cChVzVUuqbA+J8ArWK1H0hLAHKOs21SIMrskKZ3nHNeE+LFYA+IsoZGhVOT8Ktjn3M20v4rnZKN3fLbypw== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-transition-group@^4.4.6": - version "4.4.6" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.6.tgz#18187bcda5281f8e10dfc48f0943e2fdf4f75e2e" - integrity sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew== +"@types/react-transition-group@^4.4.7": + 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== dependencies: "@types/react" "*" @@ -2833,9 +2821,9 @@ csstype "^3.0.2" "@types/reactcss@*": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@types/reactcss/-/reactcss-1.2.6.tgz#133c1e7e896f2726370d1d5a26bf06a30a038bcc" - integrity sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg== + version "1.2.8" + resolved "https://registry.yarnpkg.com/@types/reactcss/-/reactcss-1.2.8.tgz#8c2342f5f650cc5f9e8bea73199c17ba747b9126" + integrity sha512-IzxChTOxOFWZb1RhXoNZ7oEi3BtUdLQIFheoOurvu6iu0X9kwhoFe73DW9EVFxVFTKnd8bb8b1dKtO0tokM3eA== dependencies: "@types/react" "*" @@ -2847,14 +2835,14 @@ "@types/node" "*" "@types/scheduler@*": - version "0.16.3" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" - integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== + version "0.16.5" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.5.tgz#4751153abbf8d6199babb345a52e1eb4167d64af" + integrity sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw== "@types/semver@^7.3.12": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" - integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== + version "7.5.4" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.4.tgz#0a41252ad431c473158b22f9bfb9a63df7541cff" + integrity sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ== "@types/throttle-debounce@^2.1.0": version "2.1.0" @@ -2862,19 +2850,19 @@ integrity sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ== "@types/trusted-types@^2.0.2": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.4.tgz#2b38784cd16957d3782e8e2b31c03bc1d13b4d65" - integrity sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ== + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.5.tgz#5cac7e7df3275bb95f79594f192d97da3b4fd5fe" + integrity sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA== "@types/unist@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.0.tgz#988ae8af1e5239e89f9fbb1ade4c935f4eeedf9a" - integrity sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w== + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.1.tgz#778652d02ddec1bfc9e5e938fec8d407b8e56cba" + integrity sha512-ue/hDUpPjC85m+PM9OQDMZr3LywT+CT6mPsQq8OJtCLiERkGRcQUFvu9XASF5XWqyZFXbf15lvb3JFJ4dRLWPg== "@types/unist@^2", "@types/unist@^2.0.0": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.8.tgz#bb197b9639aa1a04cf464a617fe800cccd92ad5c" - integrity sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw== + version "2.0.9" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.9.tgz#72e164381659a49557b0a078b28308f2c6a3e1ce" + integrity sha512-zC0iXxAv1C1ERURduJueYzkzZ2zaGyc+P2c95hgkikHPr3z8EdUZOlgEQ5X0DRmwDZn+hekycQnoeiiRVrmilQ== "@types/use-sync-external-store@^0.0.3": version "0.0.3" @@ -2887,9 +2875,9 @@ integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== "@types/uuid@^9.0.1": - version "9.0.4" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.4.tgz#e884a59338da907bda8d2ed03e01c5c49d036f1c" - integrity sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA== + version "9.0.6" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.6.tgz#c91ae743d8344a54b2b0c691195f5ff5265f6dfb" + integrity sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew== "@typescript-eslint/eslint-plugin@^5.48.2": version "5.62.0" @@ -2975,6 +2963,11 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + acorn-jsx@^5.3.1, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -3098,7 +3091,7 @@ array-buffer-byte-length@^1.0.0: call-bind "^1.0.2" is-array-buffer "^3.0.1" -array-includes@^3.1.5, array-includes@^3.1.6: +array-includes@^3.1.5, array-includes@^3.1.6, array-includes@^3.1.7: version "3.1.7" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== @@ -3126,7 +3119,7 @@ array-uniq@^1.0.1: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== -array.prototype.findlastindex@^1.2.2: +array.prototype.findlastindex@^1.2.3: 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== @@ -3137,7 +3130,7 @@ array.prototype.findlastindex@^1.2.2: es-shim-unscopables "^1.0.0" get-intrinsic "^1.2.1" -array.prototype.flat@^1.3.1: +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== @@ -3147,7 +3140,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.0, array.prototype.flatmap@^1.3.1: +array.prototype.flatmap@^1.3.0, array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -3218,7 +3211,7 @@ attr-accept@^2.2.2: resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -autoprefixer@^10.4.14: +autoprefixer@^10.4.14, autoprefixer@^10.4.15: version "10.4.16" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.16.tgz#fad1411024d8670880bdece3970aa72e3572feb8" integrity sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ== @@ -3230,32 +3223,20 @@ autoprefixer@^10.4.14: picocolors "^1.0.0" postcss-value-parser "^4.2.0" -autoprefixer@^10.4.15: - version "10.4.15" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530" - integrity sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew== - dependencies: - browserslist "^4.21.10" - caniuse-lite "^1.0.30001520" - fraction.js "^4.2.0" - normalize-range "^0.1.2" - picocolors "^1.0.0" - postcss-value-parser "^4.2.0" - available-typed-arrays@^1.0.5: version "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.1" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.1.tgz#6948854183ee7e7eae336b9877c5bafa027998ea" - integrity sha512-9l850jDDPnKq48nbad8SiEelCv4OrUWrKab/cPj0GScVg6cb6NbCCt/Ulk26QEq5jP9NnGr04Bit1BHyV6r5CQ== + version "4.8.2" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae" + integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g== axios@^1.1.3, axios@^1.3.4: - version "1.5.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267" - integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ== + version "1.5.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.1.tgz#11fbaa11fc35f431193a9564109c88c1f27b585f" + integrity sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -3292,29 +3273,29 @@ babel-plugin-macros@^3.1.0: cosmiconfig "^7.0.0" resolve "^1.19.0" -babel-plugin-polyfill-corejs2@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz#8097b4cb4af5b64a1d11332b6fb72ef5e64a054c" - integrity sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg== +babel-plugin-polyfill-corejs2@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz#b2df0251d8e99f229a8e60fc4efa9a68b41c8313" + integrity sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q== dependencies: "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.4.2" + "@babel/helper-define-polyfill-provider" "^0.4.3" semver "^6.3.1" -babel-plugin-polyfill-corejs3@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz#b4f719d0ad9bb8e0c23e3e630c0c8ec6dd7a1c52" - integrity sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA== +babel-plugin-polyfill-corejs3@^0.8.5: + version "0.8.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz#25c2d20002da91fe328ff89095c85a391d6856cf" + integrity sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ== dependencies: - "@babel/helper-define-polyfill-provider" "^0.4.2" - core-js-compat "^3.31.0" + "@babel/helper-define-polyfill-provider" "^0.4.3" + core-js-compat "^3.33.1" -babel-plugin-polyfill-regenerator@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz#80d0f3e1098c080c8b5a65f41e9427af692dc326" - integrity sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA== +babel-plugin-polyfill-regenerator@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz#d4c49e4b44614607c13fb769bcd85c72bb26a4a5" + integrity sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw== dependencies: - "@babel/helper-define-polyfill-provider" "^0.4.2" + "@babel/helper-define-polyfill-provider" "^0.4.3" bail@^2.0.0: version "2.0.2" @@ -3372,15 +3353,15 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.21.10, browserslist@^4.21.9: - version "4.21.10" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" - integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== +browserslist@^4.21.10, browserslist@^4.21.9, browserslist@^4.22.1: + version "4.22.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" + integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== dependencies: - caniuse-lite "^1.0.30001517" - electron-to-chromium "^1.4.477" + caniuse-lite "^1.0.30001541" + electron-to-chromium "^1.4.535" node-releases "^2.0.13" - update-browserslist-db "^1.0.11" + update-browserslist-db "^1.0.13" buffer-from@^1.0.0: version "1.1.2" @@ -3408,9 +3389,9 @@ bundle-require@^3.0.2: load-tsconfig "^0.2.0" bundle-require@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-4.0.1.tgz#2cc1ad76428043d15e0e7f30990ee3d5404aa2e3" - integrity sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ== + version "4.0.2" + resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-4.0.2.tgz#65fc74ff14eabbba36d26c9a6161bd78fff6b29e" + integrity sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag== dependencies: load-tsconfig "^0.2.3" @@ -3419,13 +3400,14 @@ cac@^6.7.12: resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== -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" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" callsites@^3.0.0: version "3.1.0" @@ -3445,15 +3427,10 @@ camelcase-css@^2.0.1: resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" 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.30001538" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz#9dbc6b9af1ff06b5eb12350c2012b3af56744f3f" - integrity sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw== - -caniuse-lite@^1.0.30001538: - version "1.0.30001541" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz#b1aef0fadd87fb72db4dcb55d220eae17b81cdb1" - integrity sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw== +caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: + version "1.0.30001553" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz#e64e7dc8fd4885cd246bb476471420beb5e474b5" + integrity sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A== capital-case@^1.0.4: version "1.0.4" @@ -3670,27 +3647,27 @@ constant-case@^3.0.4: tslib "^2.0.3" upper-case "^2.0.2" -convert-source-map@^1.5.0, convert-source-map@^1.7.0: +convert-source-map@^1.5.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== -cookie@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookie@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -core-js-compat@^3.31.0: - version "3.32.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.2.tgz#8047d1a8b3ac4e639f0d4f66d4431aa3b16e004c" - integrity sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ== +core-js-compat@^3.31.0, core-js-compat@^3.33.1: + version "3.33.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.33.1.tgz#debe80464107d75419e00c2ee29f35982118ff84" + integrity sha512-6pYKNOgD/j/bkC5xS5IIg6bncid3rfrI42oBH1SQJbsmYPKF7rhzcFzYCcxYMmNQQ0rCEB8WqpW7QHndOggaeQ== dependencies: - browserslist "^4.21.10" + browserslist "^4.22.1" cosmiconfig@^7.0.0: version "7.1.0" @@ -3912,10 +3889,10 @@ deepmerge@^4.2.2, deepmerge@^4.3.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -define-data-property@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.0.tgz#0db13540704e1d8d479a0656cf781267531b9451" - integrity sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g== +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== dependencies: get-intrinsic "^1.2.1" gopd "^1.0.1" @@ -4049,10 +4026,10 @@ ejs@^3.1.6: dependencies: jake "^10.8.5" -electron-to-chromium@^1.4.477: - version "1.4.525" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.525.tgz#614284f33901fbecd3e90176c0d60590cd939700" - integrity sha512-GIZ620hDK4YmIqAWkscG4W6RwY6gOx1y5J6f4JUQwctiJrqH2oxZYU4mXHi35oV32tr630UcepBzSBGJ/WYcZA== +electron-to-chromium@^1.4.535: + version "1.4.566" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.566.tgz#5c5ba1d2dc895f4887043f0cc7e61798c7e5919a" + integrity sha512-mv+fAy27uOmTVlUULy15U3DVJ+jg+8iyKH1bpwboCRhtDC69GKf1PPTZvEIhCyDr81RFqfxZJYrbgp933a1vtg== emoji-regex@^8.0.0: version "8.0.0" @@ -4105,25 +4082,25 @@ error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.22.1: - version "1.22.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.2.tgz#90f7282d91d0ad577f505e423e52d4c1d93c1b8a" - integrity sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA== + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== dependencies: array-buffer-byte-length "^1.0.0" arraybuffer.prototype.slice "^1.0.2" available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + call-bind "^1.0.5" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.1" + get-intrinsic "^1.2.2" get-symbol-description "^1.0.0" globalthis "^1.0.3" gopd "^1.0.1" - has "^1.0.3" has-property-descriptors "^1.0.0" has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" internal-slot "^1.0.5" is-array-buffer "^3.0.2" is-callable "^1.2.7" @@ -4133,7 +4110,7 @@ es-abstract@^1.22.1: is-string "^1.0.7" is-typed-array "^1.1.12" is-weakref "^1.0.2" - object-inspect "^1.12.3" + object-inspect "^1.13.1" object-keys "^1.1.1" object.assign "^4.1.4" regexp.prototype.flags "^1.5.1" @@ -4147,7 +4124,7 @@ es-abstract@^1.22.1: typed-array-byte-offset "^1.0.0" typed-array-length "^1.0.4" unbox-primitive "^1.0.2" - which-typed-array "^1.1.11" + which-typed-array "^1.1.13" es-iterator-helpers@^1.0.12: version "1.0.15" @@ -4170,20 +4147,20 @@ es-iterator-helpers@^1.0.12: safe-array-concat "^1.0.1" 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" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" + get-intrinsic "^1.2.2" has-tostringtag "^1.0.0" + hasown "^2.0.0" es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== dependencies: - has "^1.0.3" + hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" @@ -4430,13 +4407,13 @@ eslint-config-prettier@^8.3.0: integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== eslint-config-turbo@latest: - version "1.10.14" - resolved "https://registry.yarnpkg.com/eslint-config-turbo/-/eslint-config-turbo-1.10.14.tgz#5e0c5ef1942783a2f7ffb631f4f322906a52663d" - integrity sha512-ZeB+IcuFXy1OICkLuAplVa0euoYbhK+bMEQd0nH9+Lns18lgZRm33mVz/iSoH9VdUzl/1ZmFmoK+RpZc+8R80A== + version "1.10.16" + resolved "https://registry.yarnpkg.com/eslint-config-turbo/-/eslint-config-turbo-1.10.16.tgz#175cabd8eb1ec5fb8e254abcb09df3955fe476a1" + integrity sha512-O3NQI72bQHV7FvSC6lWj66EGx8drJJjuT1kuInn6nbMLOHdMBhSUX/8uhTAlHRQdlxZk2j9HtgFCIzSc93w42g== dependencies: - eslint-plugin-turbo "1.10.14" + eslint-plugin-turbo "1.10.16" -eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.7: +eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== @@ -4457,9 +4434,9 @@ eslint-import-resolver-typescript@^2.7.1: tsconfig-paths "^3.14.1" eslint-import-resolver-typescript@^3.5.2: - version "3.6.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.0.tgz#36f93e1eb65a635e688e16cae4bead54552e3bbd" - integrity sha512-QTHR9ddNnn35RTxlaEnx2gCxqFlF2SEN0SE2d17SqwyM7YOSI2GHWRYp5BiRkObTUNYPupC/3Fq2a0PpT+EKpg== + version "3.6.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" + integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== dependencies: debug "^4.3.4" enhanced-resolve "^5.12.0" @@ -4477,25 +4454,25 @@ 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.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4" - integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== dependencies: - array-includes "^3.1.6" - array.prototype.findlastindex "^1.2.2" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" + eslint-import-resolver-node "^0.3.9" eslint-module-utils "^2.8.0" - has "^1.0.3" - is-core-module "^2.13.0" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.fromentries "^2.0.6" - object.groupby "^1.0.0" - object.values "^1.1.6" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" semver "^6.3.1" tsconfig-paths "^3.14.2" @@ -4568,10 +4545,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.14: - version "1.10.14" - resolved "https://registry.yarnpkg.com/eslint-plugin-turbo/-/eslint-plugin-turbo-1.10.14.tgz#b9b7ffc2faef52cb158088e00f9ef6fe39966bd9" - integrity sha512-sBdBDnYr9AjT1g4lR3PBkZDonTrMnR4TvuGv5W0OiF7z9az1rI68yj2UHJZvjkwwcGu5mazWA1AfB0oaagpmfg== +eslint-plugin-turbo@1.10.16: + version "1.10.16" + resolved "https://registry.yarnpkg.com/eslint-plugin-turbo/-/eslint-plugin-turbo-1.10.16.tgz#368723f2140617f273c60f65b09267f73b496cd9" + integrity sha512-ZjrR88MTN64PNGufSEcM0tf+V1xFYVbeiMeuIqr0aiABGomxFLo4DBkQ7WI4WzkZtWQSIA2sP+yxqSboEfL9MQ== dependencies: dotenv "16.0.3" @@ -4758,17 +4735,18 @@ eslint@^7.23.0, eslint@^7.32.0: v8-compile-cache "^2.0.3" eslint@^8.31.0: - version "8.49.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" - integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== + version "8.52.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" + integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.49.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint/js" "8.52.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -4902,7 +4880,7 @@ fast-fifo@^1.1.0, fast-fifo@^1.2.0: 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: +fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== @@ -5004,15 +4982,15 @@ find-up@^5.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.1.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.0.tgz#0e54ab4a1a60fe87e2946b6b00657f1c99e1af3f" - integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew== + version "3.1.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" + integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q== dependencies: - flatted "^3.2.7" + flatted "^3.2.9" keyv "^4.5.3" rimraf "^3.0.2" -flatted@^3.2.7: +flatted@^3.2.9: version "3.2.9" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== @@ -5043,10 +5021,10 @@ format@^0.2.0: resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== -fraction.js@^4.2.0, fraction.js@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d" - integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg== +fraction.js@^4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== framework-utils@^1.1.0: version "1.1.0" @@ -5078,10 +5056,10 @@ fsevents@~2.3.2: 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" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.1, function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: version "1.1.6" @@ -5109,22 +5087,22 @@ gensync@^1.0.0-beta.2: integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== gesto@^1.19.0, gesto@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/gesto/-/gesto-1.19.1.tgz#b2a29730663eecf77b248982bbff929e79d4a461" - integrity sha512-ofWVEdqmnpFm3AFf7aoclhoayseb3OkwSiXbXusKYu/99iN5HgeWP+SWqdghQ5TFlOgP5Zlz+6SY8mP2V0kFaQ== + version "1.19.2" + resolved "https://registry.yarnpkg.com/gesto/-/gesto-1.19.2.tgz#1f5ab5cf49bd5a1ec2ee3805f35e77161343ea7b" + integrity sha512-i6OGsrR2GN7n2dQaUhY+LZ+AAZgBNg5/1kest/ST5VRRflfVl5bSfvOkJMDmKEUrGbKF6eIDkFz/DnCXJD4UMA== dependencies: "@daybrush/utils" "^1.13.0" "@scena/event-emitter" "^1.0.2" -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== dependencies: - function-bind "^1.1.1" - has "^1.0.3" + function-bind "^1.1.2" has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" get-nonce@^1.0.0: version "1.0.1" @@ -5150,9 +5128,9 @@ get-symbol-description@^1.0.0: get-intrinsic "^1.1.1" get-tsconfig@^4.5.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.0.tgz#06ce112a1463e93196aa90320c35df5039147e34" - integrity sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw== + version "4.7.2" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" + integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== dependencies: resolve-pkg-maps "^1.0.0" @@ -5228,9 +5206,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0, globals@^13.6.0, globals@^13.9.0: - version "13.21.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.21.0.tgz#163aae12f34ef502f5153cfbdd3600f36c63c571" - integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== + version "13.23.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" + integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== dependencies: type-fest "^0.20.2" @@ -5307,11 +5285,11 @@ has-flag@^4.0.0: integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== dependencies: - get-intrinsic "^1.1.1" + get-intrinsic "^1.2.2" has-proto@^1.0.1: version "1.0.1" @@ -5331,11 +5309,16 @@ has-tostringtag@^1.0.0: has-symbols "^1.0.2" has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + 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" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== dependencies: - function-bind "^1.1.1" + function-bind "^1.1.2" hast-util-whitespace@^2.0.0: version "2.0.1" @@ -5350,7 +5333,12 @@ header-case@^2.0.4: capital-case "^1.0.4" tslib "^2.0.3" -highlight.js@^11.8.0, highlight.js@~11.8.0: +highlight.js@^11.8.0, highlight.js@~11.9.0: + version "11.9.0" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0" + integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw== + +highlight.js@~11.8.0: version "11.8.0" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.8.0.tgz#966518ea83257bae2e7c9a48596231856555bb65" integrity sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg== @@ -5437,12 +5425,12 @@ inline-style-parser@0.1.1: integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== 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== + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" + get-intrinsic "^1.2.2" + hasown "^2.0.0" side-channel "^1.0.4" internmap@^1.0.0: @@ -5523,12 +5511,12 @@ 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.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== +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: - has "^1.0.3" + hasown "^2.0.0" is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" @@ -5775,7 +5763,7 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jiti@^1.18.2: +jiti@^1.19.1: version "1.20.0" resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== @@ -5907,9 +5895,9 @@ keycon@^1.2.0: 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== + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" @@ -6071,13 +6059,13 @@ lowlight@^2.9.0: highlight.js "~11.8.0" lowlight@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-3.0.0.tgz#8772e6514f1c14cd576b5a7a22668f5aa2ddd10b" - integrity sha512-kedX6yxvgak8P4LGh3vKRDQuMbVcnP+qRuDJlve2w+mNJAbEhEQPjYCp9QJnpVL5F2aAAVjeIzzrbQZUKHiDJw== + version "3.1.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-3.1.0.tgz#aa394c5f3a7689fce35fa49a7c850ba3ead4f590" + integrity sha512-CEbNVoSikAxwDMDPjXlqlFYiZLkDJHwyGu/MfOsJnF3d7f3tds5J3z8s/l9TMXhzfsJCCJEAsD78842mwmg0PQ== dependencies: "@types/hast" "^3.0.0" devlop "^1.0.0" - highlight.js "~11.8.0" + highlight.js "~11.9.0" lru-cache@^5.1.1: version "5.1.1" @@ -6093,11 +6081,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== - lucide-react@^0.244.0: version "0.244.0" resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.244.0.tgz#9626f44881830280012dad23afda7ddbcffff24b" @@ -6145,9 +6128,9 @@ markdown-it-task-lists@^2.1.1: integrity sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA== markdown-it@^13.0.1: - version "13.0.1" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430" - integrity sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q== + version "13.0.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.2.tgz#1bc22e23379a6952e5d56217fbed881e0c94d536" + integrity sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w== dependencies: argparse "^2.0.1" entities "~3.0.1" @@ -6489,9 +6472,9 @@ mkdirp@^0.5.5: minimist "^1.2.6" mobx-react-lite@^4.0.3: - 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== + version "4.0.5" + resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-4.0.5.tgz#e2cb98f813e118917bcc463638f5bf6ea053a67b" + integrity sha512-StfB2wxE8imKj1f6T8WWPf4lVMx3cYH9Iy60bbKXEs21+HQ4tvvfIBZfSmMXgQAefi8xYEwQIz4GN9s0d2h7dg== dependencies: use-sync-external-store "^1.2.0" @@ -6604,9 +6587,9 @@ no-case@^3.0.4: tslib "^2.0.3" node-abi@^3.3.0: - version "3.47.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.47.0.tgz#6cbfa2916805ae25c2b7156ca640131632eb05e8" - integrity sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A== + version "3.51.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.51.0.tgz#970bf595ef5a26a271307f8a4befa02823d4e87d" + integrity sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA== dependencies: semver "^7.3.5" @@ -6664,10 +6647,10 @@ object-hash@^3.0.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== -object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== object-is@^1.0.1: version "1.1.5" @@ -6701,7 +6684,7 @@ object.entries@^1.1.5, object.entries@^1.1.6: define-properties "^1.2.0" es-abstract "^1.22.1" -object.fromentries@^2.0.5, object.fromentries@^2.0.6: +object.fromentries@^2.0.5, object.fromentries@^2.0.6, object.fromentries@^2.0.7: 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== @@ -6710,7 +6693,7 @@ object.fromentries@^2.0.5, object.fromentries@^2.0.6: define-properties "^1.2.0" es-abstract "^1.22.1" -object.groupby@^1.0.0: +object.groupby@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== @@ -6742,7 +6725,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.5, object.values@^1.1.6: +object.values@^1.1.5, object.values@^1.1.6, object.values@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== @@ -7017,9 +7000,9 @@ postcss@8.4.14: source-map-js "^1.0.2" postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.29: - version "8.4.30" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7" - integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" @@ -7054,9 +7037,9 @@ prettier-plugin-tailwindcss@^0.3.0: integrity sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA== prettier-plugin-tailwindcss@^0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.4.tgz#ebfacbcb90e2ca1df671ffe4083e99f81d72040d" - integrity sha512-QZzzB1bID6qPsKHTeA9qPo1APmmxfFrA5DD3LQ+vbTmAnY40eJI7t9Q1ocqel2EKMWNPLJqdTDWZj1hKYgqSgg== + version "0.5.6" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.6.tgz#8e511857a49bf127f078985f52b04a70e8e92285" + integrity sha512-2Xgb+GQlkPAUCFi3sV+NOYcSI5XgduvDBL2Zt/hwJudeKXkyvRS65c38SB0yb9UB40+1rL83I6m0RtlOQ8eHdg== prettier@^2.8.7, prettier@^2.8.8: version "2.8.8" @@ -7231,16 +7214,16 @@ 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.5" - resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.7.5.tgz#c62aac8645bd4f8cf447d6d53dda80abe8489f03" - integrity sha512-U/fWB6frEzY7dzwJUo+ir8dU1JEanaI/RwL12Imy9js/527N0v/IRUKewocP1kTq998JNT18IGtThaDLwLOBxQ== + version "1.8.0" + resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.8.0.tgz#a47c64a3c373c1bd0ff46e95be3210c8dda0cd11" + integrity sha512-BaSBsIMv52F1BVVMvOmp1yzD3u65uC3HTzCBQV1WDPqJRQ2LuHKcyfn0jwqodo8sR9vVzMzZyI+Dal5W9E6a9A== dependencies: 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.31.8" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.31.8.tgz#01c566a1c26c5a082ca4c04c017b832e1ea45b1f" - integrity sha512-VQrEIdiPJ4YV65Ifj2kWISwaiqocMHy7cpUKVQYt19C/87FepoqnwVW3kMKRpeY/nQzED8L+vyOaYDBn0WqT7w== + version "1.32.1" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.32.1.tgz#bcd0877f1673ffe5f94c1e966b6fbdadcd2d5bbf" + integrity sha512-9SnB4HBgRczzTyIMZLPE1iszegL04hNfUyS8uPtP1RPxNM2NTCiIs8KwNsJU4nbZO9rxJTwVTv7Jm3zU4CR78A== dependencies: prosemirror-model "^1.16.0" prosemirror-state "^1.0.0" @@ -7331,9 +7314,9 @@ react-css-styled@^1.1.9: framework-utils "^1.1.0" react-datepicker@^4.8.0: - version "4.18.0" - resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.18.0.tgz#d66301acc47833d31fa6f46f98781b084106da0e" - integrity sha512-0MYt3HmLbHVk1sw4v+RCbLAVg5TA3jWP7RyjZbo53PC+SEi+pjdgc92lB53ai/ENZaTOhbXmgni9GzvMrorMAw== + version "4.21.0" + resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.21.0.tgz#09b2ba3e53654a8563b22c9f649835716c8456d3" + integrity sha512-z0DtuRrKMz9i7dcTusW29VacbM9pn08g1yw0cG+Y5GpodJDxSWv7zUMxl3IwKN9Ap/AMphiepvmT5P+iNCgEiA== dependencies: "@popperjs/core" "^2.11.8" classnames "^2.2.6" @@ -7365,9 +7348,9 @@ react-fast-compare@^3.0.1: integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== react-hook-form@^7.38.0: - version "7.46.1" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.46.1.tgz#39347dbff19d980cb41087ac32a57abdc6045bb3" - integrity sha512-0GfI31LRTBd5tqbXMGXT1Rdsv3rnvy0FjEk8Gn9/4tp6+s77T7DPZuGEpBRXOauL+NhyGT5iaXzdIM2R6F/E+w== + version "7.47.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.47.0.tgz#a42f07266bd297ddf1f914f08f4b5f9783262f31" + integrity sha512-F/TroLjTICipmHeFlMrLtNLceO2xr1jU3CyiNla5zdwsGUGu2UOxxR4UyJgLlhMwLW/Wzp4cpJ7CPfgJIeKdSg== react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" @@ -7468,9 +7451,9 @@ react-redux@^7.2.0: react-is "^17.0.2" react-redux@^8.1.1: - version "8.1.2" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188" - integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw== + version "8.1.3" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.3.tgz#4fdc0462d0acb59af29a13c27ffef6f49ab4df46" + integrity sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw== dependencies: "@babel/runtime" "^7.12.1" "@types/hoist-non-react-statics" "^3.3.1" @@ -7676,21 +7659,21 @@ 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.4: - version "1.22.6" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" - integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== +resolve@1.22.8, 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.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" resolve@^2.0.0-next.3, resolve@^2.0.0-next.4: - version "2.0.0-next.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" - integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -7738,9 +7721,9 @@ rollup@^2.43.1, rollup@^2.74.1: fsevents "~2.3.2" rollup@^3.2.5: - version "3.29.2" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.2.tgz#cbc76cd5b03b9f9e93be991d23a1dff9c6d5b740" - integrity sha512-CJouHoZ27v6siztc21eEQGo0kIcE5D1gVPA571ez0mMYb25LGYGKnVNXpEj5MGlepmDWGXNjDB5q7uNiPHC11A== + version "3.29.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" + integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== optionalDependencies: fsevents "~2.3.2" @@ -7863,6 +7846,16 @@ serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + set-function-name@^2.0.0, set-function-name@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" @@ -8120,9 +8113,9 @@ strip-json-comments@~2.0.1: integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== style-to-object@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.2.tgz#a8247057111dea8bd3b8a1a66d2d0c9cf9218a54" - integrity sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA== + version "0.4.4" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.4.tgz#266e3dfd56391a7eefb7770423612d043c3f33ec" + integrity sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg== dependencies: inline-style-parser "0.1.1" @@ -8176,9 +8169,9 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 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== + version "2.2.4" + resolved "https://registry.yarnpkg.com/swr/-/swr-2.2.4.tgz#03ec4c56019902fbdc904d78544bd7a9a6fa3f07" + integrity sha512-njiZ/4RiIhoOlAaLYDqwz5qH/KZXVilRLvomrx83HjzCWTfa+InyfAjv05PSFxnmLzZkNO9ZfvgoqzAaEI4sGQ== dependencies: client-only "^0.0.1" use-sync-external-store "^1.2.0" @@ -8205,19 +8198,19 @@ tailwindcss-animate@^1.0.6: integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA== tailwindcss@^3.2.7, tailwindcss@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" - integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== + version "3.3.4" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.4.tgz#f08c493ff3ddf03081c40e780e98f129e1c8214d" + integrity sha512-JXZNOkggUAc9T5E7nCrimoXHcSf9h3NWFe5sh36CGD/3M5TRLuQeFnQoDsit2uVTqgoOZHLx5rTykLUu16vsMQ== dependencies: "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" chokidar "^3.5.3" didyoumean "^1.2.2" dlv "^1.1.3" - fast-glob "^3.2.12" + fast-glob "^3.3.0" glob-parent "^6.0.2" is-glob "^4.0.3" - jiti "^1.18.2" + jiti "^1.19.1" lilconfig "^2.1.0" micromatch "^4.0.5" normalize-path "^3.0.0" @@ -8303,9 +8296,9 @@ terser-webpack-plugin@^5.3.3: terser "^5.16.8" terser@^5.0.0, terser@^5.16.8: - version "5.19.4" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.4.tgz#941426fa482bf9b40a0308ab2b3cd0cf7c775ebd" - integrity sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g== + version "5.22.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.22.0.tgz#4f18103f84c5c9437aafb7a14918273310a8a49d" + integrity sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -8364,9 +8357,9 @@ tiptap-markdown@^0.8.2: prosemirror-markdown "^1.11.1" tlds@^1.238.0: - version "1.242.0" - resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.242.0.tgz#da136a9c95b0efa1a4cd57dca8ef240c08ada4b7" - integrity sha512-aP3dXawgmbfU94mA32CJGHmJUE1E58HCB1KmlKRhBNtqBL27mSQcAEmcaMaQ1Za9kIVvOdbxJD3U5ycDy7nJ3w== + version "1.243.0" + resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.243.0.tgz#0dd9e6373633c495fa0c20fdafe9aaea6ff34550" + integrity sha512-jA0EMB5YFZFX2VqmK/Ra4O1UqDuWnpiw/9miYFdG1lVIDg6w9IsjlXK0TGlqFnzsnuBIpP5rCDFT2iPZNOfvqA== to-fast-properties@^2.0.0: version "2.0.0" @@ -8427,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.4.1 || ^1.9.3": +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -8491,47 +8484,47 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -turbo-darwin-64@1.10.14: - version "1.10.14" - resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.10.14.tgz#9e8061bc0d706a69bc61d88fbfa7690fa2a897fc" - integrity sha512-I8RtFk1b9UILAExPdG/XRgGQz95nmXPE7OiGb6ytjtNIR5/UZBS/xVX/7HYpCdmfriKdVwBKhalCoV4oDvAGEg== +turbo-darwin-64@1.10.16: + version "1.10.16" + resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.10.16.tgz#5a8717c1372f2a75e8cfe0b4b6455119ce410b19" + integrity sha512-+Jk91FNcp9e9NCLYlvDDlp2HwEDp14F9N42IoW3dmHI5ZkGSXzalbhVcrx3DOox3QfiNUHxzWg4d7CnVNCuuMg== -turbo-darwin-arm64@1.10.14: - version "1.10.14" - resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.10.14.tgz#2589aeb814257601c979dd40ff8a6cace6c9e4e5" - integrity sha512-KAdUWryJi/XX7OD0alOuOa0aJ5TLyd4DNIYkHPHYcM6/d7YAovYvxRNwmx9iv6Vx6IkzTnLeTiUB8zy69QkG9Q== +turbo-darwin-arm64@1.10.16: + version "1.10.16" + resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.10.16.tgz#19b5b63acf7ee0fce7e1fe5850e093c2ac9c73f5" + integrity sha512-jqGpFZipIivkRp/i+jnL8npX0VssE6IAVNKtu573LXtssZdV/S+fRGYA16tI46xJGxSAivrZ/IcgZrV6Jk80bw== -turbo-linux-64@1.10.14: - version "1.10.14" - resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.10.14.tgz#c01d26f62f6c47701026dea083054918fe8caf47" - integrity sha512-BOBzoREC2u4Vgpap/WDxM6wETVqVMRcM8OZw4hWzqCj2bqbQ6L0wxs1LCLWVrghQf93JBQtIGAdFFLyCSBXjWQ== +turbo-linux-64@1.10.16: + version "1.10.16" + resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.10.16.tgz#ee97c0011553a96bd7995e7bcc6e65aab8996798" + integrity sha512-PpqEZHwLoizQ6sTUvmImcRmACyRk9EWLXGlqceogPZsJ1jTRK3sfcF9fC2W56zkSIzuLEP07k5kl+ZxJd8JMcg== -turbo-linux-arm64@1.10.14: - version "1.10.14" - resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.10.14.tgz#7cbcb091995a09134342a57e0672501115b46df2" - integrity sha512-D8T6XxoTdN5D4V5qE2VZG+/lbZX/89BkAEHzXcsSUTRjrwfMepT3d2z8aT6hxv4yu8EDdooZq/2Bn/vjMI32xw== +turbo-linux-arm64@1.10.16: + version "1.10.16" + resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.10.16.tgz#2723cc2a846d89df7484002161b25673f4f04009" + integrity sha512-TMjFYz8to1QE0fKVXCIvG/4giyfnmqcQIwjdNfJvKjBxn22PpbjeuFuQ5kNXshUTRaTJihFbuuCcb5OYFNx4uw== -turbo-windows-64@1.10.14: - version "1.10.14" - resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.10.14.tgz#935d2d1da7fb1f9a941fb3aa122fd9a70b61c416" - integrity sha512-zKNS3c1w4i6432N0cexZ20r/aIhV62g69opUn82FLVs/zk3Ie0GVkSB6h0rqIvMalCp7enIR87LkPSDGz9K4UA== +turbo-windows-64@1.10.16: + version "1.10.16" + resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.10.16.tgz#87c46a78502a86dec73634b255a6b3471285969b" + integrity sha512-+jsf68krs0N66FfC4/zZvioUap/Tq3sPFumnMV+EBo8jFdqs4yehd6+MxIwYTjSQLIcpH8KoNMB0gQYhJRLZzw== -turbo-windows-arm64@1.10.14: - version "1.10.14" - resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.10.14.tgz#cb3a55d30a75aa76258991e929e92f207cac872f" - integrity sha512-rkBwrTPTxNSOUF7of8eVvvM+BkfkhA2OvpHM94if8tVsU+khrjglilp8MTVPHlyS9byfemPAmFN90oRIPB05BA== +turbo-windows-arm64@1.10.16: + version "1.10.16" + resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.10.16.tgz#a6208c2bc27e5e6ef0aa4a3e64389c4285c3f274" + integrity sha512-sKm3hcMM1bl0B3PLG4ifidicOGfoJmOEacM5JtgBkYM48ncMHjkHfFY7HrJHZHUnXM4l05RQTpLFoOl/uIo2HQ== turbo@^1.10.14: - version "1.10.14" - resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.10.14.tgz#31f3bb3017218191e0de64728da199678a50aa7d" - integrity sha512-hr9wDNYcsee+vLkCDIm8qTtwhJ6+UAMJc3nIY6+PNgUTtXcQgHxCq8BGoL7gbABvNWv76CNbK5qL4Lp9G3ZYRA== + version "1.10.16" + resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.10.16.tgz#51601a65a3aa56d1b9d9cb9a2ab3a5a2eab41e19" + integrity sha512-2CEaK4FIuSZiP83iFa9GqMTQhroW2QryckVqUydmg4tx78baftTOS0O+oDAhvo9r9Nit4xUEtC1RAHoqs6ZEtg== optionalDependencies: - turbo-darwin-64 "1.10.14" - turbo-darwin-arm64 "1.10.14" - turbo-linux-64 "1.10.14" - turbo-linux-arm64 "1.10.14" - turbo-windows-64 "1.10.14" - turbo-windows-arm64 "1.10.14" + turbo-darwin-64 "1.10.16" + turbo-darwin-arm64 "1.10.16" + turbo-linux-64 "1.10.16" + turbo-linux-arm64 "1.10.16" + turbo-windows-64 "1.10.16" + turbo-windows-arm64 "1.10.16" type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -8629,6 +8622,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +undici-types@~5.25.1: + version "5.25.3" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" + integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" @@ -8725,10 +8723,10 @@ upath@^1.2.0: resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -update-browserslist-db@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== dependencies: escalade "^3.1.1" picocolors "^1.0.0" @@ -8927,13 +8925,13 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -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== +which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.9: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== dependencies: available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + call-bind "^1.0.4" for-each "^0.3.3" gopd "^1.0.1" has-tostringtag "^1.0.0" @@ -9135,9 +9133,9 @@ yaml@^1.10.0, yaml@^1.10.2: integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yaml@^2.1.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" - integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg== + version "2.3.3" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.3.tgz#01f6d18ef036446340007db8e016810e5d64aad9" + integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ== yocto-queue@^0.1.0: version "0.1.0" From 597ea26d7ba24093db39e6ad90e0f8c7b8f30883 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Fri, 27 Oct 2023 13:14:03 +0530 Subject: [PATCH 08/17] fix: enabling the nextjs static site generation for web and space (#2547) --- .gitignore | 3 ++- space/next.config.js | 3 +++ space/package.json | 7 ++++--- web/next.config.js | 1 + web/package.json | 3 ++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 8bf25a3f3..7568602d3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,8 @@ node_modules # Production /build -dist +dist/ +out/ # Misc .DS_Store diff --git a/space/next.config.js b/space/next.config.js index bd3749f10..7e9865784 100644 --- a/space/next.config.js +++ b/space/next.config.js @@ -8,6 +8,9 @@ const nextConfig = { experimental: { outputFileTracingRoot: path.join(__dirname, "../"), }, + images: { + unoptimized: true, + }, output: "standalone", }; diff --git a/space/package.json b/space/package.json index 3c32211d0..5f3f60dc9 100644 --- a/space/package.json +++ b/space/package.json @@ -7,7 +7,8 @@ "develop": "next dev -p 4000", "build": "next build", "start": "next start -p 4000", - "lint": "next lint" + "lint": "next lint", + "export": "next export" }, "dependencies": { "@blueprintjs/core": "^4.16.3", @@ -16,8 +17,8 @@ "@emotion/styled": "^11.11.0", "@headlessui/react": "^1.7.13", "@mui/material": "^5.14.1", - "@plane/ui" : "*", - "@plane/lite-text-editor" : "*", + "@plane/ui": "*", + "@plane/lite-text-editor": "*", "@plane/rich-text-editor": "*", "axios": "^1.3.4", "clsx": "^2.0.0", diff --git a/web/next.config.js b/web/next.config.js index 058a68b7d..1bfac8fd2 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -21,6 +21,7 @@ const nextConfig = { "localhost", ...extraImageDomains, ], + unoptimized: true, }, output: "standalone", experimental: { diff --git a/web/package.json b/web/package.json index c80d4c509..c4513a555 100644 --- a/web/package.json +++ b/web/package.json @@ -7,7 +7,8 @@ "develop": "next dev --port 3000", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "export": "next export" }, "dependencies": { "@blueprintjs/core": "^4.16.3", From 55b2927a1708514d0e014f6de990fab4bb737ade Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:30:28 +0530 Subject: [PATCH 09/17] chore: total issues count for issue listing endpoint (#2534) * chore: total issues count for issue listing endpoint * dev: add print for DEBUG mode * fix: changed assignees_list and label_list --------- Co-authored-by: NarayanBavisetti --- apiserver/plane/api/serializers/issue.py | 18 ++++++++----- apiserver/plane/api/views/base.py | 2 ++ apiserver/plane/api/views/cycle.py | 7 +++--- apiserver/plane/api/views/issue.py | 32 +++++++++++++++++------- apiserver/plane/api/views/module.py | 8 +++--- apiserver/plane/api/views/view.py | 9 +++++-- apiserver/plane/api/views/workspace.py | 11 ++++++-- 7 files changed, 61 insertions(+), 26 deletions(-) diff --git a/apiserver/plane/api/serializers/issue.py b/apiserver/plane/api/serializers/issue.py index 57539f24c..2b64e22ef 100644 --- a/apiserver/plane/api/serializers/issue.py +++ b/apiserver/plane/api/serializers/issue.py @@ -75,13 +75,13 @@ class IssueCreateSerializer(BaseSerializer): project_detail = ProjectLiteSerializer(read_only=True, source="project") workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") - assignees_list = serializers.ListField( + assignees = serializers.ListField( child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()), write_only=True, required=False, ) - labels_list = serializers.ListField( + labels = serializers.ListField( child=serializers.PrimaryKeyRelatedField(queryset=Label.objects.all()), write_only=True, required=False, @@ -99,6 +99,12 @@ class IssueCreateSerializer(BaseSerializer): "updated_at", ] + def to_representation(self, instance): + data = super().to_representation(instance) + data['assignees'] = [str(assignee.id) for assignee in instance.assignees.all()] + data['labels'] = [str(label.id) for label in instance.labels.all()] + return data + def validate(self, data): if ( data.get("start_date", None) is not None @@ -109,8 +115,8 @@ class IssueCreateSerializer(BaseSerializer): return data def create(self, validated_data): - assignees = validated_data.pop("assignees_list", None) - labels = validated_data.pop("labels_list", None) + assignees = validated_data.pop("assignees", None) + labels = validated_data.pop("labels", None) project_id = self.context["project_id"] workspace_id = self.context["workspace_id"] @@ -168,8 +174,8 @@ class IssueCreateSerializer(BaseSerializer): return issue def update(self, instance, validated_data): - assignees = validated_data.pop("assignees_list", None) - labels = validated_data.pop("labels_list", None) + assignees = validated_data.pop("assignees", None) + labels = validated_data.pop("labels", None) # Related models project_id = instance.project_id diff --git a/apiserver/plane/api/views/base.py b/apiserver/plane/api/views/base.py index 538c8e484..7ab660e81 100644 --- a/apiserver/plane/api/views/base.py +++ b/apiserver/plane/api/views/base.py @@ -84,6 +84,7 @@ class BaseViewSet(TimezoneMixin, ModelViewSet, BasePaginator): capture_exception(e) return Response({"error": f"key {e} does not exist"}, status=status.HTTP_400_BAD_REQUEST) + print(e) if settings.DEBUG else print("Server Error") capture_exception(e) return Response({"error": "Something went wrong please try again later"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -161,6 +162,7 @@ class BaseAPIView(TimezoneMixin, APIView, BasePaginator): if isinstance(e, KeyError): return Response({"error": f"key {e} does not exist"}, status=status.HTTP_400_BAD_REQUEST) + print(e) if settings.DEBUG else print("Server Error") capture_exception(e) return Response({"error": "Something went wrong please try again later"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) diff --git a/apiserver/plane/api/views/cycle.py b/apiserver/plane/api/views/cycle.py index 7b14af4a2..cfab09801 100644 --- a/apiserver/plane/api/views/cycle.py +++ b/apiserver/plane/api/views/cycle.py @@ -579,6 +579,7 @@ class CycleIssueViewSet(BaseViewSet): ) ) + total_issues = issues.count() issues_data = IssueStateSerializer(issues, many=True).data if sub_group_by and sub_group_by == group_by: @@ -588,14 +589,14 @@ class CycleIssueViewSet(BaseViewSet): ) if group_by: + grouped_results = group_results(issues_data, group_by, sub_group_by) return Response( - group_results(issues_data, group_by, sub_group_by), + {"data": grouped_results, "total_issues": total_issues}, status=status.HTTP_200_OK, ) return Response( - issues_data, - status=status.HTTP_200_OK, + {"data": issues_data, "total_issues": total_issues}, status=status.HTTP_200_OK ) def create(self, request, slug, project_id, cycle_id): diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index be95c304e..e4a2f68b8 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -217,6 +217,7 @@ class IssueViewSet(BaseViewSet): else: issue_queryset = issue_queryset.order_by(order_by_param) + total_issues = issue_queryset.count() issues = IssueLiteSerializer(issue_queryset, many=True).data ## Grouping the results @@ -229,12 +230,16 @@ class IssueViewSet(BaseViewSet): ) if group_by: + grouped_results = group_results(issues, group_by, sub_group_by) return Response( - group_results(issues, group_by, sub_group_by), + {"data": grouped_results, "total_issues": total_issues}, status=status.HTTP_200_OK, ) - return Response(issues, status=status.HTTP_200_OK) + return Response( + {"data": issues, "total_issues": total_issues}, status=status.HTTP_200_OK + ) + def create(self, request, slug, project_id): project = Project.objects.get(pk=project_id) @@ -421,6 +426,7 @@ class UserWorkSpaceIssues(BaseAPIView): else: issue_queryset = issue_queryset.order_by(order_by_param) + total_issues = issue_queryset.count() issues = IssueLiteSerializer(issue_queryset, many=True).data ## Grouping the results @@ -433,12 +439,15 @@ class UserWorkSpaceIssues(BaseAPIView): ) if group_by: + grouped_results = group_results(issues, group_by, sub_group_by) return Response( - group_results(issues, group_by, sub_group_by), + {"data": grouped_results, "total_issues": total_issues}, status=status.HTTP_200_OK, ) - return Response(issues, status=status.HTTP_200_OK) + return Response( + {"data": issues, "total_issues": total_issues}, status=status.HTTP_200_OK + ) class WorkSpaceIssuesEndpoint(BaseAPIView): @@ -1165,9 +1174,7 @@ class IssueSubscriberViewSet(BaseViewSet): def list(self, request, slug, project_id, issue_id): members = ( - ProjectMember.objects.filter( - workspace__slug=slug, project_id=project_id - ) + ProjectMember.objects.filter(workspace__slug=slug, project_id=project_id) .annotate( is_subscribed=Exists( IssueSubscriber.objects.filter( @@ -2169,14 +2176,21 @@ class IssueDraftViewSet(BaseViewSet): else: issue_queryset = issue_queryset.order_by(order_by_param) + total_issues = issue_queryset.count() issues = IssueLiteSerializer(issue_queryset, many=True).data ## Grouping the results group_by = request.GET.get("group_by", False) if group_by: - return Response(group_results(issues, group_by), status=status.HTTP_200_OK) + grouped_results = group_results(issues, group_by) + return Response( + {"data": grouped_results, "total_issues": total_issues}, + status=status.HTTP_200_OK, + ) - return Response(issues, status=status.HTTP_200_OK) + return Response( + {"data": issues, "total_issues": total_issues}, status=status.HTTP_200_OK + ) def create(self, request, slug, project_id): project = Project.objects.get(pk=project_id) diff --git a/apiserver/plane/api/views/module.py b/apiserver/plane/api/views/module.py index ba088ea9c..45c52c0bf 100644 --- a/apiserver/plane/api/views/module.py +++ b/apiserver/plane/api/views/module.py @@ -361,7 +361,7 @@ class ModuleIssueViewSet(BaseViewSet): .values("count") ) ) - + total_issues = issues.count() issues_data = IssueStateSerializer(issues, many=True).data if sub_group_by and sub_group_by == group_by: @@ -371,14 +371,14 @@ class ModuleIssueViewSet(BaseViewSet): ) if group_by: + grouped_results = group_results(issues_data, group_by, sub_group_by) return Response( - group_results(issues_data, group_by, sub_group_by), + {"data": grouped_results, "total_issues": total_issues}, status=status.HTTP_200_OK, ) return Response( - issues_data, - status=status.HTTP_200_OK, + {"data": issues_data, "total_issues": total_issues}, status=status.HTTP_200_OK ) def create(self, request, slug, project_id, module_id): diff --git a/apiserver/plane/api/views/view.py b/apiserver/plane/api/views/view.py index 0e4b074c6..c549324a1 100644 --- a/apiserver/plane/api/views/view.py +++ b/apiserver/plane/api/views/view.py @@ -184,6 +184,7 @@ class GlobalViewIssuesViewSet(BaseViewSet): else: issue_queryset = issue_queryset.order_by(order_by_param) + total_issues = issue_queryset.count() issues = IssueLiteSerializer(issue_queryset, many=True).data ## Grouping the results @@ -196,11 +197,15 @@ class GlobalViewIssuesViewSet(BaseViewSet): ) if group_by: + grouped_results = group_results(issues, group_by, sub_group_by) return Response( - group_results(issues, group_by, sub_group_by), status=status.HTTP_200_OK + {"data": grouped_results, "total_issues": total_issues}, + status=status.HTTP_200_OK, ) - return Response(issues, status=status.HTTP_200_OK) + return Response( + {"data": issues, "total_issues": total_issues}, status=status.HTTP_200_OK + ) class IssueViewViewSet(BaseViewSet): diff --git a/apiserver/plane/api/views/workspace.py b/apiserver/plane/api/views/workspace.py index 9aa0ebcd9..e92859f14 100644 --- a/apiserver/plane/api/views/workspace.py +++ b/apiserver/plane/api/views/workspace.py @@ -1223,14 +1223,21 @@ class WorkspaceUserProfileIssuesEndpoint(BaseAPIView): else: issue_queryset = issue_queryset.order_by(order_by_param) + total_issues = issue_queryset.count() issues = IssueLiteSerializer(issue_queryset, many=True).data ## Grouping the results group_by = request.GET.get("group_by", False) if group_by: - return Response(group_results(issues, group_by), status=status.HTTP_200_OK) + grouped_results = group_results(issues, group_by) + return Response( + {"data": grouped_results, "total_issues": total_issues}, + status=status.HTTP_200_OK, + ) - return Response(issues, status=status.HTTP_200_OK) + return Response( + {"data": issues, "total_issues": total_issues}, status=status.HTTP_200_OK + ) class WorkspaceLabelsEndpoint(BaseAPIView): From c8f98a9bc20580df87e6ffb91c3065ce45d3d194 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:31:15 +0530 Subject: [PATCH 10/17] chore: make module create and list endpoint response structure simillar (#2524) --- apiserver/plane/api/views/module.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apiserver/plane/api/views/module.py b/apiserver/plane/api/views/module.py index 45c52c0bf..e5bda6b65 100644 --- a/apiserver/plane/api/views/module.py +++ b/apiserver/plane/api/views/module.py @@ -149,6 +149,9 @@ class ModuleViewSet(BaseViewSet): if serializer.is_valid(): serializer.save() + + module = Module.objects.get(pk=serializer.data["id"]) + serializer = ModuleSerializer(module) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) From 6bebb8a93beb65b40cb06c3f1b1a993bd8605856 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:32:42 +0530 Subject: [PATCH 11/17] chore: user issue display properties (#2258) * chore: user issue display properties * chore: added issue property * fix: migrations and url change * dev: add a default condition on get for issue properties --------- Co-authored-by: NarayanBavisetti --- apiserver/plane/api/urls/issue.py | 27 ++------ apiserver/plane/api/urls_deprecated.py | 25 ++----- apiserver/plane/api/views/__init__.py | 2 +- apiserver/plane/api/views/issue.py | 51 ++++---------- apiserver/plane/api/views/project.py | 67 ++++++++++++++++++- apiserver/plane/bgtasks/importer_task.py | 15 +++++ ..._alter_analyticview_created_by_and_more.py | 21 ++++++ apiserver/plane/db/models/issue.py | 35 ++++++++-- 8 files changed, 154 insertions(+), 89 deletions(-) create mode 100644 apiserver/plane/db/migrations/0046_alter_analyticview_created_by_and_more.py diff --git a/apiserver/plane/api/urls/issue.py b/apiserver/plane/api/urls/issue.py index b484fe113..f1ef7c176 100644 --- a/apiserver/plane/api/urls/issue.py +++ b/apiserver/plane/api/urls/issue.py @@ -17,7 +17,7 @@ from plane.api.views import ( IssueSubscriberViewSet, IssueReactionViewSet, CommentReactionViewSet, - IssuePropertyViewSet, + IssueUserDisplayPropertyEndpoint, IssueArchiveViewSet, IssueRelationViewSet, IssueDraftViewSet, @@ -235,28 +235,11 @@ urlpatterns = [ ## End Comment Reactions ## IssueProperty path( - "workspaces//projects//issue-properties/", - IssuePropertyViewSet.as_view( - { - "get": "list", - "post": "create", - } - ), - name="project-issue-roadmap", + "workspaces//projects//issue-display-properties/", + IssueUserDisplayPropertyEndpoint.as_view(), + name="project-issue-display-properties", ), - path( - "workspaces//projects//issue-properties//", - IssuePropertyViewSet.as_view( - { - "get": "retrieve", - "put": "update", - "patch": "partial_update", - "delete": "destroy", - } - ), - name="project-issue-roadmap", - ), - ## IssueProperty Ebd + ## IssueProperty End ## Issue Archives path( "workspaces//projects//archived-issues/", diff --git a/apiserver/plane/api/urls_deprecated.py b/apiserver/plane/api/urls_deprecated.py index 0dc1b3a08..c108257b3 100644 --- a/apiserver/plane/api/urls_deprecated.py +++ b/apiserver/plane/api/urls_deprecated.py @@ -82,7 +82,7 @@ from plane.api.views import ( BulkDeleteIssuesEndpoint, BulkImportIssuesEndpoint, ProjectUserViewsEndpoint, - IssuePropertyViewSet, + IssueUserDisplayPropertyEndpoint, LabelViewSet, SubIssuesEndpoint, IssueLinkViewSet, @@ -1008,26 +1008,9 @@ urlpatterns = [ ## End Comment Reactions ## IssueProperty path( - "workspaces//projects//issue-properties/", - IssuePropertyViewSet.as_view( - { - "get": "list", - "post": "create", - } - ), - name="project-issue-roadmap", - ), - path( - "workspaces//projects//issue-properties//", - IssuePropertyViewSet.as_view( - { - "get": "retrieve", - "put": "update", - "patch": "partial_update", - "delete": "destroy", - } - ), - name="project-issue-roadmap", + "workspaces//projects//issue-display-properties/", + IssueUserDisplayPropertyEndpoint.as_view(), + name="project-issue-display-properties", ), ## IssueProperty Ebd ## Issue Archives diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index 8a974f868..e17550050 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -71,7 +71,7 @@ from .issue import ( WorkSpaceIssuesEndpoint, IssueActivityEndpoint, IssueCommentViewSet, - IssuePropertyViewSet, + IssueUserDisplayPropertyEndpoint, LabelViewSet, BulkDeleteIssuesEndpoint, UserWorkSpaceIssues, diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index e4a2f68b8..361d31f86 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -606,41 +606,12 @@ class IssueCommentViewSet(BaseViewSet): return Response(status=status.HTTP_204_NO_CONTENT) -class IssuePropertyViewSet(BaseViewSet): - serializer_class = IssuePropertySerializer - model = IssueProperty +class IssueUserDisplayPropertyEndpoint(BaseAPIView): permission_classes = [ - ProjectEntityPermission, + ProjectLitePermission, ] - filterset_fields = [] - - def perform_create(self, serializer): - serializer.save( - project_id=self.kwargs.get("project_id"), user=self.request.user - ) - - def get_queryset(self): - return self.filter_queryset( - super() - .get_queryset() - .filter(workspace__slug=self.kwargs.get("slug")) - .filter(project_id=self.kwargs.get("project_id")) - .filter(user=self.request.user) - .filter(project__project_projectmember__member=self.request.user) - .select_related("project") - .select_related("workspace") - ) - - def list(self, request, slug, project_id): - queryset = self.get_queryset() - serializer = IssuePropertySerializer(queryset, many=True) - return Response( - serializer.data[0] if len(serializer.data) > 0 else [], - status=status.HTTP_200_OK, - ) - - def create(self, request, slug, project_id): + def post(self, request, slug, project_id): issue_property, created = IssueProperty.objects.get_or_create( user=request.user, project_id=project_id, @@ -649,16 +620,20 @@ class IssuePropertyViewSet(BaseViewSet): if not created: issue_property.properties = request.data.get("properties", {}) issue_property.save() - - serializer = IssuePropertySerializer(issue_property) - return Response(serializer.data, status=status.HTTP_200_OK) - issue_property.properties = request.data.get("properties", {}) issue_property.save() serializer = IssuePropertySerializer(issue_property) return Response(serializer.data, status=status.HTTP_201_CREATED) + def get(self, request, slug, project_id): + issue_property, _ = IssueProperty.objects.get_or_create( + user=request.user, project_id=project_id + ) + serializer = IssuePropertySerializer(issue_property) + return Response(serializer.data, status=status.HTTP_200_OK) + + class LabelViewSet(BaseViewSet): serializer_class = LabelSerializer model = Label @@ -972,8 +947,8 @@ class IssueAttachmentEndpoint(BaseAPIView): issue_attachments = IssueAttachment.objects.filter( issue_id=issue_id, workspace__slug=slug, project_id=project_id ) - serilaizer = IssueAttachmentSerializer(issue_attachments, many=True) - return Response(serilaizer.data, status=status.HTTP_200_OK) + serializer = IssueAttachmentSerializer(issue_attachments, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) class IssueArchiveViewSet(BaseViewSet): diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 1058ac593..1ab7e644c 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -69,6 +69,7 @@ from plane.db.models import ( ModuleMember, Inbox, ProjectDeployBoard, + IssueProperty, ) from plane.bgtasks.project_invitation_task import project_invitation @@ -201,6 +202,11 @@ class ProjectViewSet(BaseViewSet): project_member = ProjectMember.objects.create( project_id=serializer.data["id"], member=request.user, role=20 ) + # Also create the issue property for the user + _ = IssueProperty.objects.create( + project_id=serializer.data["id"], + user=request.user, + ) if serializer.data["project_lead"] is not None and str( serializer.data["project_lead"] @@ -210,6 +216,11 @@ class ProjectViewSet(BaseViewSet): member_id=serializer.data["project_lead"], role=20, ) + # Also create the issue property for the user + IssueProperty.objects.create( + project_id=serializer.data["id"], + user_id=serializer.data["project_lead"], + ) # Default states states = [ @@ -393,6 +404,8 @@ class InviteProjectEndpoint(BaseAPIView): member=user, project_id=project_id, role=role ) + _ = IssueProperty.objects.create(user=user, project_id=project_id) + return Response( ProjectMemberSerializer(project_member).data, status=status.HTTP_200_OK ) @@ -428,6 +441,18 @@ class UserProjectInvitationsViewset(BaseViewSet): ] ) + IssueProperty.objects.bulk_create( + [ + ProjectMember( + project=invitation.project, + workspace=invitation.project.workspace, + user=request.user, + created_by=request.user, + ) + for invitation in project_invitations + ] + ) + # Delete joined project invites project_invitations.delete() @@ -560,6 +585,7 @@ class AddMemberToProjectEndpoint(BaseAPIView): status=status.HTTP_400_BAD_REQUEST, ) bulk_project_members = [] + bulk_issue_props = [] project_members = ( ProjectMember.objects.filter( @@ -574,7 +600,8 @@ class AddMemberToProjectEndpoint(BaseAPIView): sort_order = [ project_member.get("sort_order") for project_member in project_members - if str(project_member.get("member_id")) == str(member.get("member_id")) + if str(project_member.get("member_id")) + == str(member.get("member_id")) ] bulk_project_members.append( ProjectMember( @@ -585,6 +612,13 @@ class AddMemberToProjectEndpoint(BaseAPIView): sort_order=sort_order[0] - 10000 if len(sort_order) else 65535, ) ) + bulk_issue_props.append( + IssueProperty( + user_id=member.get("member_id"), + project_id=project_id, + workspace_id=project.workspace_id, + ) + ) project_members = ProjectMember.objects.bulk_create( bulk_project_members, @@ -592,7 +626,12 @@ class AddMemberToProjectEndpoint(BaseAPIView): ignore_conflicts=True, ) + _ = IssueProperty.objects.bulk_create( + bulk_issue_props, batch_size=10, ignore_conflicts=True + ) + serializer = ProjectMemberSerializer(project_members, many=True) + return Response(serializer.data, status=status.HTTP_201_CREATED) @@ -614,6 +653,7 @@ class AddTeamToProjectEndpoint(BaseAPIView): workspace = Workspace.objects.get(slug=slug) project_members = [] + issue_props = [] for member in team_members: project_members.append( ProjectMember( @@ -623,11 +663,23 @@ class AddTeamToProjectEndpoint(BaseAPIView): created_by=request.user, ) ) + issue_props.append( + IssueProperty( + project_id=project_id, + user_id=member, + workspace=workspace, + created_by=request.user, + ) + ) ProjectMember.objects.bulk_create( project_members, batch_size=10, ignore_conflicts=True ) + _ = IssueProperty.objects.bulk_create( + issue_props, batch_size=10, ignore_conflicts=True + ) + serializer = ProjectMemberSerializer(project_members, many=True) return Response(serializer.data, status=status.HTTP_201_CREATED) @@ -743,6 +795,19 @@ class ProjectJoinEndpoint(BaseAPIView): ignore_conflicts=True, ) + IssueProperty.objects.bulk_create( + [ + IssueProperty( + project_id=project_id, + user=request.user, + workspace=workspace, + created_by=request.user, + ) + for project_id in project_ids + ], + ignore_conflicts=True, + ) + return Response( {"message": "Projects joined successfully"}, status=status.HTTP_201_CREATED, diff --git a/apiserver/plane/bgtasks/importer_task.py b/apiserver/plane/bgtasks/importer_task.py index 757ef601b..20dc65e51 100644 --- a/apiserver/plane/bgtasks/importer_task.py +++ b/apiserver/plane/bgtasks/importer_task.py @@ -25,6 +25,7 @@ from plane.db.models import ( WorkspaceIntegration, Label, User, + IssueProperty, ) from .workspace_invitation_task import workspace_invitation from plane.bgtasks.user_welcome_task import send_welcome_slack @@ -103,6 +104,20 @@ def service_importer(service, importer_id): ignore_conflicts=True, ) + IssueProperty.objects.bulk_create( + [ + IssueProperty( + project_id=importer.project_id, + workspace_id=importer.workspace_id, + user=user, + created_by=importer.created_by, + ) + for user in workspace_users + ], + batch_size=100, + ignore_conflicts=True, + ) + # Check if sync config is on for github importers if service == "github" and importer.config.get("sync", False): name = importer.metadata.get("name", False) diff --git a/apiserver/plane/db/migrations/0046_alter_analyticview_created_by_and_more.py b/apiserver/plane/db/migrations/0046_alter_analyticview_created_by_and_more.py new file mode 100644 index 000000000..4890ec9d5 --- /dev/null +++ b/apiserver/plane/db/migrations/0046_alter_analyticview_created_by_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.5 on 2023-10-18 12:04 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import plane.db.models.issue + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0045_issueactivity_epoch_workspacemember_issue_props_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='issueproperty', + name='properties', + field=models.JSONField(default=plane.db.models.issue.get_default_properties), + ), + ] diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index 3ba054d49..9ba73fd43 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -16,6 +16,24 @@ from . import ProjectBaseModel from plane.utils.html_processor import strip_tags +def get_default_properties(): + return { + "assignee": True, + "start_date": True, + "due_date": True, + "labels": True, + "key": True, + "priority": True, + "state": True, + "sub_issue_count": True, + "link": True, + "attachment_count": True, + "estimate": True, + "created_on": True, + "updated_on": True, + } + + # TODO: Handle identifiers for Bulk Inserts - nk class IssueManager(models.Manager): def get_queryset(self): @@ -39,7 +57,7 @@ class Issue(ProjectBaseModel): ("high", "High"), ("medium", "Medium"), ("low", "Low"), - ("none", "None") + ("none", "None"), ) parent = models.ForeignKey( "self", @@ -186,7 +204,7 @@ class IssueRelation(ProjectBaseModel): ("relates_to", "Relates To"), ("blocked_by", "Blocked By"), ) - + issue = models.ForeignKey( Issue, related_name="issue_relation", on_delete=models.CASCADE ) @@ -208,7 +226,7 @@ class IssueRelation(ProjectBaseModel): ordering = ("-created_at",) def __str__(self): - return f"{self.issue.name} {self.related_issue.name}" + return f"{self.issue.name} {self.related_issue.name}" class IssueAssignee(ProjectBaseModel): @@ -327,7 +345,9 @@ class IssueComment(ProjectBaseModel): comment_json = models.JSONField(blank=True, default=dict) comment_html = models.TextField(blank=True, default="

") attachments = ArrayField(models.URLField(), size=10, blank=True, default=list) - issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name="issue_comments") + issue = models.ForeignKey( + Issue, on_delete=models.CASCADE, related_name="issue_comments" + ) # System can also create comment actor = models.ForeignKey( settings.AUTH_USER_MODEL, @@ -367,7 +387,7 @@ class IssueProperty(ProjectBaseModel): on_delete=models.CASCADE, related_name="issue_property_user", ) - properties = models.JSONField(default=dict) + properties = models.JSONField(default=get_default_properties) class Meta: verbose_name = "Issue Property" @@ -515,7 +535,10 @@ class IssueVote(ProjectBaseModel): ) class Meta: - unique_together = ["issue", "actor",] + unique_together = [ + "issue", + "actor", + ] verbose_name = "Issue Vote" verbose_name_plural = "Issue Votes" db_table = "issue_votes" From 4e861101236a55b90796c9b6cd13df84870e0dff Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:34:01 +0530 Subject: [PATCH 12/17] chore: database configuration (#2497) --- apiserver/plane/settings/production.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/apiserver/plane/settings/production.py b/apiserver/plane/settings/production.py index 9c6bd95a9..541a0cfd4 100644 --- a/apiserver/plane/settings/production.py +++ b/apiserver/plane/settings/production.py @@ -14,19 +14,21 @@ from .common import * # noqa # Database DEBUG = int(os.environ.get("DEBUG", 0)) == 1 -DATABASES = { - "default": { - "ENGINE": "django.db.backends.postgresql", - "NAME": "plane", - "USER": os.environ.get("PGUSER", ""), - "PASSWORD": os.environ.get("PGPASSWORD", ""), - "HOST": os.environ.get("PGHOST", ""), +if bool(os.environ.get("DATABASE_URL")): + # Parse database configuration from $DATABASE_URL + DATABASES["default"] = dj_database_url.config() +else: + DATABASES = { + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": os.environ.get("POSTGRES_DB"), + "USER": os.environ.get("POSTGRES_USER"), + "PASSWORD": os.environ.get("POSTGRES_PASSWORD"), + "HOST": os.environ.get("POSTGRES_HOST"), + } } -} -# Parse database configuration from $DATABASE_URL -DATABASES["default"] = dj_database_url.config() SITE_ID = 1 # Set the variable true if running in docker environment @@ -278,4 +280,3 @@ SCOUT_NAME = "Plane" # Unsplash Access key UNSPLASH_ACCESS_KEY = os.environ.get("UNSPLASH_ACCESS_KEY") - From 3e706f9653a8ede7ece7a54af95b388c5bedd6a1 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:35:15 +0530 Subject: [PATCH 13/17] chore: project create/update endpoint to be simillar to list (#2476) * chore: project create endpoint to be simillar to list * dev: make project create and update response same --- apiserver/plane/api/views/project.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 1ab7e644c..632a5bf53 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -273,12 +273,9 @@ class ProjectViewSet(BaseViewSet): ] ) - data = serializer.data - # Additional fields of the member - data["sort_order"] = project_member.sort_order - data["member_role"] = project_member.role - data["is_member"] = True - return Response(data, status=status.HTTP_201_CREATED) + project = self.get_queryset().filter(pk=serializer.data["id"]).first() + serializer = ProjectListSerializer(project) + return Response(serializer.data, status=status.HTTP_201_CREATED) return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST, @@ -328,6 +325,8 @@ class ProjectViewSet(BaseViewSet): color="#ff7700", ) + project = self.get_queryset().filter(pk=serializer.data["id"]).first() + serializer = ProjectListSerializer(project) return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) From b0a24ab57b0aeb8b351303148c43224c7cbeb1d6 Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:36:27 +0530 Subject: [PATCH 14/17] fix: issue filters validation (#2417) --- apiserver/plane/utils/issue_filters.py | 73 +++++++++++++++++--------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/apiserver/plane/utils/issue_filters.py b/apiserver/plane/utils/issue_filters.py index 0b8f39e14..52c181622 100644 --- a/apiserver/plane/utils/issue_filters.py +++ b/apiserver/plane/utils/issue_filters.py @@ -1,10 +1,24 @@ import re +import uuid from datetime import timedelta from django.utils import timezone + # The date from pattern pattern = re.compile(r"\d+_(weeks|months)$") +# check the valid uuids +def filter_valid_uuids(uuid_list): + valid_uuids = [] + for uuid_str in uuid_list: + try: + uuid_obj = uuid.UUID(uuid_str) + valid_uuids.append(uuid_obj) + except ValueError: + # ignore the invalid uuids + pass + return valid_uuids + # Get the 2_weeks, 3_months def string_date_filter(filter, duration, subsequent, term, date_filter, offset): @@ -61,40 +75,41 @@ def date_filter(filter, date_term, queries): def filter_state(params, filter, method): if method == "GET": - states = params.get("state").split(",") + states = [item for item in params.get("state").split(",") if item != 'null'] + states = filter_valid_uuids(states) if len(states) and "" not in states: filter["state__in"] = states else: - if params.get("state", None) and len(params.get("state")): + if params.get("state", None) and len(params.get("state")) and params.get("state") != 'null': filter["state__in"] = params.get("state") return filter def filter_state_group(params, filter, method): if method == "GET": - state_group = params.get("state_group").split(",") + state_group = [item for item in params.get("state_group").split(",") if item != 'null'] if len(state_group) and "" not in state_group: filter["state__group__in"] = state_group else: - if params.get("state_group", None) and len(params.get("state_group")): + if params.get("state_group", None) and len(params.get("state_group")) and params.get("state_group") != 'null': filter["state__group__in"] = params.get("state_group") return filter def filter_estimate_point(params, filter, method): if method == "GET": - estimate_points = params.get("estimate_point").split(",") + estimate_points = [item for item in params.get("estimate_point").split(",") if item != 'null'] if len(estimate_points) and "" not in estimate_points: filter["estimate_point__in"] = estimate_points else: - if params.get("estimate_point", None) and len(params.get("estimate_point")): + if params.get("estimate_point", None) and len(params.get("estimate_point")) and params.get("estimate_point") != 'null': filter["estimate_point__in"] = params.get("estimate_point") return filter def filter_priority(params, filter, method): if method == "GET": - priorities = params.get("priority").split(",") + priorities = [item for item in params.get("priority").split(",") if item != 'null'] if len(priorities) and "" not in priorities: filter["priority__in"] = priorities return filter @@ -102,44 +117,48 @@ def filter_priority(params, filter, method): def filter_parent(params, filter, method): if method == "GET": - parents = params.get("parent").split(",") + parents = [item for item in params.get("parent").split(",") if item != 'null'] + parents = filter_valid_uuids(parents) if len(parents) and "" not in parents: filter["parent__in"] = parents else: - if params.get("parent", None) and len(params.get("parent")): + if params.get("parent", None) and len(params.get("parent")) and params.get("parent") != 'null': filter["parent__in"] = params.get("parent") return filter def filter_labels(params, filter, method): if method == "GET": - labels = params.get("labels").split(",") + labels = [item for item in params.get("labels").split(",") if item != 'null'] + labels = filter_valid_uuids(labels) if len(labels) and "" not in labels: filter["labels__in"] = labels else: - if params.get("labels", None) and len(params.get("labels")): + if params.get("labels", None) and len(params.get("labels")) and params.get("labels") != 'null': filter["labels__in"] = params.get("labels") return filter def filter_assignees(params, filter, method): if method == "GET": - assignees = params.get("assignees").split(",") + assignees = [item for item in params.get("assignees").split(",") if item != 'null'] + assignees = filter_valid_uuids(assignees) if len(assignees) and "" not in assignees: filter["assignees__in"] = assignees else: - if params.get("assignees", None) and len(params.get("assignees")): + if params.get("assignees", None) and len(params.get("assignees")) and params.get("assignees") != 'null': filter["assignees__in"] = params.get("assignees") return filter def filter_created_by(params, filter, method): if method == "GET": - created_bys = params.get("created_by").split(",") + created_bys = [item for item in params.get("created_by").split(",") if item != 'null'] + created_bys = filter_valid_uuids(created_bys) if len(created_bys) and "" not in created_bys: filter["created_by__in"] = created_bys else: - if params.get("created_by", None) and len(params.get("created_by")): + if params.get("created_by", None) and len(params.get("created_by")) and params.get("created_by") != 'null': filter["created_by__in"] = params.get("created_by") return filter @@ -219,44 +238,47 @@ def filter_issue_state_type(params, filter, method): def filter_project(params, filter, method): if method == "GET": - projects = params.get("project").split(",") + projects = [item for item in params.get("project").split(",") if item != 'null'] + projects = filter_valid_uuids(projects) if len(projects) and "" not in projects: filter["project__in"] = projects else: - if params.get("project", None) and len(params.get("project")): + if params.get("project", None) and len(params.get("project")) and params.get("project") != 'null': filter["project__in"] = params.get("project") return filter def filter_cycle(params, filter, method): if method == "GET": - cycles = params.get("cycle").split(",") + cycles = [item for item in params.get("cycle").split(",") if item != 'null'] + cycles = filter_valid_uuids(cycles) if len(cycles) and "" not in cycles: filter["issue_cycle__cycle_id__in"] = cycles else: - if params.get("cycle", None) and len(params.get("cycle")): + if params.get("cycle", None) and len(params.get("cycle")) and params.get("cycle") != 'null': filter["issue_cycle__cycle_id__in"] = params.get("cycle") return filter def filter_module(params, filter, method): if method == "GET": - modules = params.get("module").split(",") + modules = [item for item in params.get("module").split(",") if item != 'null'] + modules = filter_valid_uuids(modules) if len(modules) and "" not in modules: filter["issue_module__module_id__in"] = modules else: - if params.get("module", None) and len(params.get("module")): + if params.get("module", None) and len(params.get("module")) and params.get("module") != 'null': filter["issue_module__module_id__in"] = params.get("module") return filter def filter_inbox_status(params, filter, method): if method == "GET": - status = params.get("inbox_status").split(",") + status = [item for item in params.get("inbox_status").split(",") if item != 'null'] if len(status) and "" not in status: filter["issue_inbox__status__in"] = status else: - if params.get("inbox_status", None) and len(params.get("inbox_status")): + if params.get("inbox_status", None) and len(params.get("inbox_status")) and params.get("inbox_status") != 'null': filter["issue_inbox__status__in"] = params.get("inbox_status") return filter @@ -275,11 +297,12 @@ def filter_sub_issue_toggle(params, filter, method): def filter_subscribed_issues(params, filter, method): if method == "GET": - subscribers = params.get("subscriber").split(",") + subscribers = [item for item in params.get("subscriber").split(",") if item != 'null'] + subscribers = filter_valid_uuids(subscribers) if len(subscribers) and "" not in subscribers: filter["issue_subscribers__subscriber_id__in"] = subscribers else: - if params.get("subscriber", None) and len(params.get("subscriber")): + if params.get("subscriber", None) and len(params.get("subscriber")) and params.get("subscriber") != 'null': filter["issue_subscribers__subscriber_id__in"] = params.get("subscriber") return filter From 9ee3fb9c6cae50b8bec98c64a9bcd876af6bf75a Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:37:26 +0530 Subject: [PATCH 15/17] chore: removed duplicate issues (#2418) --- apiserver/plane/api/views/issue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 361d31f86..56b79ea34 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -130,7 +130,7 @@ class IssueViewSet(BaseViewSet): queryset=IssueReaction.objects.select_related("actor"), ) ) - ) + ).distinct() @method_decorator(gzip_page) def list(self, request, slug, project_id): From 080b5a29ae7bb4478f4204f4791ea65530090a6f Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:38:54 +0530 Subject: [PATCH 16/17] refactor: issue activity (#2503) * dev: update project and workspace save in issue activity * chore: issue activity structuring * chore: added workspace id --------- Co-authored-by: pablohashescobar --- .../plane/bgtasks/issue_activites_task.py | 1242 +++++++++-------- apiserver/plane/bgtasks/notification_task.py | 102 ++ 2 files changed, 783 insertions(+), 561 deletions(-) create mode 100644 apiserver/plane/bgtasks/notification_task.py diff --git a/apiserver/plane/bgtasks/issue_activites_task.py b/apiserver/plane/bgtasks/issue_activites_task.py index 1ad54e3a8..1dbaf8bc9 100644 --- a/apiserver/plane/bgtasks/issue_activites_task.py +++ b/apiserver/plane/bgtasks/issue_activites_task.py @@ -29,117 +29,32 @@ from plane.db.models import ( IssueComment, ) from plane.api.serializers import IssueActivitySerializer +from plane.bgtasks.notification_task import notifications -# Track Chnages in name +# Track Changes in name def track_name( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): if current_instance.get("name") != requested_data.get("name"): issue_activities.append( IssueActivity( issue_id=issue_id, - actor=actor, + actor_id=actor_id, verb="updated", old_value=current_instance.get("name"), new_value=requested_data.get("name"), field="name", - project=project, - workspace=project.workspace, - comment=f"updated the name to {requested_data.get('name')}", - epoch=epoch, - ) - ) - - -# Track changes in parent issue -def track_parent( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch -): - if current_instance.get("parent") != requested_data.get("parent"): - if requested_data.get("parent") == None: - old_parent = Issue.objects.get(pk=current_instance.get("parent")) - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=f"{old_parent.project.identifier}-{old_parent.sequence_id}", - new_value=None, - field="parent", - project=project, - workspace=project.workspace, - comment=f"updated the parent issue to None", - old_identifier=old_parent.id, - new_identifier=None, - epoch=epoch, - ) - ) - else: - new_parent = Issue.objects.get(pk=requested_data.get("parent")) - old_parent = Issue.objects.filter(pk=current_instance.get("parent")).first() - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=f"{old_parent.project.identifier}-{old_parent.sequence_id}" - if old_parent is not None - else None, - new_value=f"{new_parent.project.identifier}-{new_parent.sequence_id}", - field="parent", - project=project, - workspace=project.workspace, - comment=f"updated the parent issue to {new_parent.name}", - old_identifier=old_parent.id if old_parent is not None else None, - new_identifier=new_parent.id, - epoch=epoch, - ) - ) - - -# Track changes in priority -def track_priority( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch -): - if current_instance.get("priority") != requested_data.get("priority"): - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=current_instance.get("priority"), - new_value=requested_data.get("priority"), - field="priority", - project=project, - workspace=project.workspace, - comment=f"updated the priority to {requested_data.get('priority')}", - epoch=epoch, - ) - ) - - -# Track chnages in state of the issue -def track_state( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch -): - if current_instance.get("state") != requested_data.get("state"): - new_state = State.objects.get(pk=requested_data.get("state", None)) - old_state = State.objects.get(pk=current_instance.get("state", None)) - - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=old_state.name, - new_value=new_state.name, - field="state", - project=project, - workspace=project.workspace, - comment=f"updated the state to {new_state.name}", - old_identifier=old_state.id, - new_identifier=new_state.id, + project_id=project_id, + workspace_id=workspace_id, + comment=f"updated the name to", epoch=epoch, ) ) @@ -147,7 +62,14 @@ def track_state( # Track issue description def track_description( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): if current_instance.get("description_html") != requested_data.get( "description_html" @@ -160,7 +82,7 @@ def track_description( if ( last_activity is not None and last_activity.field == "description" - and actor.id == last_activity.actor_id + and actor_id == last_activity.actor_id ): last_activity.created_at = timezone.now() last_activity.save(update_fields=["created_at"]) @@ -168,257 +90,343 @@ def track_description( issue_activities.append( IssueActivity( issue_id=issue_id, - actor=actor, + actor_id=actor_id, verb="updated", old_value=current_instance.get("description_html"), new_value=requested_data.get("description_html"), field="description", - project=project, - workspace=project.workspace, - comment=f"updated the description to {requested_data.get('description_html')}", + project_id=project_id, + workspace_id=workspace_id, + comment=f"updated the description to", epoch=epoch, ) ) +# Track changes in parent issue +def track_parent( + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, +): + if current_instance.get("parent") != requested_data.get("parent"): + old_parent = Issue.objects.filter(pk=current_instance.get("parent")).first() + new_parent = Issue.objects.filter(pk=requested_data.get("parent")).first() + + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + verb="updated", + old_value=f"{old_parent.project.identifier}-{old_parent.sequence_id}" + if old_parent is not None + else "", + new_value=f"{new_parent.project.identifier}-{new_parent.sequence_id}" + if new_parent is not None + else "", + field="parent", + project_id=project_id, + workspace=workspace_id, + comment=f"updated the parent issue to", + old_identifier=old_parent.id if old_parent is not None else None, + new_identifier=new_parent.id if new_parent is not None else None, + epoch=epoch, + ) + ) + + +# Track changes in priority +def track_priority( + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, +): + if current_instance.get("priority") != requested_data.get("priority"): + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + verb="updated", + old_value=current_instance.get("priority"), + new_value=requested_data.get("priority"), + field="priority", + project_id=project_id, + workspace_id=workspace_id, + comment=f"updated the priority to", + epoch=epoch, + ) + ) + + +# Track changes in state of the issue +def track_state( + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, +): + if current_instance.get("state") != requested_data.get("state"): + new_state = State.objects.get(pk=requested_data.get("state", None)) + old_state = State.objects.get(pk=current_instance.get("state", None)) + + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + verb="updated", + old_value=old_state.name, + new_value=new_state.name, + field="state", + project_id=project_id, + workspace_id=workspace_id, + comment=f"updated the state to", + old_identifier=old_state.id, + new_identifier=new_state.id, + epoch=epoch, + ) + ) + + # Track changes in issue target date def track_target_date( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): if current_instance.get("target_date") != requested_data.get("target_date"): - if requested_data.get("target_date") == None: - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=current_instance.get("target_date"), - new_value=requested_data.get("target_date"), - field="target_date", - project=project, - workspace=project.workspace, - comment=f"updated the target date to None", - epoch=epoch, - ) - ) - else: - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=current_instance.get("target_date"), - new_value=requested_data.get("target_date"), - field="target_date", - project=project, - workspace=project.workspace, - comment=f"updated the target date to {requested_data.get('target_date')}", - epoch=epoch, - ) + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + verb="updated", + old_value=current_instance.get("target_date") + if current_instance.get("target_date") is not None + else "", + new_value=requested_data.get("target_date") + if requested_data.get("target_date") is not None + else "", + field="target_date", + project_id=project_id, + workspace_id=workspace_id, + comment=f"updated the target date to", + epoch=epoch, ) + ) # Track changes in issue start date def track_start_date( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): if current_instance.get("start_date") != requested_data.get("start_date"): - if requested_data.get("start_date") == None: - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=current_instance.get("start_date"), - new_value=requested_data.get("start_date"), - field="start_date", - project=project, - workspace=project.workspace, - comment=f"updated the start date to None", - epoch=epoch, - ) - ) - else: - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=current_instance.get("start_date"), - new_value=requested_data.get("start_date"), - field="start_date", - project=project, - workspace=project.workspace, - comment=f"updated the start date to {requested_data.get('start_date')}", - epoch=epoch, - ) + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + verb="updated", + old_value=current_instance.get("start_date") + if current_instance.get("start_date") is not None + else "", + new_value=requested_data.get("start_date") + if requested_data.get("start_date") is not None + else "", + field="start_date", + project_id=project_id, + workspace_id=workspace_id, + comment=f"updated the start date to ", + epoch=epoch, ) + ) # Track changes in issue labels def track_labels( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): - # Label Addition - if len(requested_data.get("labels_list")) > len(current_instance.get("labels")): - for label in requested_data.get("labels_list"): - if label not in current_instance.get("labels"): - label = Label.objects.get(pk=label) - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value="", - new_value=label.name, - field="labels", - project=project, - workspace=project.workspace, - comment=f"added label {label.name}", - new_identifier=label.id, - old_identifier=None, - epoch=epoch, - ) - ) + requested_labels = set([str(lab) for lab in requested_data.get("labels_list", [])]) + current_labels = set([str(lab) for lab in current_instance.get("labels", [])]) - # Label Removal - if len(requested_data.get("labels_list")) < len(current_instance.get("labels")): - for label in current_instance.get("labels"): - if label not in requested_data.get("labels_list"): - label = Label.objects.get(pk=label) - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=label.name, - new_value="", - field="labels", - project=project, - workspace=project.workspace, - comment=f"removed label {label.name}", - old_identifier=label.id, - new_identifier=None, - epoch=epoch, - ) - ) + added_labels = requested_labels - current_labels + dropped_labels = current_labels - requested_labels + + # Set of newly added labels + for added_label in added_labels: + label = Label.objects.get(pk=added_label) + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + project_id=project_id, + workspace_id=workspace_id, + verb="updated", + field="labels", + comment="added label ", + old_value="", + new_value=label.name, + new_identifier=label.id, + old_identifier=None, + epoch=epoch, + ) + ) + + # Set of dropped labels + for dropped_label in dropped_labels: + label = Label.objects.get(pk=dropped_label) + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + verb="updated", + old_value=label.name, + new_value="", + field="labels", + project_id=project_id, + workspace_id=workspace_id, + comment=f"removed label ", + old_identifier=label.id, + new_identifier=None, + epoch=epoch, + ) + ) # Track changes in issue assignees def track_assignees( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): - # Assignee Addition - if len(requested_data.get("assignees_list")) > len( - current_instance.get("assignees") - ): - for assignee in requested_data.get("assignees_list"): - if assignee not in current_instance.get("assignees"): - assignee = User.objects.get(pk=assignee) - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value="", - new_value=assignee.display_name, - field="assignees", - project=project, - workspace=project.workspace, - comment=f"added assignee {assignee.display_name}", - new_identifier=assignee.id, - epoch=epoch, - ) - ) + requested_assignees = set( + [str(asg) for asg in requested_data.get("assignees_list", [])] + ) + current_assignees = set([str(asg) for asg in current_instance.get("assignees", [])]) - # Assignee Removal - if len(requested_data.get("assignees_list")) < len( - current_instance.get("assignees") - ): - for assignee in current_instance.get("assignees"): - if assignee not in requested_data.get("assignees_list"): - assignee = User.objects.get(pk=assignee) - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=assignee.display_name, - new_value="", - field="assignees", - project=project, - workspace=project.workspace, - comment=f"removed assignee {assignee.display_name}", - old_identifier=assignee.id, - epoch=epoch, - ) - ) + added_assignees = requested_assignees - current_assignees + dropped_assginees = current_assignees - requested_assignees + for added_asignee in added_assignees: + assignee = User.objects.get(pk=added_asignee) + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + verb="updated", + old_value="", + new_value=assignee.display_name, + field="assignees", + project_id=project_id, + workspace_id=workspace_id, + comment=f"added assignee ", + new_identifier=assignee.id, + epoch=epoch, + ) + ) -def create_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch -): - issue_activities.append( - IssueActivity( + for dropped_assignee in dropped_assginees: + assignee = User.objects.get(pk=dropped_assignee) + issue_activities.append( issue_id=issue_id, - project=project, - workspace=project.workspace, - comment=f"created the issue", - verb="created", - actor=actor, + actor_id=actor_id, + verb="updated", + old_value=assignee.display_name, + new_value="", + field="assignees", + project_id=project_id, + workspace_id=workspace_id, + comment=f"removed assignee ", + old_identifier=assignee.id, epoch=epoch, ) - ) def track_estimate_points( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): if current_instance.get("estimate_point") != requested_data.get("estimate_point"): - if requested_data.get("estimate_point") == None: - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=current_instance.get("estimate_point"), - new_value=requested_data.get("estimate_point"), - field="estimate_point", - project=project, - workspace=project.workspace, - comment=f"updated the estimate point to None", - epoch=epoch, - ) - ) - else: - issue_activities.append( - IssueActivity( - issue_id=issue_id, - actor=actor, - verb="updated", - old_value=current_instance.get("estimate_point"), - new_value=requested_data.get("estimate_point"), - field="estimate_point", - project=project, - workspace=project.workspace, - comment=f"updated the estimate point to {requested_data.get('estimate_point')}", - epoch=epoch, - ) + issue_activities.append( + IssueActivity( + issue_id=issue_id, + actor_id=actor_id, + verb="updated", + old_value=current_instance.get("estimate_point") + if current_instance.get("estimate_point") is not None + else "", + new_value=requested_data.get("estimate_point") + if requested_data.get("estimate_point") is not None + else "", + field="estimate_point", + project_id=project_id, + workspace_id=workspace_id, + comment=f"updated the estimate point to ", + epoch=epoch, ) + ) def track_archive_at( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): if requested_data.get("archived_at") is None: issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"has restored the issue", verb="updated", - actor=actor, + actor_id=actor_id, field="archived_at", old_value="archive", new_value="restore", @@ -429,11 +437,11 @@ def track_archive_at( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"Plane has archived the issue", verb="updated", - actor=actor, + actor_id=actor_id, field="archived_at", old_value=None, new_value="archive", @@ -443,24 +451,30 @@ def track_archive_at( def track_closed_to( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): if requested_data.get("closed_to") is not None: updated_state = State.objects.get( - pk=requested_data.get("closed_to"), project=project + pk=requested_data.get("closed_to"), project_id=project_id ) - issue_activities.append( IssueActivity( issue_id=issue_id, - actor=actor, + actor_id=actor_id, verb="updated", old_value=None, new_value=updated_state.name, field="state", - project=project, - workspace=project.workspace, - comment=f"Plane updated the state to {updated_state.name}", + project_id=project_id, + workspace_id=workspace_id, + comment=f"Plane updated the state to ", old_identifier=None, new_identifier=updated_state.id, epoch=epoch, @@ -468,8 +482,38 @@ def track_closed_to( ) +def create_issue_activity( + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, +): + issue_activities.append( + IssueActivity( + issue_id=issue_id, + project_id=project_id, + workspace_id=workspace_id, + comment=f"created the issue", + verb="created", + actor_id=actor_id, + epoch=epoch, + ) + ) + + def update_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): ISSUE_ACTIVITY_MAPPER = { "name": track_name, @@ -495,26 +539,34 @@ def update_issue_activity( func = ISSUE_ACTIVITY_MAPPER.get(key, None) if func is not None: func( - requested_data, - current_instance, - issue_id, - project, - actor, - issue_activities, - epoch, + requested_data=requested_data, + current_instance=current_instance, + issue_id=issue_id, + project_id=project_id, + workspace_id=workspace_id, + actor_id=actor_id, + issue_activities=issue_activities, + epoch=epoch, ) def delete_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): issue_activities.append( IssueActivity( - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"deleted the issue", verb="deleted", - actor=actor, + actor_id=actor_id, field="issue", epoch=epoch, ) @@ -522,7 +574,14 @@ def delete_issue_activity( def create_comment_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -532,11 +591,11 @@ def create_comment_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"created a comment", verb="created", - actor=actor, + actor_id=actor_id, field="comment", new_value=requested_data.get("comment_html", ""), new_identifier=requested_data.get("id", None), @@ -547,7 +606,14 @@ def create_comment_activity( def update_comment_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -558,11 +624,11 @@ def update_comment_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"updated a comment", verb="updated", - actor=actor, + actor_id=actor_id, field="comment", old_value=current_instance.get("comment_html", ""), old_identifier=current_instance.get("id"), @@ -575,16 +641,23 @@ def update_comment_activity( def delete_comment_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"deleted the comment", verb="deleted", - actor=actor, + actor_id=actor_id, field="comment", epoch=epoch, ) @@ -592,7 +665,14 @@ def delete_comment_activity( def create_cycle_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -614,13 +694,13 @@ def create_cycle_issue_activity( issue_activities.append( IssueActivity( issue_id=updated_record.get("issue_id"), - actor=actor, + actor_id=actor_id, verb="updated", old_value=old_cycle.name, new_value=new_cycle.name, field="cycles", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"updated cycle from {old_cycle.name} to {new_cycle.name}", old_identifier=old_cycle.id, new_identifier=new_cycle.id, @@ -636,13 +716,13 @@ def create_cycle_issue_activity( issue_activities.append( IssueActivity( issue_id=created_record.get("fields").get("issue"), - actor=actor, + actor_id=actor_id, verb="created", old_value="", new_value=cycle.name, field="cycles", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"added cycle {cycle.name}", new_identifier=cycle.id, epoch=epoch, @@ -651,7 +731,14 @@ def create_cycle_issue_activity( def delete_cycle_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -666,13 +753,13 @@ def delete_cycle_issue_activity( issue_activities.append( IssueActivity( issue_id=issue, - actor=actor, + actor_id=actor_id, verb="deleted", old_value=cycle.name if cycle is not None else "", new_value="", field="cycles", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"removed this issue from {cycle.name if cycle is not None else None}", old_identifier=cycle.id if cycle is not None else None, epoch=epoch, @@ -681,7 +768,14 @@ def delete_cycle_issue_activity( def create_module_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -703,14 +797,14 @@ def create_module_issue_activity( issue_activities.append( IssueActivity( issue_id=updated_record.get("issue_id"), - actor=actor, + actor_id=actor_id, verb="updated", old_value=old_module.name, new_value=new_module.name, field="modules", - project=project, - workspace=project.workspace, - comment=f"updated module from {old_module.name} to {new_module.name}", + project_id=project_id, + workspace_id=workspace_id, + comment=f"updated module to ", old_identifier=old_module.id, new_identifier=new_module.id, epoch=epoch, @@ -724,13 +818,13 @@ def create_module_issue_activity( issue_activities.append( IssueActivity( issue_id=created_record.get("fields").get("issue"), - actor=actor, + actor_id=actor_id, verb="created", old_value="", new_value=module.name, field="modules", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"added module {module.name}", new_identifier=module.id, epoch=epoch, @@ -739,7 +833,14 @@ def create_module_issue_activity( def delete_module_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -754,14 +855,14 @@ def delete_module_issue_activity( issue_activities.append( IssueActivity( issue_id=issue, - actor=actor, + actor_id=actor_id, verb="deleted", old_value=module.name if module is not None else "", new_value="", field="modules", - project=project, - workspace=project.workspace, - comment=f"removed this issue from {module.name if module is not None else None}", + project_id=project_id, + workspace_id=workspace_id, + comment=f"removed this issue from ", old_identifier=module.id if module is not None else None, epoch=epoch, ) @@ -769,7 +870,14 @@ def delete_module_issue_activity( def create_link_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + actor_id, + workspace_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -779,11 +887,11 @@ def create_link_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"created a link", verb="created", - actor=actor, + actor_id=actor_id, field="link", new_value=requested_data.get("url", ""), new_identifier=requested_data.get("id", None), @@ -793,7 +901,14 @@ def create_link_activity( def update_link_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -804,11 +919,11 @@ def update_link_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"updated a link", verb="updated", - actor=actor, + actor_id=actor_id, field="link", old_value=current_instance.get("url", ""), old_identifier=current_instance.get("id"), @@ -820,7 +935,14 @@ def update_link_activity( def delete_link_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): current_instance = ( json.loads(current_instance) if current_instance is not None else None @@ -829,11 +951,11 @@ def delete_link_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"deleted the link", verb="deleted", - actor=actor, + actor_id=actor_id, field="link", old_value=current_instance.get("url", ""), new_value="", @@ -843,7 +965,14 @@ def delete_link_activity( def create_attachment_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + actor_id, + workspace_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -853,11 +982,11 @@ def create_attachment_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"created an attachment", verb="created", - actor=actor, + actor_id=actor_id, field="attachment", new_value=current_instance.get("asset", ""), new_identifier=current_instance.get("id", None), @@ -867,16 +996,23 @@ def create_attachment_activity( def delete_attachment_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"deleted the attachment", verb="deleted", - actor=actor, + actor_id=actor_id, field="attachment", epoch=epoch, ) @@ -884,13 +1020,22 @@ def delete_attachment_activity( def create_issue_reaction_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None if requested_data and requested_data.get("reaction") is not None: issue_reaction = ( IssueReaction.objects.filter( - reaction=requested_data.get("reaction"), project=project, actor=actor + reaction=requested_data.get("reaction"), + project_id=project_id, + actor_id=actor_id, ) .values_list("id", flat=True) .first() @@ -899,13 +1044,13 @@ def create_issue_reaction_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - actor=actor, + actor_id=actor_id, verb="created", old_value=None, new_value=requested_data.get("reaction"), field="reaction", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment="added the reaction", old_identifier=None, new_identifier=issue_reaction, @@ -915,7 +1060,14 @@ def create_issue_reaction_activity( def delete_issue_reaction_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): current_instance = ( json.loads(current_instance) if current_instance is not None else None @@ -924,13 +1076,13 @@ def delete_issue_reaction_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - actor=actor, + actor_id=actor_id, verb="deleted", old_value=current_instance.get("reaction"), new_value=None, field="reaction", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment="removed the reaction", old_identifier=current_instance.get("identifier"), new_identifier=None, @@ -940,18 +1092,27 @@ def delete_issue_reaction_activity( def create_comment_reaction_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None if requested_data and requested_data.get("reaction") is not None: comment_reaction_id, comment_id = ( CommentReaction.objects.filter( - reaction=requested_data.get("reaction"), project=project, actor=actor + reaction=requested_data.get("reaction"), + project_id=project_id, + actor_id=actor_id, ) .values_list("id", "comment__id") .first() ) - comment = IssueComment.objects.get(pk=comment_id, project=project) + comment = IssueComment.objects.get(pk=comment_id, project_id=project_id) if ( comment is not None and comment_reaction_id is not None @@ -960,13 +1121,13 @@ def create_comment_reaction_activity( issue_activities.append( IssueActivity( issue_id=comment.issue_id, - actor=actor, + actor_id=actor_id, verb="created", old_value=None, new_value=requested_data.get("reaction"), field="reaction", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment="added the reaction", old_identifier=None, new_identifier=comment_reaction_id, @@ -976,7 +1137,14 @@ def create_comment_reaction_activity( def delete_comment_reaction_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): current_instance = ( json.loads(current_instance) if current_instance is not None else None @@ -984,7 +1152,7 @@ def delete_comment_reaction_activity( if current_instance and current_instance.get("reaction") is not None: issue_id = ( IssueComment.objects.filter( - pk=current_instance.get("comment_id"), project=project + pk=current_instance.get("comment_id"), project_id=project_id ) .values_list("issue_id", flat=True) .first() @@ -993,13 +1161,13 @@ def delete_comment_reaction_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - actor=actor, + actor_id=actor_id, verb="deleted", old_value=current_instance.get("reaction"), new_value=None, field="reaction", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment="removed the reaction", old_identifier=current_instance.get("identifier"), new_identifier=None, @@ -1009,20 +1177,27 @@ def delete_comment_reaction_activity( def create_issue_vote_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None if requested_data and requested_data.get("vote") is not None: issue_activities.append( IssueActivity( issue_id=issue_id, - actor=actor, + actor_id=actor_id, verb="created", old_value=None, new_value=requested_data.get("vote"), field="vote", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment="added the vote", old_identifier=None, new_identifier=None, @@ -1032,7 +1207,14 @@ def create_issue_vote_activity( def delete_issue_vote_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): current_instance = ( json.loads(current_instance) if current_instance is not None else None @@ -1041,13 +1223,13 @@ def delete_issue_vote_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - actor=actor, + actor_id=actor_id, verb="deleted", old_value=current_instance.get("vote"), new_value=None, field="vote", - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment="removed the vote", old_identifier=current_instance.get("identifier"), new_identifier=None, @@ -1057,7 +1239,14 @@ def delete_issue_vote_activity( def create_issue_relation_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -1073,13 +1262,13 @@ def create_issue_relation_activity( issue_activities.append( IssueActivity( issue_id=issue_relation.get("related_issue"), - actor=actor, + actor_id=actor_id, verb="created", old_value="", - new_value=f"{project.identifier}-{issue.sequence_id}", + new_value=f"{issue.project.identifier}-{issue.sequence_id}", field=relation_type, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"added {relation_type} relation", old_identifier=issue_relation.get("issue"), ) @@ -1088,13 +1277,13 @@ def create_issue_relation_activity( issue_activities.append( IssueActivity( issue_id=issue_relation.get("issue"), - actor=actor, + actor_id=actor_id, verb="created", old_value="", - new_value=f"{project.identifier}-{issue.sequence_id}", + new_value=f"{issue.project.identifier}-{issue.sequence_id}", field=f'{issue_relation.get("relation_type")}', - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f'added {issue_relation.get("relation_type")} relation', old_identifier=issue_relation.get("related_issue"), epoch=epoch, @@ -1103,7 +1292,14 @@ def create_issue_relation_activity( def delete_issue_relation_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -1118,13 +1314,13 @@ def delete_issue_relation_activity( issue_activities.append( IssueActivity( issue_id=current_instance.get("related_issue"), - actor=actor, + actor_id=actor_id, verb="deleted", - old_value=f"{project.identifier}-{issue.sequence_id}", + old_value=f"{issue.project.identifier}-{issue.sequence_id}", new_value="", field=relation_type, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"deleted {relation_type} relation", old_identifier=current_instance.get("issue"), epoch=epoch, @@ -1134,13 +1330,13 @@ def delete_issue_relation_activity( issue_activities.append( IssueActivity( issue_id=current_instance.get("issue"), - actor=actor, + actor_id=actor_id, verb="deleted", - old_value=f"{project.identifier}-{issue.sequence_id}", + old_value=f"{issue.project.identifier}-{issue.sequence_id}", new_value="", field=f'{current_instance.get("relation_type")}', - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f'deleted {current_instance.get("relation_type")} relation', old_identifier=current_instance.get("related_issue"), epoch=epoch, @@ -1149,24 +1345,38 @@ def delete_issue_relation_activity( def create_draft_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"drafted the issue", field="draft", verb="created", - actor=actor, + actor_id=actor_id, epoch=epoch, ) ) def update_draft_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): requested_data = json.loads(requested_data) if requested_data is not None else None current_instance = ( @@ -1179,11 +1389,11 @@ def update_draft_issue_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"created the issue", verb="updated", - actor=actor, + actor_id=actor_id, epoch=epoch, ) ) @@ -1191,28 +1401,35 @@ def update_draft_issue_activity( issue_activities.append( IssueActivity( issue_id=issue_id, - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"updated the draft issue", field="draft", verb="updated", - actor=actor, + actor_id=actor_id, epoch=epoch, ) ) def delete_draft_issue_activity( - requested_data, current_instance, issue_id, project, actor, issue_activities, epoch + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, ): issue_activities.append( IssueActivity( - project=project, - workspace=project.workspace, + project_id=project_id, + workspace_id=workspace_id, comment=f"deleted the draft issue", field="draft", verb="deleted", - actor=actor, + actor_id=actor_id, epoch=epoch, ) ) @@ -1231,44 +1448,18 @@ def issue_activity( subscriber=True, ): try: - issue_activities = [] - actor = User.objects.get(pk=actor_id) project = Project.objects.get(pk=project_id) + issue = Issue.objects.filter(pk=issue_id).first() + workspace_id = project.workspace_id - if type not in [ - "cycle.activity.created", - "cycle.activity.deleted", - "module.activity.created", - "module.activity.deleted", - "issue_reaction.activity.created", - "issue_reaction.activity.deleted", - "comment_reaction.activity.created", - "comment_reaction.activity.deleted", - "issue_vote.activity.created", - "issue_vote.activity.deleted", - "issue_draft.activity.created", - "issue_draft.activity.updated", - "issue_draft.activity.deleted", - ]: - issue = Issue.objects.filter(pk=issue_id).first() - - if issue is not None: - try: - issue.updated_at = timezone.now() - issue.save(update_fields=["updated_at"]) - except Exception as e: - pass - - if subscriber: - # add the user to issue subscriber - try: - _ = IssueSubscriber.objects.get_or_create( - issue_id=issue_id, subscriber=actor - ) - except Exception as e: - pass + if issue is not None: + try: + issue.updated_at = timezone.now() + issue.save(update_fields=["updated_at"]) + except Exception as e: + pass ACTIVITY_MAPPER = { "issue.activity.created": create_issue_activity, @@ -1302,13 +1493,14 @@ def issue_activity( func = ACTIVITY_MAPPER.get(type) if func is not None: func( - requested_data, - current_instance, - issue_id, - project, - actor, - issue_activities, - epoch, + requested_data=requested_data, + current_instance=current_instance, + issue_id=issue_id, + project_id=project_id, + workspace_id=workspace_id, + actor_id=actor_id, + issue_activities=issue_activities, + epoch=epoch, ) # Save all the values to database @@ -1332,89 +1524,17 @@ def issue_activity( except Exception as e: capture_exception(e) - if type not in [ - "cycle.activity.created", - "cycle.activity.deleted", - "module.activity.created", - "module.activity.deleted", - "issue_reaction.activity.created", - "issue_reaction.activity.deleted", - "comment_reaction.activity.created", - "comment_reaction.activity.deleted", - "issue_vote.activity.created", - "issue_vote.activity.deleted", - "issue_draft.activity.created", - "issue_draft.activity.updated", - "issue_draft.activity.deleted", - ]: - # Create Notifications - bulk_notifications = [] - - issue_subscribers = list( - IssueSubscriber.objects.filter(project=project, issue_id=issue_id) - .exclude(subscriber_id=actor_id) - .values_list("subscriber", flat=True) - ) - - issue_assignees = list( - IssueAssignee.objects.filter(project=project, issue_id=issue_id) - .exclude(assignee_id=actor_id) - .values_list("assignee", flat=True) - ) - - issue_subscribers = issue_subscribers + issue_assignees - - issue = Issue.objects.filter(pk=issue_id).first() - - # Add bot filtering - if ( - issue is not None - and issue.created_by_id is not None - and not issue.created_by.is_bot - and str(issue.created_by_id) != str(actor_id) - ): - issue_subscribers = issue_subscribers + [issue.created_by_id] - - for subscriber in list(set(issue_subscribers)): - for issue_activity in issue_activities_created: - bulk_notifications.append( - Notification( - workspace=project.workspace, - sender="in_app:issue_activities", - triggered_by_id=actor_id, - receiver_id=subscriber, - entity_identifier=issue_id, - entity_name="issue", - project=project, - title=issue_activity.comment, - data={ - "issue": { - "id": str(issue_id), - "name": str(issue.name), - "identifier": str(issue.project.identifier), - "sequence_id": issue.sequence_id, - "state_name": issue.state.name, - "state_group": issue.state.group, - }, - "issue_activity": { - "id": str(issue_activity.id), - "verb": str(issue_activity.verb), - "field": str(issue_activity.field), - "actor": str(issue_activity.actor_id), - "new_value": str(issue_activity.new_value), - "old_value": str(issue_activity.old_value), - "issue_comment": str( - issue_activity.issue_comment.comment_stripped - if issue_activity.issue_comment is not None - else "" - ), - }, - }, - ) - ) - - # Bulk create notifications - Notification.objects.bulk_create(bulk_notifications, batch_size=100) + notifications.delay( + type=type, + issue_id=issue_id, + actor_id=actor_id, + project_id=project_id, + subscriber=subscriber, + issue_activities_created=json.dumps( + IssueActivitySerializer(issue_activities_created, many=True).data, + cls=DjangoJSONEncoder, + ), + ) return except Exception as e: diff --git a/apiserver/plane/bgtasks/notification_task.py b/apiserver/plane/bgtasks/notification_task.py new file mode 100644 index 000000000..f290a38c0 --- /dev/null +++ b/apiserver/plane/bgtasks/notification_task.py @@ -0,0 +1,102 @@ +# Python imports +import json + +# Django imports +from django.utils import timezone + +# Module imports +from plane.db.models import IssueSubscriber, Project, IssueAssignee, Issue, Notification + +# Third Party imports +from celery import shared_task + + +@shared_task +def notifications(type, issue_id, project_id, actor_id, subscriber, issue_activities_created): + issue_activities_created = ( + json.loads(issue_activities_created) if issue_activities_created is not None else None + ) + if type not in [ + "cycle.activity.created", + "cycle.activity.deleted", + "module.activity.created", + "module.activity.deleted", + "issue_reaction.activity.created", + "issue_reaction.activity.deleted", + "comment_reaction.activity.created", + "comment_reaction.activity.deleted", + "issue_vote.activity.created", + "issue_vote.activity.deleted", + "issue_draft.activity.created", + "issue_draft.activity.updated", + "issue_draft.activity.deleted", + ]: + # Create Notifications + bulk_notifications = [] + issue_subscribers = list( + IssueSubscriber.objects.filter(project_id=project_id, issue_id=issue_id) + .exclude(subscriber_id=actor_id) + .values_list("subscriber", flat=True) + ) + + issue_assignees = list( + IssueAssignee.objects.filter(project_id=project_id, issue_id=issue_id) + .exclude(assignee_id=actor_id) + .values_list("assignee", flat=True) + ) + + issue_subscribers = issue_subscribers + issue_assignees + + issue = Issue.objects.filter(pk=issue_id).first() + + if subscriber: + # add the user to issue subscriber + try: + _ = IssueSubscriber.objects.get_or_create( + issue_id=issue_id, subscriber_id=actor_id + ) + except Exception as e: + pass + + project = Project.objects.get(pk=project_id) + + for subscriber in list(set(issue_subscribers)): + for issue_activity in issue_activities_created: + bulk_notifications.append( + Notification( + workspace=project.workspace, + sender="in_app:issue_activities", + triggered_by_id=actor_id, + receiver_id=subscriber, + entity_identifier=issue_id, + entity_name="issue", + project=project, + title=issue_activity.get("comment"), + data={ + "issue": { + "id": str(issue_id), + "name": str(issue.name), + "identifier": str(issue.project.identifier), + "sequence_id": issue.sequence_id, + "state_name": issue.state.name, + "state_group": issue.state.group, + }, + "issue_activity": { + "id": str(issue_activity.get("id")), + "verb": str(issue_activity.get("verb")), + "field": str(issue_activity.get("field")), + "actor": str(issue_activity.get("actor_id")), + "new_value": str(issue_activity.get("new_value")), + "old_value": str(issue_activity.get("old_value")), + "issue_comment": str( + issue_activity.get("issue_comment").comment_stripped + if issue_activity.get("issue_comment") is not None + else "" + ), + }, + }, + ) + ) + + # Bulk create notifications + Notification.objects.bulk_create(bulk_notifications, batch_size=100) From fc82d6fc230da6c73b21316bfb4e91da1c41f768 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 27 Oct 2023 18:45:10 +0530 Subject: [PATCH 17/17] style: module ui revamp (#2548) * chore: module constant and helper function added * style: module card ui revamp * chore: custom media query added * chore: circular progress indicator added * chore: module card item ui improvement * chore: module list view added * chore: module sidebar added in list and card view * chore: module list and card ui improvement * chore: module sidebar select, avatar and link list component improvement * chore: sidebar improvement and refactor * style: module sidebar revamp * style: module sidebar ui improvement * chore: module sidebar lead and member select improvement * style: module sidebar progress section empty state added * chore: module card issue count validation added * style: module card and list item ui improvement --- .../tailwind-config-custom/tailwind.config.js | 4 +- .../progress/circular-progress-indicator.tsx | 102 ++++ packages/ui/src/progress/index.tsx | 1 + web/components/core/sidebar/links-list.tsx | 101 +-- .../core/sidebar/sidebar-progress-stats.tsx | 224 ++++--- .../core/sidebar/single-progress-stats.tsx | 4 +- web/components/headers/modules-list.tsx | 17 +- web/components/modules/index.ts | 2 + web/components/modules/module-card-item.tsx | 221 ++++--- web/components/modules/module-list-item.tsx | 242 ++++++++ .../modules/module-peek-overview.tsx | 55 ++ web/components/modules/modules-list-view.tsx | 55 +- .../modules/sidebar-select/select-lead.tsx | 31 +- .../modules/sidebar-select/select-members.tsx | 35 +- web/components/modules/sidebar.tsx | 574 +++++++----------- web/components/ui/avatar.tsx | 15 +- web/constants/module.ts | 50 +- web/helpers/date-time.helper.ts | 12 + .../[projectId]/modules/[moduleId].tsx | 20 +- web/public/empty-state/empty_label.svg | 4 + web/public/empty-state/empty_members.svg | 13 + 21 files changed, 1159 insertions(+), 623 deletions(-) create mode 100644 packages/ui/src/progress/circular-progress-indicator.tsx create mode 100644 web/components/modules/module-list-item.tsx create mode 100644 web/components/modules/module-peek-overview.tsx create mode 100644 web/public/empty-state/empty_label.svg create mode 100644 web/public/empty-state/empty_members.svg diff --git a/packages/tailwind-config-custom/tailwind.config.js b/packages/tailwind-config-custom/tailwind.config.js index 8a03462c0..b877dc7c0 100644 --- a/packages/tailwind-config-custom/tailwind.config.js +++ b/packages/tailwind-config-custom/tailwind.config.js @@ -213,7 +213,9 @@ module.exports = { }, }, }), - + screens: { + "3xl": "1792px", + }, // scale down font sizes to 90% of default fontSize: { xs: "0.675rem", diff --git a/packages/ui/src/progress/circular-progress-indicator.tsx b/packages/ui/src/progress/circular-progress-indicator.tsx new file mode 100644 index 000000000..8ef74ea52 --- /dev/null +++ b/packages/ui/src/progress/circular-progress-indicator.tsx @@ -0,0 +1,102 @@ +import React, { Children } from "react"; + +interface ICircularProgressIndicator { + size: number; + percentage: number; + strokeWidth?: number; + strokeColor?: string; + children?: React.ReactNode; +} + +export const CircularProgressIndicator: React.FC = ( + props +) => { + const { size = 40, percentage = 25, strokeWidth = 6, children } = props; + + const sqSize = size; + const radius = (size - strokeWidth) / 2; + const viewBox = `0 0 ${sqSize} ${sqSize}`; + const dashArray = radius * Math.PI * 2; + const dashOffset = dashArray - (dashArray * percentage) / 100; + return ( +
+ + + + + + + + + + + + + + + + + + +
+ {children} +
+
+ ); +}; diff --git a/packages/ui/src/progress/index.tsx b/packages/ui/src/progress/index.tsx index ad5a371c1..56d28cee7 100644 --- a/packages/ui/src/progress/index.tsx +++ b/packages/ui/src/progress/index.tsx @@ -1,3 +1,4 @@ export * from "./radial-progress"; export * from "./progress-bar"; export * from "./linear-progress-indicator"; +export * from "./circular-progress-indicator"; diff --git a/web/components/core/sidebar/links-list.tsx b/web/components/core/sidebar/links-list.tsx index 6de940296..ff8d30927 100644 --- a/web/components/core/sidebar/links-list.tsx +++ b/web/components/core/sidebar/links-list.tsx @@ -15,58 +15,63 @@ type Props = { export const LinksList: React.FC = ({ links, handleDeleteLink, handleEditLink, userAuth }) => { const isNotAllowed = userAuth.isGuest || userAuth.isViewer; - return ( <> {links.map((link) => ( -
- {!isNotAllowed && ( -
- - - - - +
+
+
+ + + + {link.title && link.title !== "" ? link.title : link.url}
- )} - -
- -
-
-
{link.title ?? link.url}
-

- Added {timeAgo(link.created_at)} -
- by{" "} - {link.created_by_detail.is_bot - ? link.created_by_detail.first_name + " Bot" - : link.created_by_detail.display_name} -

-
-
+ + {!isNotAllowed && ( +
+ + + + + +
+ )} +
+
+

+ Added {timeAgo(link.created_at)} +
+ by{" "} + {link.created_by_detail.is_bot + ? link.created_by_detail.first_name + " Bot" + : link.created_by_detail.display_name} +

+
))} diff --git a/web/components/core/sidebar/sidebar-progress-stats.tsx b/web/components/core/sidebar/sidebar-progress-stats.tsx index fed61b59f..bb6690172 100644 --- a/web/components/core/sidebar/sidebar-progress-stats.tsx +++ b/web/components/core/sidebar/sidebar-progress-stats.tsx @@ -1,11 +1,16 @@ import React from "react"; +import Image from "next/image"; // headless ui import { Tab } from "@headlessui/react"; // hooks import useLocalStorage from "hooks/use-local-storage"; import useIssuesView from "hooks/use-issues-view"; +// images +import emptyLabel from "public/empty-state/empty_label.svg"; +import emptyMembers from "public/empty-state/empty_members.svg"; // components +import { StateGroupIcon } from "@plane/ui"; import { SingleProgressStats } from "components/core"; // ui import { Avatar } from "components/ui"; @@ -17,9 +22,7 @@ import { TLabelsDistribution, TStateGroups, } from "types"; -// constants -import { STATE_GROUP_COLORS } from "constants/state"; -// types + type Props = { distribution: { assignees: TAssigneesDistribution[]; @@ -33,6 +36,7 @@ type Props = { module?: IModule; roundedTab?: boolean; noBackground?: boolean; + isPeekModuleDetails?: boolean; }; export const SidebarProgressStats: React.FC = ({ @@ -42,6 +46,7 @@ export const SidebarProgressStats: React.FC = ({ module, roundedTab, noBackground, + isPeekModuleDetails = false, }) => { const { filters, setFilters } = useIssuesView(); @@ -55,7 +60,6 @@ export const SidebarProgressStats: React.FC = ({ return 1; case "States": return 2; - default: return 0; } @@ -72,7 +76,6 @@ export const SidebarProgressStats: React.FC = ({ return setTab("Labels"); case 2: return setTab("States"); - default: return setTab("Assignees"); } @@ -82,15 +85,17 @@ export const SidebarProgressStats: React.FC = ({ as="div" className={`flex w-full items-center gap-2 justify-between rounded-md ${ noBackground ? "" : "bg-custom-background-90" - } px-1 py-1.5 - ${module ? "text-xs" : "text-sm"} `} + } p-0.5 + ${module ? "text-xs" : "text-sm"}`} > `w-full ${ roundedTab ? "rounded-3xl border border-custom-border-200" : "rounded" } px-3 py-1 text-custom-text-100 ${ - selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80" + selected + ? "bg-custom-background-100 text-custom-text-300 shadow-custom-shadow-2xs" + : "text-custom-text-400 hover:text-custom-text-300" }` } > @@ -101,7 +106,9 @@ export const SidebarProgressStats: React.FC = ({ `w-full ${ roundedTab ? "rounded-3xl border border-custom-border-200" : "rounded" } px-3 py-1 text-custom-text-100 ${ - selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80" + selected + ? "bg-custom-background-100 text-custom-text-300 shadow-custom-shadow-2xs" + : "text-custom-text-400 hover:text-custom-text-300" }` } > @@ -112,113 +119,128 @@ export const SidebarProgressStats: React.FC = ({ `w-full ${ roundedTab ? "rounded-3xl border border-custom-border-200" : "rounded" } px-3 py-1 text-custom-text-100 ${ - selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80" + selected + ? "bg-custom-background-100 text-custom-text-300 shadow-custom-shadow-2xs" + : "text-custom-text-400 hover:text-custom-text-300" }` } > States - - - {distribution.assignees.map((assignee, index) => { - if (assignee.assignee_id) - return ( - - - {assignee.display_name} -
- } - completed={assignee.completed_issues} - total={assignee.total_issues} - onClick={() => { - if (filters?.assignees?.includes(assignee.assignee_id ?? "")) - setFilters({ - assignees: filters?.assignees?.filter((a) => a !== assignee.assignee_id), - }); - else - setFilters({ - assignees: [...(filters?.assignees ?? []), assignee.assignee_id ?? ""], - }); - }} - selected={filters?.assignees?.includes(assignee.assignee_id ?? "")} - /> - ); - else - return ( - -
- User + + {distribution.assignees.length > 0 ? ( + distribution.assignees.map((assignee, index) => { + if (assignee.assignee_id) + return ( + + + {assignee.display_name}
- No assignee -
- } - completed={assignee.completed_issues} - total={assignee.total_issues} - /> - ); - })} - - - {distribution.labels.map((label, index) => ( - - { + if (filters?.assignees?.includes(assignee.assignee_id ?? "")) + setFilters({ + assignees: filters?.assignees?.filter((a) => a !== assignee.assignee_id), + }); + else + setFilters({ + assignees: [...(filters?.assignees ?? []), assignee.assignee_id ?? ""], + }); + }, + selected: filters?.assignees?.includes(assignee.assignee_id ?? ""), + })} /> - {label.label_name ?? "No labels"} -
- } - completed={label.completed_issues} - total={label.total_issues} - onClick={() => { - if (filters.labels?.includes(label.label_id ?? "")) - setFilters({ - labels: filters?.labels?.filter((l) => l !== label.label_id), - }); - else setFilters({ labels: [...(filters?.labels ?? []), label.label_id ?? ""] }); - }} - selected={filters?.labels?.includes(label.label_id ?? "")} - /> - ))} + ); + else + return ( + +
+ User +
+ No assignee +
+ } + completed={assignee.completed_issues} + total={assignee.total_issues} + /> + ); + }) + ) : ( +
+
+ empty members +
+
No assignees yet
+
+ )} - + + {distribution.labels.length > 0 ? ( + distribution.labels.map((label, index) => ( + + + {label.label_name ?? "No labels"} +
+ } + completed={label.completed_issues} + total={label.total_issues} + {...(!isPeekModuleDetails && { + onClick: () => { + if (filters.labels?.includes(label.label_id ?? "")) + setFilters({ + labels: filters?.labels?.filter((l) => l !== label.label_id), + }); + else setFilters({ labels: [...(filters?.labels ?? []), label.label_id ?? ""] }); + }, + selected: filters?.labels?.includes(label.label_id ?? ""), + })} + /> + )) + ) : ( +
+
+ empty label +
+
No labels yet
+
+ )} + + {Object.keys(groupedIssues).map((group, index) => ( - + {group}
} diff --git a/web/components/core/sidebar/single-progress-stats.tsx b/web/components/core/sidebar/single-progress-stats.tsx index 3ff214b57..ba6675c9a 100644 --- a/web/components/core/sidebar/single-progress-stats.tsx +++ b/web/components/core/sidebar/single-progress-stats.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { ProgressBar } from "@plane/ui"; +import { CircularProgressIndicator } from "@plane/ui"; type TSingleProgressStatsProps = { title: any; @@ -27,7 +27,7 @@ export const SingleProgressStats: React.FC = ({
- + {isNaN(Math.floor((completed / total) * 100)) ? "0" : Math.floor((completed / total) * 100)}% diff --git a/web/components/headers/modules-list.tsx b/web/components/headers/modules-list.tsx index 8d5df1b32..01c6df5c8 100644 --- a/web/components/headers/modules-list.tsx +++ b/web/components/headers/modules-list.tsx @@ -1,25 +1,28 @@ import { useRouter } from "next/router"; import Link from "next/link"; import { observer } from "mobx-react-lite"; -import { Plus } from "lucide-react"; +import { GanttChart, LayoutGrid, List, Plus } from "lucide-react"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // hooks import useLocalStorage from "hooks/use-local-storage"; // ui import { Breadcrumbs, BreadcrumbItem, Button, Tooltip } from "@plane/ui"; -import { Icon } from "components/ui"; // helper import { replaceUnderscoreIfSnakeCase, truncateText } from "helpers/string.helper"; -const moduleViewOptions: { type: "grid" | "gantt_chart"; icon: any }[] = [ +const moduleViewOptions: { type: "list" | "grid" | "gantt_chart"; icon: any }[] = [ { - type: "gantt_chart", - icon: "view_timeline", + type: "list", + icon: List, }, { type: "grid", - icon: "table_rows", + icon: LayoutGrid, + }, + { + type: "gantt_chart", + icon: GanttChart, }, ]; @@ -67,7 +70,7 @@ export const ModulesListHeader: React.FC = observer(() => { }`} onClick={() => setModulesView(option.type)} > - + ))} diff --git a/web/components/modules/index.ts b/web/components/modules/index.ts index 750db2fd0..c87ea79d2 100644 --- a/web/components/modules/index.ts +++ b/web/components/modules/index.ts @@ -7,3 +7,5 @@ export * from "./modal"; export * from "./modules-list-view"; export * from "./sidebar"; export * from "./module-card-item"; +export * from "./module-list-item"; +export * from "./module-peek-overview"; diff --git a/web/components/modules/module-card-item.tsx b/web/components/modules/module-card-item.tsx index 74dd20ad9..620333f8e 100644 --- a/web/components/modules/module-card-item.tsx +++ b/web/components/modules/module-card-item.tsx @@ -10,14 +10,16 @@ import useToast from "hooks/use-toast"; import { CreateUpdateModuleModal, DeleteModuleModal } from "components/modules"; // ui import { AssigneesList } from "components/ui"; -import { CustomMenu, Tooltip } from "@plane/ui"; +import { CustomMenu, LayersIcon, Tooltip } from "@plane/ui"; // icons -import { CalendarDays, LinkIcon, Pencil, Star, Target, Trash2 } from "lucide-react"; +import { Info, LinkIcon, Pencil, Star, Trash2 } from "lucide-react"; // helpers -import { copyUrlToClipboard, truncateText } from "helpers/string.helper"; -import { renderShortDateWithYearFormat } from "helpers/date-time.helper"; +import { copyUrlToClipboard } from "helpers/string.helper"; +import { renderShortDate, renderShortMonthDate } from "helpers/date-time.helper"; // types import { IModule } from "types"; +// constants +import { MODULE_STATUS } from "constants/module"; type Props = { module: IModule; @@ -72,9 +74,32 @@ export const ModuleCardItem: React.FC = observer((props) => { }); }; + const openModuleOverview = () => { + const { query } = router; + + router.push({ + pathname: router.pathname, + query: { ...query, peekModule: module.id }, + }); + }; + const endDate = new Date(module.target_date ?? ""); const startDate = new Date(module.start_date ?? ""); - const lastUpdated = new Date(module.updated_at ?? ""); + + const areYearsEqual = startDate.getFullYear() === endDate.getFullYear(); + + const moduleStatus = MODULE_STATUS.find((status) => status.value === module.status); + + const issueCount = + module.completed_issues && module.total_issues + ? module.total_issues === 0 + ? "0 Issue" + : module.total_issues === module.completed_issues + ? module.total_issues > 1 + ? `${module.total_issues} Issues` + : `${module.total_issues} Issue` + : `${module.completed_issues}/${module.total_issues} Issues` + : "0 Issue"; return ( <> @@ -88,96 +113,142 @@ export const ModuleCardItem: React.FC = observer((props) => { /> )} setModuleDeleteModal(false)} /> -
-
-
-
- - - -

- {truncateText(module.name, 75)} -

-
- + + +
+
+ + {module.name} +
+ {moduleStatus && ( + + {moduleStatus.label} + + )} + +
+
+
-
-
- {module?.status?.replace("-", " ")} +
+
+
+ + {issueCount} +
+ {module.members_detail.length > 0 && ( + +
+ +
+
+ )} +
+ + +
+
+
+
+ + +
+ + {areYearsEqual ? renderShortDate(startDate, "_ _") : renderShortMonthDate(startDate, "_ _")} -{" "} + {areYearsEqual ? renderShortDate(endDate, "_ _") : renderShortMonthDate(endDate, "_ _")} + +
{module.is_favorite ? ( - ) : ( - )} - - - + + { + e.preventDefault(); + e.stopPropagation(); + setEditModuleModal(true); + }} + > - - Copy link - - - setEditModuleModal(true)}> - - + Edit module - setModuleDeleteModal(true)}> + { + e.preventDefault(); + e.stopPropagation(); + setModuleDeleteModal(true); + }} + > - + Delete module + { + e.preventDefault(); + e.stopPropagation(); + handleCopyText(); + }} + > + + + Copy module link + +
-
-
- - Start: - {renderShortDateWithYearFormat(startDate, "Not set")} -
-
- - End: - {renderShortDateWithYearFormat(endDate, "Not set")} -
-
-
-
-
- Progress -
-
-
- {isNaN(completionPercentage) ? 0 : completionPercentage.toFixed(0)}% -
-
-

- Last updated: - {renderShortDateWithYearFormat(lastUpdated)} -

- {module.members_detail.length > 0 && ( -
- -
- )} -
-
-
+
+ ); }); diff --git a/web/components/modules/module-list-item.tsx b/web/components/modules/module-list-item.tsx new file mode 100644 index 000000000..8b1271cc8 --- /dev/null +++ b/web/components/modules/module-list-item.tsx @@ -0,0 +1,242 @@ +import React, { useState } from "react"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +// hooks +import useToast from "hooks/use-toast"; +// components +import { CreateUpdateModuleModal, DeleteModuleModal } from "components/modules"; +// ui +import { AssigneesList } from "components/ui"; +import { CircularProgressIndicator, CustomMenu, Tooltip } from "@plane/ui"; +// icons +import { Check, Info, LinkIcon, Pencil, Star, Trash2, User2 } from "lucide-react"; +// helpers +import { copyUrlToClipboard } from "helpers/string.helper"; +import { renderShortDate, renderShortMonthDate } from "helpers/date-time.helper"; +// types +import { IModule } from "types"; +// constants +import { MODULE_STATUS } from "constants/module"; + +type Props = { + module: IModule; +}; + +export const ModuleListItem: React.FC = observer((props) => { + const { module } = props; + + const [editModuleModal, setEditModuleModal] = useState(false); + const [moduleDeleteModal, setModuleDeleteModal] = useState(false); + + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { setToastAlert } = useToast(); + + const { module: moduleStore } = useMobxStore(); + + const completionPercentage = ((module.completed_issues + module.cancelled_issues) / module.total_issues) * 100; + + const handleAddToFavorites = () => { + if (!workspaceSlug || !projectId) return; + + moduleStore.addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), module.id).catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Couldn't add the module to favorites. Please try again.", + }); + }); + }; + + const handleRemoveFromFavorites = () => { + if (!workspaceSlug || !projectId) return; + + moduleStore.removeModuleFromFavorites(workspaceSlug.toString(), projectId.toString(), module.id).catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Couldn't remove the module from favorites. Please try again.", + }); + }); + }; + + const handleCopyText = () => { + copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/modules/${module.id}`).then(() => { + setToastAlert({ + type: "success", + title: "Link Copied!", + message: "Module link copied to clipboard.", + }); + }); + }; + + const endDate = new Date(module.target_date ?? ""); + const startDate = new Date(module.start_date ?? ""); + + const renderDate = module.start_date || module.target_date; + + const areYearsEqual = startDate.getFullYear() === endDate.getFullYear(); + + const moduleStatus = MODULE_STATUS.find((status) => status.value === module.status); + + const progress = isNaN(completionPercentage) ? 0 : Math.floor(completionPercentage); + + const completedModuleCheck = module.status === "completed" && module.total_issues - module.completed_issues; + + const openModuleOverview = () => { + const { query } = router; + + router.push({ + pathname: router.pathname, + query: { ...query, peekModule: module.id }, + }); + }; + + return ( + <> + {workspaceSlug && projectId && ( + setEditModuleModal(false)} + data={module} + projectId={projectId.toString()} + workspaceSlug={workspaceSlug.toString()} + /> + )} + setModuleDeleteModal(false)} /> + + +
+
+ + + {completedModuleCheck ? ( + {`!`} + ) : progress === 100 ? ( + + ) : ( + {`${progress}%`} + )} + + + + {module.name} + +
+ +
+ +
+
+ {moduleStatus && ( + + {moduleStatus.label} + + )} +
+ + {renderDate && ( + + {areYearsEqual ? renderShortDate(startDate, "_ _") : renderShortMonthDate(startDate, "_ _")} + {" - "} + {areYearsEqual ? renderShortDate(endDate, "_ _") : renderShortMonthDate(endDate, "_ _")} + + )} + + +
+ {module.members_detail.length > 0 ? ( + + ) : ( + + + + )} +
+
+ + {module.is_favorite ? ( + + ) : ( + + )} + + + { + e.preventDefault(); + e.stopPropagation(); + setEditModuleModal(true); + }} + > + + + Edit module + + + { + e.preventDefault(); + e.stopPropagation(); + setModuleDeleteModal(true); + }} + > + + + Delete module + + + { + e.preventDefault(); + e.stopPropagation(); + handleCopyText(); + }} + > + + + Copy module link + + + +
+
+ + + ); +}); diff --git a/web/components/modules/module-peek-overview.tsx b/web/components/modules/module-peek-overview.tsx new file mode 100644 index 000000000..c7d2630cb --- /dev/null +++ b/web/components/modules/module-peek-overview.tsx @@ -0,0 +1,55 @@ +import React, { useEffect } from "react"; + +import { useRouter } from "next/router"; + +// mobx +import { observer } from "mobx-react-lite"; +import { useMobxStore } from "lib/mobx/store-provider"; +// components +import { ModuleDetailsSidebar } from "./sidebar"; + +type Props = { + projectId: string; + workspaceSlug: string; +}; + +export const ModulePeekOverview: React.FC = observer(({ projectId, workspaceSlug }) => { + const router = useRouter(); + const { peekModule } = router.query; + + const ref = React.useRef(null); + + const { module: moduleStore } = useMobxStore(); + const { fetchModuleDetails } = moduleStore; + + const handleClose = () => { + delete router.query.peekModule; + router.push({ + pathname: router.pathname, + query: { ...router.query }, + }); + }; + + useEffect(() => { + if (!peekModule) return; + + fetchModuleDetails(workspaceSlug, projectId, peekModule.toString()); + }, [fetchModuleDetails, peekModule, projectId, workspaceSlug]); + + return ( + <> + {peekModule && ( +
+ +
+ )} + + ); +}); diff --git a/web/components/modules/modules-list-view.tsx b/web/components/modules/modules-list-view.tsx index d40b72a31..457f43524 100644 --- a/web/components/modules/modules-list-view.tsx +++ b/web/components/modules/modules-list-view.tsx @@ -1,3 +1,4 @@ +import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { Plus } from "lucide-react"; // mobx store @@ -5,7 +6,7 @@ import { useMobxStore } from "lib/mobx/store-provider"; // hooks import useLocalStorage from "hooks/use-local-storage"; // components -import { ModuleCardItem, ModulesListGanttChartView } from "components/modules"; +import { ModuleCardItem, ModuleListItem, ModulePeekOverview, ModulesListGanttChartView } from "components/modules"; import { EmptyState } from "components/common"; // ui import { Loader } from "@plane/ui"; @@ -13,6 +14,9 @@ import { Loader } from "@plane/ui"; import emptyModule from "public/empty-state/module.svg"; export const ModulesListView: React.FC = observer(() => { + const router = useRouter(); + const { workspaceSlug, projectId, peekModule } = router.query; + const { module: moduleStore } = useMobxStore(); const { storedValue: modulesView } = useLocalStorage("modules_view", "grid"); @@ -22,12 +26,12 @@ export const ModulesListView: React.FC = observer(() => { if (!modulesList) return ( - - - - - - + + + + + + ); @@ -35,12 +39,39 @@ export const ModulesListView: React.FC = observer(() => { <> {modulesList.length > 0 ? ( <> + {modulesView === "list" && ( +
+
+
+ {modulesList.map((module) => ( + + ))} +
+ +
+
+ )} {modulesView === "grid" && ( -
-
- {modulesList.map((module) => ( - - ))} +
+
+
+ {modulesList.map((module) => ( + + ))} +
+
)} diff --git a/web/components/modules/sidebar-select/select-lead.tsx b/web/components/modules/sidebar-select/select-lead.tsx index 83ee93404..020aad037 100644 --- a/web/components/modules/sidebar-select/select-lead.tsx +++ b/web/components/modules/sidebar-select/select-lead.tsx @@ -7,7 +7,7 @@ import { ProjectService } from "services/project"; import { Avatar } from "components/ui"; import { CustomSearchSelect } from "@plane/ui"; // icons -import { UserCircle2 } from "lucide-react"; +import { ChevronDown, UserCircle2 } from "lucide-react"; // fetch-keys import { PROJECT_MEMBERS } from "constants/fetch-keys"; @@ -36,7 +36,7 @@ export const SidebarLeadSelect: FC = (props) => { query: member.member.display_name, content: (
- + {member.member.display_name}
), @@ -46,18 +46,27 @@ export const SidebarLeadSelect: FC = (props) => { return (
-
- - Lead +
+ + Lead
-
+
- {selectedOption && } - {selectedOption ? selectedOption?.display_name : No lead} -
+ customButtonClassName="rounded-sm" + customButton={ + selectedOption ? ( +
+ + {selectedOption?.display_name} +
+ ) : ( +
+ No lead + +
+ ) } options={options} maxHeight="md" diff --git a/web/components/modules/sidebar-select/select-members.tsx b/web/components/modules/sidebar-select/select-members.tsx index c25959e3f..7b74ef794 100644 --- a/web/components/modules/sidebar-select/select-members.tsx +++ b/web/components/modules/sidebar-select/select-members.tsx @@ -10,6 +10,7 @@ import { ProjectService } from "services/project"; import { AssigneesList, Avatar } from "components/ui"; import { CustomSearchSelect, UserGroupIcon } from "@plane/ui"; // icons +import { ChevronDown } from "lucide-react"; // fetch-keys import { PROJECT_MEMBERS } from "constants/fetch-keys"; @@ -37,7 +38,7 @@ export const SidebarMembersSelect: React.FC = ({ value, onChange }) => { query: member.member.display_name, content: (
- + {member.member.display_name}
), @@ -45,24 +46,26 @@ export const SidebarMembersSelect: React.FC = ({ value, onChange }) => { return (
-
- - Members +
+ + Members
-
+
- {value && value.length > 0 && Array.isArray(value) ? ( -
- - {value.length} Assignees -
- ) : ( - "No members" - )} -
+ customButtonClassName="rounded-sm" + customButton={ + value && value.length > 0 && Array.isArray(value) ? ( +
+ +
+ ) : ( +
+ No members + +
+ ) } options={options} onChange={onChange} diff --git a/web/components/modules/sidebar.tsx b/web/components/modules/sidebar.tsx index c6a2818ee..aa5462e08 100644 --- a/web/components/modules/sidebar.tsx +++ b/web/components/modules/sidebar.tsx @@ -3,8 +3,7 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { mutate } from "swr"; import { Controller, useForm } from "react-hook-form"; -import { Disclosure, Popover, Transition } from "@headlessui/react"; -import DatePicker from "react-datepicker"; +import { Disclosure, Transition } from "@headlessui/react"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // services @@ -18,22 +17,12 @@ import { LinkModal, LinksList, SidebarProgressStats } from "components/core"; import { DeleteModuleModal, SidebarLeadSelect, SidebarMembersSelect } from "components/modules"; import ProgressChart from "components/core/sidebar/progress-chart"; // ui -import { CustomSelect, CustomMenu, Loader, ProgressBar } from "@plane/ui"; +import { CustomMenu, Loader, LayersIcon } from "@plane/ui"; // icon -import { - AlertCircle, - CalendarDays, - ChevronDown, - File, - LinkIcon, - MoveRight, - PieChart, - Plus, - Trash2, -} from "lucide-react"; +import { AlertCircle, ChevronDown, ChevronRight, Info, LinkIcon, Plus, Trash2 } from "lucide-react"; // helpers -import { renderDateFormat, renderShortDateWithYearFormat } from "helpers/date-time.helper"; -import { capitalizeFirstLetter, copyUrlToClipboard } from "helpers/string.helper"; +import { renderShortDate, renderShortMonthDate } from "helpers/date-time.helper"; +import { copyUrlToClipboard } from "helpers/string.helper"; // types import { linkDetails, IModule, ModuleLink } from "types"; // fetch-keys @@ -50,8 +39,8 @@ const defaultValues: Partial = { }; type Props = { - isOpen: boolean; moduleId: string; + handleClose: () => void; }; // services @@ -59,14 +48,14 @@ const moduleService = new ModuleService(); // TODO: refactor this component export const ModuleDetailsSidebar: React.FC = observer((props) => { - const { isOpen, moduleId } = props; + const { moduleId, handleClose } = props; const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const [moduleLinkModal, setModuleLinkModal] = useState(false); const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState(null); const router = useRouter(); - const { workspaceSlug, projectId } = router.query; + const { workspaceSlug, projectId, peekModule } = router.query; const { module: moduleStore, user: userStore } = useMobxStore(); @@ -77,7 +66,7 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => { const { setToastAlert } = useToast(); - const { reset, watch, control } = useForm({ + const { reset, control } = useForm({ defaultValues, }); @@ -209,12 +198,29 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => { : null; const handleEditLink = (link: linkDetails) => { + console.log("link", link); setSelectedLinkToUpdate(link); setModuleLinkModal(true); }; if (!moduleDetails) return null; + const startDate = new Date(moduleDetails.start_date ?? ""); + const endDate = new Date(moduleDetails.target_date ?? ""); + + const areYearsEqual = startDate.getFullYear() === endDate.getFullYear(); + + const moduleStatus = MODULE_STATUS.find((status) => status.value === moduleDetails.status); + + const issueCount = + moduleDetails.total_issues === 0 + ? "0 Issue" + : moduleDetails.total_issues === moduleDetails.completed_issues + ? moduleDetails.total_issues > 1 + ? `${moduleDetails.total_issues}` + : `${moduleDetails.total_issues}` + : `${moduleDetails.completed_issues}/${moduleDetails.total_issues}`; + return ( <> = observer((props) => { updateIssueLink={handleUpdateLink} /> setModuleDeleteModal(false)} data={moduleDetails} /> -
- {module ? ( - <> -
-
-
- ( - - {capitalizeFirstLetter(`${watch("status")}`)} - - } - value={value} - onChange={(value: any) => { - submitChanges({ status: value }); - }} - > - {MODULE_STATUS.map((option) => ( - - {option.label} - - ))} - - )} - /> -
-
- - {({}) => ( - <> - - - - {renderShortDateWithYearFormat(new Date(`${moduleDetails.start_date}`), "Start date")} - - - - - - { - submitChanges({ - start_date: renderDateFormat(date), - }); - }} - selectsStart - startDate={new Date(`${watch("start_date")}`)} - endDate={new Date(`${watch("target_date")}`)} - maxDate={new Date(`${watch("target_date")}`)} - shouldCloseOnSelect - inline - /> - - - - )} - - - + {module ? ( + <> +
+
+ {peekModule && ( + + )} +
+
+ + + setModuleDeleteModal(true)}> + + + Delete - - {({}) => ( - <> - - + + +
+
- - {renderShortDateWithYearFormat(new Date(`${moduleDetails?.target_date}`), "End date")} - - +
+

{moduleDetails.name}

+
+ {moduleStatus && ( + + {moduleStatus.label} + + )} + + {areYearsEqual ? renderShortDate(startDate, "_ _") : renderShortMonthDate(startDate, "_ _")} -{" "} + {areYearsEqual ? renderShortDate(endDate, "_ _") : renderShortMonthDate(endDate, "_ _")} + +
+
- - - { - submitChanges({ - target_date: renderDateFormat(date), - }); - }} - selectsEnd - startDate={new Date(`${watch("start_date")}`)} - endDate={new Date(`${watch("target_date")}`)} - minDate={new Date(`${watch("start_date")}`)} - shouldCloseOnSelect - inline - /> - - - - )} - -
+ {moduleDetails.description && ( + + {moduleDetails.description} + + )} + +
+ ( + { + submitChanges({ lead: val }); + }} + /> + )} + /> + ( + { + submitChanges({ members_list: val }); + }} + /> + )} + /> + +
+
+ + Issues
- -
-
-
-
-

- {moduleDetails.name} -

-
- - setModuleDeleteModal(true)}> - - - Delete - - - - - - Copy link - - - -
- - - {moduleDetails.description} - -
- -
- ( - { - submitChanges({ lead: val }); - }} - /> - )} - /> - ( - { - submitChanges({ members_list: val }); - }} - /> - )} - /> - -
-
- - Progress -
- -
- - - - {moduleDetails.completed_issues}/{moduleDetails.total_issues} -
-
-
+
+ {issueCount}
+
-
- +
+
+ {({ open }) => (
-
+
Progress - {!open && progressPercentage ? ( - +
+ +
+ {progressPercentage ? ( + {progressPercentage ? `${progressPercentage}%` : ""} ) : ( "" )} -
- - {isStartValid && isEndValid ? ( - - - ) : ( -
- - - Invalid date. Please enter valid date. - -
- )} -
- - {isStartValid && isEndValid ? ( -
-
-
- - - - - Pending Issues -{" "} - {moduleDetails.total_issues - - (moduleDetails.completed_issues + moduleDetails.cancelled_issues)}{" "} - -
- -
-
- - Ideal -
-
- - Current -
-
-
-
- -
-
+ + ) : ( - "" +
+ + + Invalid date. Please enter valid date. + +
)} -
-
-
- )} - -
- -
- - {({ open }) => ( -
-
-
- Other Information
- - {moduleDetails.total_issues > 0 ? ( - - - ) : ( -
- - - No issues found. Please add issue. - -
- )}
- {moduleDetails.total_issues > 0 ? ( - <> -
+
+ {isStartValid && isEndValid ? ( +
+
+
+
+ + Ideal +
+
+ + Current +
+
+
+
+ +
+
+ ) : ( + "" + )} + {moduleDetails.total_issues > 0 && ( +
= observer((props) => { }} totalIssues={moduleDetails.total_issues} module={moduleDetails} + isPeekModuleDetails={Boolean(peekModule)} />
- - ) : ( - "" - )} + )} +
@@ -555,42 +412,83 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => {
-
-
-

Links

- -
-
- {memberRole && moduleDetails.link_module && moduleDetails.link_module.length > 0 ? ( - - ) : null} -
+
+ + {({ open }) => ( +
+
+
+ Links +
+ +
+ + +
+
+ + +
+ {memberRole && moduleDetails.link_module && moduleDetails.link_module.length > 0 ? ( + <> +
+ +
+ + + + ) : ( +
+
+ + No links added yet +
+ +
+ )} +
+
+
+
+ )} +
- - ) : ( - -
- - -
-
- - - -
-
- )} -
+
+ + ) : ( + +
+ + +
+
+ + + +
+
+ )} ); }); diff --git a/web/components/ui/avatar.tsx b/web/components/ui/avatar.tsx index 0eb76fe93..44997f807 100644 --- a/web/components/ui/avatar.tsx +++ b/web/components/ui/avatar.tsx @@ -76,11 +76,20 @@ export const Avatar: React.FC = ({ type AsigneesListProps = { users?: Partial | (Partial | undefined)[] | Partial[]; userIds?: string[]; + height?: string; + width?: string; length?: number; showLength?: boolean; }; -export const AssigneesList: React.FC = ({ users, userIds, length = 3, showLength = true }) => { +export const AssigneesList: React.FC = ({ + users, + userIds, + height = "24px", + width = "24px", + length = 3, + showLength = true, +}) => { const router = useRouter(); const { workspaceSlug } = router.query; @@ -101,7 +110,7 @@ export const AssigneesList: React.FC = ({ users, userIds, len {users && ( <> {users.slice(0, length).map((user, index) => ( - + ))} {users.length > length ? (
@@ -118,7 +127,7 @@ export const AssigneesList: React.FC = ({ users, userIds, len {userIds.slice(0, length).map((userId, index) => { const user = people?.find((p) => p.member.id === userId)?.member; - return ; + return ; })} {showLength ? ( userIds.length > length ? ( diff --git a/web/constants/module.ts b/web/constants/module.ts index 058171328..a49df336c 100644 --- a/web/constants/module.ts +++ b/web/constants/module.ts @@ -5,11 +5,49 @@ export const MODULE_STATUS: { label: string; value: TModuleStatus; color: string; + textColor: string; + bgColor: 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" }, + { + label: "Backlog", + value: "backlog", + color: "#a3a3a2", + textColor: "text-custom-text-400", + bgColor: "bg-custom-background-80", + }, + { + label: "Planned", + value: "planned", + color: "#3f76ff", + textColor: "text-blue-500", + bgColor: "bg-indigo-50", + }, + { + label: "In Progress", + value: "in-progress", + color: "#f39e1f", + textColor: "text-amber-500", + bgColor: "bg-amber-50", + }, + { + label: "Paused", + value: "paused", + color: "#525252", + textColor: "text-custom-text-300", + bgColor: "bg-custom-background-90", + }, + { + label: "Completed", + value: "completed", + color: "#16a34a", + textColor: "text-green-600", + bgColor: "bg-green-100", + }, + { + label: "Cancelled", + value: "cancelled", + color: "#ef4444", + textColor: "text-red-500", + bgColor: "bg-red-50", + }, ]; diff --git a/web/helpers/date-time.helper.ts b/web/helpers/date-time.helper.ts index 08dff4a18..dced747f9 100644 --- a/web/helpers/date-time.helper.ts +++ b/web/helpers/date-time.helper.ts @@ -172,6 +172,18 @@ export const renderShortDate = (date: string | Date, placeholder?: string) => { return isNaN(date.getTime()) ? placeholder ?? "N/A" : `${day} ${month}`; }; +export const renderShortMonthDate = (date: string | Date, placeholder?: string) => { + if (!date || date === "") return null; + + date = new Date(date); + + const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + const month = months[date.getMonth()]; + const year = date.getFullYear(); + + return isNaN(date.getTime()) ? placeholder ?? "N/A" : `${month} ${year}`; +}; + export const render12HourFormatTime = (date: string | Date): string => { if (!date || date === "") return ""; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx index fd6d05f8e..27e6880d7 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx @@ -27,7 +27,7 @@ const ModuleIssuesPage: NextPage = () => { const { module: moduleStore } = useMobxStore(); - const { storedValue } = useLocalStorage("module_sidebar_collapsed", "false"); + const { setValue, storedValue } = useLocalStorage("module_sidebar_collapsed", "false"); const isSidebarCollapsed = storedValue ? (storedValue === "true" ? true : false) : false; const { error } = useSWR( @@ -60,6 +60,10 @@ const ModuleIssuesPage: NextPage = () => { // setModuleIssuesListModal(true); // }; + const toggleSidebar = () => { + setValue(`${!isSidebarCollapsed}`); + }; + return ( <> } withProjectWrapper> @@ -82,10 +86,20 @@ const ModuleIssuesPage: NextPage = () => { /> ) : (
-
+
- {moduleId && } + {moduleId && !isSidebarCollapsed && ( +
+ +
+ )}
)} diff --git a/web/public/empty-state/empty_label.svg b/web/public/empty-state/empty_label.svg new file mode 100644 index 000000000..c664da6f4 --- /dev/null +++ b/web/public/empty-state/empty_label.svg @@ -0,0 +1,4 @@ + + + + diff --git a/web/public/empty-state/empty_members.svg b/web/public/empty-state/empty_members.svg new file mode 100644 index 000000000..6672c587b --- /dev/null +++ b/web/public/empty-state/empty_members.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + +