0
0
mirror of https://github.com/makeplane/plane synced 2024-06-14 14:31:34 +00:00

chore: implement project view hook

This commit is contained in:
Aaryan Khandelwal 2023-12-15 17:01:36 +05:30
parent 960f170fd4
commit 4e755289a1
80 changed files with 362 additions and 401 deletions
web
components
constants
hooks/store
layouts
auth-layout
settings-layout/project
pages/[workspaceSlug]/projects/[projectId]
services
store
store_legacy
types

View File

@ -8,10 +8,9 @@ import { SelectMonthModal } from "components/automation";
// icon
import { ArchiveRestore } from "lucide-react";
// constants
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
import { EUserProjectRoles, PROJECT_AUTOMATION_MONTHS } from "constants/project";
// types
import { IProject } from "types";
import { EUserWorkspaceRoles } from "constants/workspace";
type Props = {
handleChange: (formData: Partial<IProject>) => Promise<void>;
@ -29,7 +28,7 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
} = useUser();
const { currentProjectDetails } = useProject();
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
const isAdmin = currentProjectRole === EUserProjectRoles.ADMIN;
return (
<>

View File

@ -9,9 +9,8 @@ import { CustomSelect, CustomSearchSelect, ToggleSwitch, StateGroupIcon, DoubleC
import { ArchiveX } from "lucide-react";
// types
import { IProject } from "types";
// fetch keys
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
import { EUserWorkspaceRoles } from "constants/workspace";
// constants
import { EUserProjectRoles, PROJECT_AUTOMATION_MONTHS } from "constants/project";
type Props = {
handleChange: (formData: Partial<IProject>) => Promise<void>;
@ -55,7 +54,7 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
default_state: defaultState,
};
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
const isAdmin = currentProjectRole === EUserProjectRoles.ADMIN;
return (
<>

View File

@ -12,7 +12,7 @@ import { CycleGanttBlock } from "components/cycles";
// types
import { ICycle } from "types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
workspaceSlug: string;
@ -83,7 +83,7 @@ export const CyclesListGanttChartView: FC<Props> = observer((props) => {
};
const isAllowed =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<div className="h-full w-full overflow-y-auto">

View File

@ -19,10 +19,9 @@ import { renderEmoji } from "helpers/emoji.helper";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EFilterType } from "store_legacy/issues/types";
import { EProjectStore } from "store_legacy/command-palette.store";
import { EUserProjectRoles } from "constants/project";
export const CycleIssuesHeader: React.FC = observer(() => {
// states
@ -110,7 +109,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
const cycleDetails = cycleId ? cycleStore.getCycleById(cycleId.toString()) : undefined;
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<>

View File

@ -8,7 +8,7 @@ import { useApplication, useProject, useUser } from "hooks/store";
import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui";
// helpers
import { renderEmoji } from "helpers/emoji.helper";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const CyclesHeader: FC = observer(() => {
// router
@ -25,7 +25,7 @@ export const CyclesHeader: FC = observer(() => {
const { currentProjectDetails } = useProject();
const canUserCreateCycle =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">

View File

@ -19,10 +19,10 @@ import { renderEmoji } from "helpers/emoji.helper";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { EUserWorkspaceRoles } from "constants/workspace";
// store
import { EFilterType } from "store_legacy/issues/types";
import { EProjectStore } from "store_legacy/command-palette.store";
import { EUserProjectRoles } from "constants/project";
export const ModuleIssuesHeader: React.FC = observer(() => {
// states
@ -109,7 +109,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
const moduleDetails = moduleId ? moduleStore.getModuleById(moduleId.toString()) : undefined;
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<>

View File

@ -10,7 +10,7 @@ import { Breadcrumbs, Button, Tooltip, DiceIcon } from "@plane/ui";
import { renderEmoji } from "helpers/emoji.helper";
// constants
import { MODULE_VIEW_LAYOUTS } from "constants/module";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const ModulesListHeader: React.FC = observer(() => {
// router
@ -26,7 +26,7 @@ export const ModulesListHeader: React.FC = observer(() => {
const { storedValue: modulesView, setValue: setModulesView } = useLocalStorage("modules_view", "grid");
const canUserCreateModule =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">

View File

@ -8,7 +8,7 @@ import { Breadcrumbs, Button } from "@plane/ui";
// helpers
import { renderEmoji } from "helpers/emoji.helper";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const PagesHeader = observer(() => {
// router
@ -24,7 +24,7 @@ export const PagesHeader = observer(() => {
const { currentProjectDetails } = useProject();
const canUserCreatePage =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">

View File

@ -3,7 +3,8 @@ import Link from "next/link";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { ArrowLeft, Briefcase, Circle, ExternalLink, Plus } from "lucide-react";
// mobx store
// hooks
import { useApplication, useLabel, useProject, useProjectState, useUser } from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
@ -14,31 +15,37 @@ import { Breadcrumbs, Button, LayersIcon } from "@plane/ui";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { EUserWorkspaceRoles } from "constants/workspace";
// helper
import { renderEmoji } from "helpers/emoji.helper";
import { EFilterType } from "store_legacy/issues/types";
import { EProjectStore } from "store_legacy/command-palette.store";
import { EUserProjectRoles } from "constants/project";
export const ProjectIssuesHeader: React.FC = observer(() => {
// states
const [analyticsModal, setAnalyticsModal] = useState(false);
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string };
// store hooks
const {
project: { currentProjectDetails },
projectLabel: { projectLabels },
projectMember: { projectMembers },
projectState: projectStateStore,
inbox: inboxStore,
commandPalette: commandPaletteStore,
trackEvent: { setTrackElement },
// issue filters
projectIssuesFilter: { issueFilters, updateFilters },
projectIssues: {},
user: { currentProjectRole },
} = useMobxStore();
const {
commandPalette: { toggleCreateIssueModal },
eventTracker: { setTrackElement },
} = useApplication();
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { projectStates } = useProjectState();
const {
project: { projectLabels },
} = useLabel();
const activeLayout = issueFilters?.displayFilters?.layout;
@ -90,7 +97,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
const deployUrl = process.env.NEXT_PUBLIC_DEPLOY_URL;
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<>
@ -172,9 +179,9 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
layoutDisplayFiltersOptions={
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
}
labels={projectLabels ?? undefined}
labels={projectLabels}
members={projectMembers?.map((m) => m.member)}
states={projectStateStore.states?.[projectId ?? ""] ?? undefined}
states={projectStates}
/>
</FiltersDropdown>
<FiltersDropdown title="Display" placement="bottom-end">
@ -211,7 +218,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
<Button
onClick={() => {
setTrackElement("PROJECT_PAGE_HEADER");
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT);
toggleCreateIssueModal(true, EProjectStore.PROJECT);
}}
size="sm"
prependIcon={<Plus />}

View File

@ -8,7 +8,7 @@ import { renderEmoji } from "helpers/emoji.helper";
// hooks
import { useProject, useUser } from "hooks/store";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export interface IProjectSettingHeader {
title: string;
@ -25,7 +25,7 @@ export const ProjectSettingHeader: FC<IProjectSettingHeader> = observer((props)
} = useUser();
const { currentProjectDetails } = useProject();
if (currentProjectRole && currentProjectRole <= EUserWorkspaceRoles.VIEWER) return null;
if (currentProjectRole && currentProjectRole <= EUserProjectRoles.VIEWER) return null;
return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">

View File

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { Plus } from "lucide-react";
// hooks
import { useApplication, useLabel, useProject, useProjectState, useUser } from "hooks/store";
import { useApplication, useLabel, useProject, useProjectState, useProjectView, useUser } from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
@ -16,10 +16,9 @@ import { renderEmoji } from "helpers/emoji.helper";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EFilterType } from "store_legacy/issues/types";
import { EProjectStore } from "store_legacy/command-palette.store";
import { EUserProjectRoles } from "constants/project";
export const ProjectViewIssuesHeader: React.FC = observer(() => {
// router
@ -32,7 +31,6 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
// store hooks
const {
projectMember: { projectMembers },
projectViews: projectViewsStore,
viewIssuesFilter: { issueFilters, updateFilters },
} = useMobxStore();
const {
@ -43,6 +41,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { projectViews, getViewById } = useProjectView();
const { projectStates } = useProjectState();
const {
project: { projectLabels },
@ -93,11 +92,10 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
[workspaceSlug, projectId, viewId, updateFilters]
);
const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined;
const viewDetails = viewId ? projectViewsStore.viewDetails[viewId.toString()] : undefined;
const viewDetails = viewId ? getViewById(viewId.toString()) : null;
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<div className="relative z-10 flex h-[3.75rem] w-full items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
@ -142,17 +140,23 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
className="ml-1.5"
placement="bottom-start"
>
{viewsList?.map((view) => (
<CustomMenu.MenuItem
key={view.id}
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/views/${view.id}`)}
>
<div className="flex items-center gap-1.5">
<PhotoFilterIcon height={12} width={12} />
{truncateText(view.name, 40)}
</div>
</CustomMenu.MenuItem>
))}
{projectViews?.map((viewId) => {
const view = getViewById(viewId);
if (!view) return;
return (
<CustomMenu.MenuItem
key={viewId}
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/views/${viewId}`)}
>
<div className="flex items-center gap-1.5">
<PhotoFilterIcon height={12} width={12} />
{truncateText(view.name, 40)}
</div>
</CustomMenu.MenuItem>
);
})}
</CustomMenu>
}
/>

View File

@ -8,7 +8,7 @@ import { Breadcrumbs, PhotoFilterIcon, Button } from "@plane/ui";
// helpers
import { renderEmoji } from "helpers/emoji.helper";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const ProjectViewsHeader: React.FC = observer(() => {
// router
@ -24,7 +24,7 @@ export const ProjectViewsHeader: React.FC = observer(() => {
const { currentProjectDetails } = useProject();
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<>

View File

@ -3,10 +3,9 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import DatePicker from "react-datepicker";
import { Popover } from "@headlessui/react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// hooks
import { useUser } from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider";
import useToast from "hooks/use-toast";
// components
import {
@ -22,22 +21,25 @@ import { Button } from "@plane/ui";
import { CheckCircle2, ChevronDown, ChevronUp, Clock, FileStack, Inbox, Trash2, XCircle } from "lucide-react";
// types
import type { TInboxStatus } from "types";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const InboxActionsHeader = observer(() => {
// states
const [date, setDate] = useState(new Date());
const [selectDuplicateIssue, setSelectDuplicateIssue] = useState(false);
const [acceptIssueModal, setAcceptIssueModal] = useState(false);
const [declineIssueModal, setDeclineIssueModal] = useState(false);
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
// router
const router = useRouter();
const { workspaceSlug, projectId, inboxId, inboxIssueId } = router.query;
// store hooks
const { inboxIssues: inboxIssuesStore, inboxIssueDetails: inboxIssueDetailsStore } = useMobxStore();
const {
currentUser,
membership: { currentProjectRole },
} = useUser();
const { inboxIssues: inboxIssuesStore, inboxIssueDetails: inboxIssueDetailsStore, user: userStore } = useMobxStore();
const user = userStore?.currentUser;
const userRole = userStore.currentProjectRole;
const issuesList = inboxId ? inboxIssuesStore.inboxIssues[inboxId.toString()] : null;
const { setToastAlert } = useToast();
@ -72,7 +74,7 @@ export const InboxActionsHeader = observer(() => {
}, [issue]);
const issueStatus = issue?.issue_inbox[0].status;
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const today = new Date();
const tomorrow = new Date(today);
@ -228,7 +230,7 @@ export const InboxActionsHeader = observer(() => {
</Button>
</div>
)}
{(isAllowed || user?.id === issue?.created_by) && (
{(isAllowed || currentUser?.id === issue?.created_by) && (
<div className="flex-shrink-0">
<Button
variant="neutral-primary"

View File

@ -16,7 +16,7 @@ import { Loader, StateGroupIcon } from "@plane/ui";
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
// types
import { IInboxIssue, IIssue } from "types";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
const defaultValues: Partial<IInboxIssue> = {
name: "",
@ -151,7 +151,7 @@ export const InboxMainContent: React.FC = observer(() => {
</div>
);
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<>

View File

@ -17,7 +17,7 @@ import {
IViewIssuesFilterStore,
} from "store_legacy/issues";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
issuesFilterStore:
@ -50,7 +50,7 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
} = useMobxStore();
const { enableIssueCreation } = issueStore?.viewFlags || {};
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const calendarPayload = calendarStore.calendarPayload;

View File

@ -16,7 +16,7 @@ import emptyIssue from "public/empty-state/issue.svg";
import { ISearchIssueResponse } from "types";
import { EProjectStore } from "store_legacy/command-palette.store";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
workspaceSlug: string | undefined;
@ -54,7 +54,7 @@ export const CycleEmptyState: React.FC<Props> = observer((props) => {
});
};
const isEditingAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!userRole && userRole >= EUserProjectRoles.MEMBER;
return (
<>

View File

@ -15,7 +15,7 @@ import emptyIssue from "public/empty-state/issue.svg";
// types
import { ISearchIssueResponse } from "types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
workspaceSlug: string | undefined;
@ -53,7 +53,7 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
);
};
const isEditingAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!userRole && userRole >= EUserProjectRoles.MEMBER;
return (
<>

View File

@ -5,7 +5,7 @@ import { useApplication, useUser } from "hooks/store";
// components
import { NewEmptyState } from "components/common/new-empty-state";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
// assets
import emptyIssue from "public/empty-state/empty_issues.webp";
import { EProjectStore } from "store_legacy/command-palette.store";
@ -20,7 +20,7 @@ export const ProjectEmptyState: React.FC = observer(() => {
membership: { currentProjectRole },
} = useUser();
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<div className="grid h-full w-full place-items-center">

View File

@ -17,7 +17,7 @@ import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
// types
import { IIssueFilterOptions, IIssueLabel, IProject, IState, IUserLite } from "types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
appliedFilters: IIssueFilterOptions;
@ -43,7 +43,7 @@ export const AppliedFiltersList: React.FC<Props> = observer((props) => {
if (Object.keys(appliedFilters).length === 0) return null;
const isEditingAllowed = currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<div className="flex flex-wrap items-stretch gap-2 bg-custom-background-100">

View File

@ -1,6 +1,7 @@
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
// mobx store
// hooks
import { useProjectView } from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { AppliedFiltersList } from "components/issues";
@ -13,22 +14,23 @@ import { IIssueFilterOptions } from "types";
import { EFilterType } from "store_legacy/issues/types";
export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
// router
const router = useRouter();
const { workspaceSlug, projectId, viewId } = router.query as {
workspaceSlug: string;
projectId: string;
viewId: string;
};
// store hooks
const {
projectLabel: { projectLabels },
projectState: projectStateStore,
projectMember: { projectMembers },
projectViews: projectViewsStore,
viewIssuesFilter: { issueFilters, updateFilters },
} = useMobxStore();
const { getViewById, updateView } = useProjectView();
const viewDetails = viewId ? projectViewsStore.viewDetails[viewId.toString()] : undefined;
const viewDetails = viewId ? getViewById(viewId.toString()) : null;
const userFilters = issueFilters?.filters;
// filters whose value not null or empty array
@ -83,7 +85,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
const handleUpdateView = () => {
if (!workspaceSlug || !projectId || !viewId || !viewDetails) return;
projectViewsStore.updateView(workspaceSlug.toString(), projectId.toString(), viewId.toString(), {
updateView(workspaceSlug.toString(), projectId.toString(), viewId.toString(), {
query_data: {
...viewDetails.query_data,
...(appliedFilters ?? {}),

View File

@ -25,7 +25,7 @@ import {
IViewIssuesStore,
} from "store_legacy/issues";
import { TUnGroupedIssues } from "store_legacy/issues/types";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
interface IBaseGanttRoot {
issueFiltersStore:
@ -70,7 +70,7 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
await issueStore.updateIssue(workspaceSlug.toString(), projectId, issueId, payload, viewId);
};
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<>

View File

@ -30,7 +30,7 @@ import { KanBan } from "./default";
import { KanBanSwimLanes } from "./swimlanes";
import { EProjectStore } from "store_legacy/command-palette.store";
import { DeleteIssueModal, IssuePeekOverview } from "components/issues";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export interface IBaseKanBanLayout {
issueStore:
@ -118,7 +118,7 @@ export const BaseKanBanRoot: React.FC<IBaseKanBanLayout> = observer((props: IBas
const [dragState, setDragState] = useState<KanbanDragState>({});
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const canEditProperties = useCallback(
(projectId: string | undefined) => {

View File

@ -10,7 +10,7 @@ import { IIssue } from "types";
import { EIssueActions } from "../../types";
import { BaseKanBanRoot } from "../base-kanban-root";
import { EProjectStore } from "store_legacy/command-palette.store";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const ProfileIssuesKanBanLayout: React.FC = observer(() => {
const router = useRouter();
@ -39,7 +39,7 @@ export const ProfileIssuesKanBanLayout: React.FC = observer(() => {
const canEditPropertiesBasedOnProject = (projectId: string) => {
const currentProjectRole = currentWorkspaceUserProjectsRole && currentWorkspaceUserProjectsRole[projectId];
return !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
return !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
};
return (

View File

@ -25,7 +25,7 @@ import { IIssueResponse } from "store_legacy/issues/types";
import { EProjectStore } from "store_legacy/command-palette.store";
import { IssuePeekOverview } from "components/issues";
import { useRouter } from "next/router";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
enum EIssueActions {
UPDATE = "update",
@ -86,7 +86,7 @@ export const BaseListRoot = observer((props: IBaseListRoot) => {
} = useMobxStore();
const { currentProjectRole } = userStore;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const issueIds = issueStore?.getIssuesIds || [];
const issues = issueStore?.getIssues;

View File

@ -12,7 +12,7 @@ import { EIssueActions } from "../../types";
import { BaseListRoot } from "../base-list-root";
import { IProjectStore } from "store_legacy/project";
import { EProjectStore } from "store_legacy/command-palette.store";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const ProfileIssuesListLayout: FC = observer(() => {
const router = useRouter();
@ -46,9 +46,9 @@ export const ProfileIssuesListLayout: FC = observer(() => {
console.log(
projectId,
currentWorkspaceUserProjectsRole,
!!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER
!!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER
);
return !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
return !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
};
return (

View File

@ -14,7 +14,7 @@ import { IIssue } from "types";
import { IQuickActionProps } from "../list/list-view-types";
import { EProjectStore } from "store_legacy/command-palette.store";
// constant
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const ProjectIssueQuickActions: React.FC<IQuickActionProps> = (props) => {
const { issue, handleDelete, handleUpdate, customActionButton } = props;
@ -30,7 +30,7 @@ export const ProjectIssueQuickActions: React.FC<IQuickActionProps> = (props) =>
membership: { currentProjectRole },
} = useUser();
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const { setToastAlert } = useToast();

View File

@ -16,7 +16,7 @@ import { IIssueUnGroupedStructure } from "store_legacy/issue";
import { EIssueActions } from "../types";
import { EFilterType, TUnGroupedIssues } from "store_legacy/issues/types";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
type?: TStaticViewTypes | null;
@ -62,7 +62,7 @@ export const AllIssueLayoutRoot: React.FC<Props> = observer((props) => {
const currentProjectRole = currentWorkspaceUserProjectsRole && currentWorkspaceUserProjectsRole[projectId];
return !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
return !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
};
const issuesResponse = getIssues;

View File

@ -18,7 +18,7 @@ import { observer } from "mobx-react-lite";
import { EFilterType, TUnGroupedIssues } from "store_legacy/issues/types";
import { EIssueActions } from "../types";
import { IQuickActionProps } from "../list/list-view-types";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
interface IBaseSpreadsheetRoot {
issueFiltersStore:
@ -53,7 +53,7 @@ export const BaseSpreadsheetRoot = observer((props: IBaseSpreadsheetRoot) => {
const { enableInlineEditing, enableQuickAdd, enableIssueCreation } = issueStore?.viewFlags || {};
const { currentProjectRole } = userStore;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const canEditProperties = (projectId: string | undefined) => {
const isEditingAllowedBasedOnProject =

View File

@ -27,7 +27,7 @@ import { IIssue, IIssueActivity } from "types";
// fetch-keys
import { PROJECT_ISSUES_ACTIVITY, SUB_ISSUES } from "constants/fetch-keys";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
issueDetails: IIssue;
@ -151,7 +151,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
);
};
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<>

View File

@ -16,7 +16,7 @@ import { IIssue, IUser } from "types";
// services
import { FileService } from "services/file.service";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
const fileService = new FileService();
@ -48,7 +48,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
const {
membership: { currentProjectRole },
} = useUser();
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
// states
const [characterLimit, setCharacterLimit] = useState(false);
// hooks

View File

@ -23,7 +23,7 @@ import { LinkModal, LinksList } from "components/core";
// types
import { IIssue, TIssuePriorities, ILinkDetails, IIssueLink } from "types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
interface IPeekOverviewProperties {
issue: IIssue;
@ -295,10 +295,10 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
handleDeleteLink={issueLinkDelete}
handleEditLink={handleEditLink}
userAuth={{
isGuest: currentProjectRole === EUserWorkspaceRoles.GUEST,
isViewer: currentProjectRole === EUserWorkspaceRoles.VIEWER,
isMember: currentProjectRole === EUserWorkspaceRoles.MEMBER,
isOwner: currentProjectRole === EUserWorkspaceRoles.ADMIN,
isGuest: currentProjectRole === EUserProjectRoles.GUEST,
isViewer: currentProjectRole === EUserProjectRoles.VIEWER,
isMember: currentProjectRole === EUserProjectRoles.MEMBER,
isOwner: currentProjectRole === EUserProjectRoles.ADMIN,
}}
/>
) : null}

View File

@ -12,7 +12,7 @@ import { copyUrlToClipboard } from "helpers/string.helper";
// types
import { IIssue, IIssueLink } from "types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
interface IIssuePeekOverview {
workspaceSlug: string;
@ -146,7 +146,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
}
};
const userRole = currentProjectRole ?? EUserWorkspaceRoles.GUEST;
const userRole = currentProjectRole ?? EUserProjectRoles.GUEST;
return (
<Fragment>

View File

@ -40,7 +40,7 @@ import { copyTextToClipboard } from "helpers/string.helper";
import type { IIssue, IIssueLink, ILinkDetails } from "types";
// fetch-keys
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
control: any;
@ -191,7 +191,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
setLinkModal(true);
};
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const currentIssueState = projectStates?.find((s) => s.id === issueDetail?.state);

View File

@ -22,7 +22,8 @@ import { IUser, IIssue, ISearchIssueResponse } from "types";
import { IssueService } from "services/issue";
// fetch keys
import { SUB_ISSUES } from "constants/fetch-keys";
import { EUserWorkspaceRoles } from "constants/workspace";
// constants
import { EUserProjectRoles } from "constants/project";
export interface ISubIssuesRoot {
parentIssue: IIssue;
@ -178,7 +179,7 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
[updateIssueStructure, projectId, updateIssue, user, workspaceSlug]
);
const isEditable = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditable = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const mutateSubIssues = (parentIssueId: string | null) => {
if (parentIssueId) mutate(SUB_ISSUES(parentIssueId));

View File

@ -15,7 +15,7 @@ import { copyUrlToClipboard } from "helpers/string.helper";
import { renderShortDate, renderShortMonthDate } from "helpers/date-time.helper";
// constants
import { MODULE_STATUS } from "constants/module";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
moduleId: string;
@ -38,7 +38,7 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
const { getModuleById, addModuleToFavorites, removeModuleFromFavorites } = useModule();
// derived values
const moduleDetails = getModuleById(moduleId);
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const handleAddToFavorites = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();

View File

@ -15,7 +15,7 @@ import { copyUrlToClipboard } from "helpers/string.helper";
import { renderShortDate, renderShortMonthDate } from "helpers/date-time.helper";
// constants
import { MODULE_STATUS } from "constants/module";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
moduleId: string;
@ -38,7 +38,7 @@ export const ModuleListItem: React.FC<Props> = observer((props) => {
const { getModuleById, addModuleToFavorites, removeModuleFromFavorites } = useModule();
// derived values
const moduleDetails = getModuleById(moduleId);
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const handleAddToFavorites = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();

View File

@ -9,7 +9,7 @@ import { ModuleCardItem, ModuleListItem, ModulePeekOverview, ModulesListGanttCha
// ui
import { Loader } from "@plane/ui";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
// assets
import emptyModule from "public/empty-state/empty_modules.webp";
import { NewEmptyState } from "components/common/new-empty-state";
@ -27,7 +27,7 @@ export const ModulesListView: React.FC = observer(() => {
const { storedValue: modulesView } = useLocalStorage("modules_view", "grid");
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
if (!projectModules)
return (

View File

@ -28,7 +28,7 @@ import { copyUrlToClipboard } from "helpers/string.helper";
import { ILinkDetails, IModule, ModuleLink } from "types";
// constant
import { MODULE_STATUS } from "constants/module";
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
const defaultValues: Partial<IModule> = {
lead: "",
@ -255,7 +255,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
: `${moduleDetails.total_issues}`
: `${moduleDetails.completed_issues}/${moduleDetails.total_issues}`;
const isEditingAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<>
@ -583,10 +583,10 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
handleEditLink={handleEditLink}
handleDeleteLink={handleDeleteLink}
userAuth={{
isGuest: currentProjectRole === EUserWorkspaceRoles.GUEST,
isViewer: currentProjectRole === EUserWorkspaceRoles.VIEWER,
isMember: currentProjectRole === EUserWorkspaceRoles.MEMBER,
isOwner: currentProjectRole === EUserWorkspaceRoles.ADMIN,
isGuest: currentProjectRole === EUserProjectRoles.GUEST,
isViewer: currentProjectRole === EUserProjectRoles.VIEWER,
isMember: currentProjectRole === EUserProjectRoles.MEMBER,
isOwner: currentProjectRole === EUserProjectRoles.ADMIN,
}}
/>
</>

View File

@ -9,7 +9,7 @@ import { TourRoot } from "components/onboarding";
import { UserGreetingsView } from "components/user";
import { CompletedIssuesGraph, IssuesList, IssuesPieChart, IssuesStats } from "components/workspace";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
// images
import { NewEmptyState } from "components/common/new-empty-state";
import emptyProject from "public/empty-state/dashboard_empty_project.webp";
@ -25,7 +25,13 @@ export const WorkspaceDashboardView = observer(() => {
commandPalette: commandPaletteStore,
eventTracker: { setTrackElement, postHogEventTracker },
} = useApplication();
const { currentUser, dashboardInfo: workspaceDashboardInfo, fetchUserDashboardInfo, updateTourCompleted } = useUser();
const {
currentUser,
dashboardInfo: workspaceDashboardInfo,
fetchUserDashboardInfo,
updateTourCompleted,
membership: { currentProjectRole },
} = useUser();
const { workspaceProjects } = useProject();
// fetch user dashboard info
useSWR(
@ -33,7 +39,7 @@ export const WorkspaceDashboardView = observer(() => {
workspaceSlug ? () => fetchUserDashboardInfo(workspaceSlug.toString(), month) : null
);
const isEditingAllowed = !!userStore.currentProjectRole && userStore.currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const handleTourCompleted = () => {
updateTourCompleted()

View File

@ -26,7 +26,7 @@ import { CustomMenu, Tooltip } from "@plane/ui";
// components
import { CreateUpdatePageModal, DeletePageModal } from "components/pages";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export interface IPagesListItem {
workspaceSlug: string;
@ -168,11 +168,11 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
const userCanEdit =
isCurrentUserOwner ||
(currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole));
(currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole));
const userCanChangeAccess = isCurrentUserOwner;
const userCanArchive = isCurrentUserOwner || currentProjectRole === EUserWorkspaceRoles.ADMIN;
const userCanDelete = isCurrentUserOwner || currentProjectRole === EUserWorkspaceRoles.ADMIN;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const userCanArchive = isCurrentUserOwner || currentProjectRole === EUserProjectRoles.ADMIN;
const userCanDelete = isCurrentUserOwner || currentProjectRole === EUserProjectRoles.ADMIN;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<>

View File

@ -12,7 +12,7 @@ import { Loader } from "@plane/ui";
// images
import emptyPage from "public/empty-state/empty_page.png";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type IPagesListView = {
pages: string[];
@ -31,7 +31,7 @@ export const PagesListView: FC<IPagesListView> = observer((props) => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<>

View File

@ -13,7 +13,7 @@ import emptyPage from "public/empty-state/empty_page.png";
// helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const RecentPagesList: FC = observer(() => {
// store hooks
@ -25,7 +25,7 @@ export const RecentPagesList: FC = observer(() => {
const isEmpty = recentProjectPages && Object.values(recentProjectPages).every((value) => value.length === 0);
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
if (!recentProjectPages) {
return (

View File

@ -9,7 +9,7 @@ import emptyProject from "public/empty-state/empty_project.webp";
// icons
import { NewEmptyState } from "components/common/new-empty-state";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const ProjectCardList = observer(() => {
// store hooks
@ -22,7 +22,7 @@ export const ProjectCardList = observer(() => {
} = useUser();
const { workspaceProjects, searchedProjects, getProjectById } = useProject();
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
if (!workspaceProjects)
return (

View File

@ -15,7 +15,8 @@ import { ChevronDown, Dot, XCircle } from "lucide-react";
// constants
import { EUserWorkspaceRoles, ROLE } from "constants/workspace";
// types
import { IProjectMember, TUserProjectRole } from "types";
import { IProjectMember } from "types";
import { EUserProjectRoles } from "constants/project";
type Props = {
member: IProjectMember;
@ -136,7 +137,7 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
</div>
}
value={member.role}
onChange={(value: TUserProjectRole | undefined) => {
onChange={(value: EUserProjectRoles | undefined) => {
if (!workspaceSlug || !projectId) return;
updateMember(workspaceSlug.toString(), projectId.toString(), member.id, {

View File

@ -15,7 +15,7 @@ import { IProject, IUserLite, IWorkspace } from "types";
// fetch-keys
import { PROJECT_MEMBERS } from "constants/fetch-keys";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
const defaultValues: Partial<IProject> = {
project_lead: null,
@ -32,7 +32,7 @@ export const ProjectSettingsMemberDefaults: React.FC = observer(() => {
} = useUser();
const { currentProjectDetails, fetchProjectDetails, updateProject } = useProject();
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
const isAdmin = currentProjectRole === EUserProjectRoles.ADMIN;
// hooks
const { setToastAlert } = useToast();
// form info

View File

@ -13,9 +13,10 @@ import { Avatar, Button, CustomSelect, CustomSearchSelect } from "@plane/ui";
// services
import { ProjectMemberService } from "services/project";
// types
import { IProjectMember, TUserProjectRole } from "types";
import { IProjectMember } from "types";
// constants
import { EUserWorkspaceRoles, ROLE } from "constants/workspace";
import { ROLE } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
isOpen: boolean;
@ -25,7 +26,7 @@ type Props = {
};
type member = {
role: TUserProjectRole;
role: EUserProjectRoles;
member_id: string;
};
@ -267,8 +268,7 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
width="w-full"
>
{Object.entries(ROLE).map(([key, label]) => {
if (parseInt(key) > (currentProjectRole ?? EUserWorkspaceRoles.GUEST))
return null;
if (parseInt(key) > (currentProjectRole ?? EUserProjectRoles.GUEST)) return null;
return (
<CustomSelect.Option key={key} value={key}>

View File

@ -9,7 +9,7 @@ import useToast from "hooks/use-toast";
// types
import { IProject } from "types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {};
@ -60,7 +60,7 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
} = useUser();
const { currentWorkspace } = useWorkspace();
const { currentProjectDetails, updateProject } = useProject();
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
const isAdmin = currentProjectRole === EUserProjectRoles.ADMIN;
// toast alert
const { setToastAlert } = useToast();

View File

@ -2,15 +2,12 @@ import React, { useState } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { Dialog, Transition } from "@headlessui/react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { AlertTriangle } from "lucide-react";
// hooks
import { useProjectView } from "hooks/store";
import useToast from "hooks/use-toast";
// ui
import { Button } from "@plane/ui";
// icons
import { AlertTriangle } from "lucide-react";
// types
import { IProjectView } from "types";
@ -22,14 +19,14 @@ type Props = {
export const DeleteProjectViewModal: React.FC<Props> = observer((props) => {
const { data, isOpen, onClose } = props;
// states
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const { projectViews: projectViewsStore } = useMobxStore();
// store hooks
const { deleteView } = useProjectView();
// toast alert
const { setToastAlert } = useToast();
const handleClose = () => {
@ -42,8 +39,7 @@ export const DeleteProjectViewModal: React.FC<Props> = observer((props) => {
setIsDeleteLoading(true);
await projectViewsStore
.deleteView(workspaceSlug.toString(), projectId.toString(), data.id)
await deleteView(workspaceSlug.toString(), projectId.toString(), data.id)
.then(() => {
handleClose();

View File

@ -1,14 +1,14 @@
import { FC, Fragment } from "react";
import { observer } from "mobx-react-lite";
import { Dialog, Transition } from "@headlessui/react";
import { debounce } from "lodash";
// hooks
import { useMobxStore } from "lib/mobx/store-provider";
import { useProjectView } from "hooks/store";
import useToast from "hooks/use-toast";
// components
import { ProjectViewForm } from "components/views";
// types
import { IProjectView } from "types";
import { debounce } from "lodash";
type Props = {
data?: IProjectView | null;
@ -21,18 +21,17 @@ type Props = {
export const CreateUpdateProjectViewModal: FC<Props> = observer((props) => {
const { data, isOpen, onClose, preLoadedData, workspaceSlug, projectId } = props;
// store
const { projectViews: projectViewsStore } = useMobxStore();
// hooks
// store hooks
const { createView, updateView } = useProjectView();
// toast alert
const { setToastAlert } = useToast();
const handleClose = () => {
onClose();
};
const createView = async (payload: IProjectView) => {
await projectViewsStore
.createView(workspaceSlug, projectId, payload)
const handleCreateView = async (payload: IProjectView) => {
await createView(workspaceSlug, projectId, payload)
.then(() => {
console.log("after calling store");
handleClose();
@ -52,9 +51,8 @@ export const CreateUpdateProjectViewModal: FC<Props> = observer((props) => {
);
};
const updateView = async (payload: IProjectView) => {
await projectViewsStore
.updateView(workspaceSlug, projectId, data?.id as string, payload)
const handleUpdateView = async (payload: IProjectView) => {
await updateView(workspaceSlug, projectId, data?.id as string, payload)
.then(() => handleClose())
.catch((err) =>
setToastAlert({
@ -66,8 +64,8 @@ export const CreateUpdateProjectViewModal: FC<Props> = observer((props) => {
};
const handleFormSubmit = async (formData: IProjectView) => {
if (!data) await createView(formData);
else await updateView(formData);
if (!data) await handleCreateView(formData);
else await handleUpdateView(formData);
};
const debouncedFormSubmit = debounce(handleFormSubmit, 10, { leading: false, trailing: true });

View File

@ -4,8 +4,7 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { LinkIcon, PencilIcon, StarIcon, TrashIcon } from "lucide-react";
// hooks
import { useUser } from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider";
import { useProjectView, useUser } from "hooks/store";
import useToast from "hooks/use-toast";
// components
import { CreateUpdateProjectViewModal, DeleteProjectViewModal } from "components/views";
@ -17,7 +16,7 @@ import { copyUrlToClipboard } from "helpers/string.helper";
// types
import { IProjectView } from "types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
type Props = {
view: IProjectView;
@ -34,21 +33,21 @@ export const ProjectViewListItem: React.FC<Props> = observer((props) => {
// toast alert
const { setToastAlert } = useToast();
// store hooks
const { projectViews: projectViewsStore } = useMobxStore();
const {
membership: { currentProjectRole },
} = useUser();
const { addViewToFavorites, removeViewFromFavorites } = useProjectView();
const handleAddToFavorites = () => {
if (!workspaceSlug || !projectId) return;
projectViewsStore.addViewToFavorites(workspaceSlug.toString(), projectId.toString(), view.id);
addViewToFavorites(workspaceSlug.toString(), projectId.toString(), view.id);
};
const handleRemoveFromFavorites = () => {
if (!workspaceSlug || !projectId) return;
projectViewsStore.removeViewFromFavorites(workspaceSlug.toString(), projectId.toString(), view.id);
removeViewFromFavorites(workspaceSlug.toString(), projectId.toString(), view.id);
};
const handleCopyText = (e: React.MouseEvent<HTMLButtonElement>) => {
@ -65,7 +64,7 @@ export const ProjectViewListItem: React.FC<Props> = observer((props) => {
const totalFilters = calculateTotalFilters(view.query_data ?? {});
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return (
<>

View File

@ -1,10 +1,8 @@
import { useState } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { Plus, Search } from "lucide-react";
// hooks
import { useApplication, useUser } from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider";
import { useApplication, useProjectView, useUser } from "hooks/store";
// components
import { ProjectViewListItem } from "components/views";
import { NewEmptyState } from "components/common/new-empty-state";
@ -13,28 +11,23 @@ import { Input, Loader } from "@plane/ui";
// assets
import emptyView from "public/empty-state/empty_view.webp";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export const ProjectViewsList = observer(() => {
// states
const [query, setQuery] = useState("");
// router
const router = useRouter();
const { projectId } = router.query;
// store hooks
const { projectViews: projectViewsStore } = useMobxStore();
const {
commandPalette: { toggleCreateViewModal },
} = useApplication();
const {
membership: { currentProjectRole },
} = useUser();
const { projectViews, getViewById } = useProjectView();
const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
if (!viewsList)
if (!projectViews)
return (
<Loader className="space-y-4 p-4">
<Loader.Item height="72px" />
@ -44,7 +37,9 @@ export const ProjectViewsList = observer(() => {
</Loader>
);
const filteredViewsList = viewsList.filter((v) => v.name.toLowerCase().includes(query.toLowerCase()));
const viewsList = projectViews.map((viewId) => getViewById(viewId));
const filteredViewsList = viewsList.filter((v) => v?.name.toLowerCase().includes(query.toLowerCase()));
return (
<>

View File

@ -1,6 +1,13 @@
import { Globe2, Lock, LucideIcon } from "lucide-react";
import { TIssuePriorities } from "types";
export enum EUserProjectRoles {
GUEST = 5,
VIEWER = 10,
MEMBER = 15,
ADMIN = 20,
}
export const NETWORK_CHOICES: { key: 0 | 2; label: string; icon: LucideIcon }[] = [
{
key: 0,
@ -53,7 +60,6 @@ export const PROJECT_AUTOMATION_MONTHS = [
export const STATE_GROUP_KEYS = ["backlog", "unstarted", "started", "completed", "cancelled"];
export const PROJECT_UNSPLASH_COVERS = [
"https://images.unsplash.com/photo-1531045535792-b515d59c3d1f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80",
"https://images.unsplash.com/photo-1693027407934-e3aa8a54c7ae?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80",

View File

@ -5,6 +5,7 @@ export * from "./use-module";
export * from "./use-page";
export * from "./use-project-publish";
export * from "./use-project-state";
export * from "./use-project-view";
export * from "./use-project";
export * from "./use-user";
export * from "./use-webhook";

View File

@ -0,0 +1,11 @@
import { useContext } from "react";
// mobx store
import { MobxStoreContext } from "lib/mobx/store-provider";
// types
import { IProjectViewStore } from "store/project-view.store";
export const useProjectView = (): IProjectViewStore => {
const context = useContext(MobxStoreContext);
if (context === undefined) throw new Error("useMobxStore must be used within MobxStoreProvider");
return context.projectView;
};

View File

@ -3,7 +3,16 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import useSWR from "swr";
// hooks
import { useApplication, useCycle, useLabel, useModule, useProjectState, useUser } from "hooks/store";
import {
useApplication,
useCycle,
useLabel,
useModule,
useProject,
useProjectState,
useProjectView,
useUser,
} from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { Spinner } from "@plane/ui";
@ -20,10 +29,8 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
const { children } = props;
// store
const {
project: { fetchProjectDetails, workspaceProjects },
projectMember: { fetchProjectMembers },
projectEstimates: { fetchProjectEstimates },
projectViews: { fetchAllViews },
inbox: { fetchInboxesList, isInboxEnabled },
} = useMobxStore();
const {
@ -32,8 +39,10 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
const {
membership: { fetchUserProjectInfo, projectMemberInfo, hasPermissionToProject },
} = useUser();
const { getProjectById, fetchProjectDetails } = useProject();
const { fetchAllCycles } = useCycle();
const { fetchModules } = useModule();
const { fetchViews } = useProjectView();
const { fetchProjectStates } = useProjectState();
const {
project: { fetchProjectLabels },
@ -85,7 +94,7 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
// fetching project views
useSWR(
workspaceSlug && projectId ? `PROJECT_VIEWS_${workspaceSlug}_${projectId}` : null,
workspaceSlug && projectId ? () => fetchAllViews(workspaceSlug.toString(), projectId.toString()) : null
workspaceSlug && projectId ? () => fetchViews(workspaceSlug.toString(), projectId.toString()) : null
);
// fetching project inboxes if inbox is enabled
useSWR(
@ -99,8 +108,7 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
}
);
const projectsList = workspaceSlug ? workspaceProjects : null;
const projectExists = projectId ? projectsList?.find((project) => project.id === projectId.toString()) : null;
const projectExists = projectId ? getProjectById(projectId.toString()) : null;
// check if the project member apis is loading
if (!projectMemberInfo && projectId && hasPermissionToProject[projectId.toString()] === null)

View File

@ -9,7 +9,7 @@ import { NotAuthorizedView } from "components/auth-screens";
// ui
import { Button, LayersIcon } from "@plane/ui";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
export interface IProjectSettingLayout {
children: ReactNode;
@ -25,7 +25,7 @@ export const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((props)
membership: { currentProjectRole },
} = useUser();
const restrictViewSettings = currentProjectRole && currentProjectRole <= EUserWorkspaceRoles.VIEWER;
const restrictViewSettings = currentProjectRole && currentProjectRole <= EUserProjectRoles.VIEWER;
return restrictViewSettings ? (
<NotAuthorizedView

View File

@ -34,7 +34,7 @@ import { IPage, IIssue } from "types";
// fetch-keys
import { PAGE_DETAILS, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
import { EUserProjectRoles } from "constants/project";
// services
const fileService = new FileService();
@ -362,15 +362,15 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
const isPageReadOnly =
pageDetails?.is_locked ||
pageDetails?.archived_at ||
(currentProjectRole && [EUserWorkspaceRoles.VIEWER, EUserWorkspaceRoles.GUEST].includes(currentProjectRole));
(currentProjectRole && [EUserProjectRoles.VIEWER, EUserProjectRoles.GUEST].includes(currentProjectRole));
const isCurrentUserOwner = pageDetails?.owned_by === currentUser?.id;
const userCanDuplicate =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
const userCanArchive = isCurrentUserOwner || currentProjectRole === EUserWorkspaceRoles.ADMIN;
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
const userCanArchive = isCurrentUserOwner || currentProjectRole === EUserProjectRoles.ADMIN;
const userCanLock =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
return (
<>

View File

@ -14,7 +14,8 @@ import { ProjectSettingHeader } from "components/headers";
// types
import { NextPageWithLayout } from "types/app";
import { IProject } from "types";
import { EUserWorkspaceRoles } from "constants/workspace";
// constants
import { EUserProjectRoles } from "constants/project";
const AutomationSettingsPage: NextPageWithLayout = observer(() => {
// router
@ -40,7 +41,7 @@ const AutomationSettingsPage: NextPageWithLayout = observer(() => {
});
};
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
const isAdmin = currentProjectRole === EUserProjectRoles.ADMIN;
return (
<section className={`w-full overflow-y-auto py-8 pr-9 ${isAdmin ? "" : "opacity-60"}`}>

View File

@ -10,14 +10,15 @@ import { ProjectSettingHeader } from "components/headers";
import { EstimatesList } from "components/estimates";
// types
import { NextPageWithLayout } from "types/app";
import { EUserWorkspaceRoles } from "constants/workspace";
// constants
import { EUserProjectRoles } from "constants/project";
const EstimatesSettingsPage: NextPageWithLayout = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
const isAdmin = currentProjectRole === EUserProjectRoles.ADMIN;
return (
<div className={`w-full overflow-y-auto py-8 pr-9 ${isAdmin ? "" : "pointer-events-none opacity-60"}`}>

View File

@ -1,8 +1,8 @@
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// hooks
import { useProjectView } from "hooks/store";
// layouts
import { AppLayout } from "layouts/app-layout";
// components
@ -16,15 +16,16 @@ import emptyView from "public/empty-state/view.svg";
import { NextPageWithLayout } from "types/app";
const ProjectViewIssuesPage: NextPageWithLayout = () => {
// router
const router = useRouter();
const { workspaceSlug, projectId, viewId } = router.query;
const { projectViews: projectViewsStore } = useMobxStore();
// store hooks
const { fetchViewDetails } = useProjectView();
const { error } = useSWR(
workspaceSlug && projectId && viewId ? `VIEW_DETAILS_${viewId.toString()}` : null,
workspaceSlug && projectId && viewId
? () => projectViewsStore.fetchViewDetails(workspaceSlug.toString(), projectId.toString(), viewId.toString())
? () => fetchViewDetails(workspaceSlug.toString(), projectId.toString(), viewId.toString())
: null
);

View File

@ -1,8 +1,4 @@
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { ProjectViewsHeader } from "components/headers";
import { ProjectViewsList } from "components/views";
@ -11,21 +7,7 @@ import { AppLayout } from "layouts/app-layout";
// types
import { NextPageWithLayout } from "types/app";
const ProjectViewsPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
// store
const {
projectViews: { fetchAllViews },
} = useMobxStore();
useSWR(
workspaceSlug && projectId ? `PROJECT_VIEWS_LIST_${workspaceSlug.toString()}_${projectId.toString()}` : null,
workspaceSlug && projectId ? () => fetchAllViews(workspaceSlug.toString(), projectId.toString()) : null
);
return <ProjectViewsList />;
};
const ProjectViewsPage: NextPageWithLayout = () => <ProjectViewsList />;
ProjectViewsPage.getLayout = function getLayout(page: ReactElement) {
return (

View File

@ -19,11 +19,7 @@ export class CycleService extends APIService {
});
}
async getCyclesWithParams(
workspaceSlug: string,
projectId: string,
cycleType?: "current"
): Promise<Record<string, ICycle>> {
async getCyclesWithParams(workspaceSlug: string, projectId: string, cycleType?: "current"): Promise<ICycle[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, {
params: {
cycle_view: cycleType,

View File

@ -10,7 +10,7 @@ export class ModuleService extends APIService {
super(API_BASE_URL);
}
async getModules(workspaceSlug: string, projectId: string): Promise<Record<string, IModule>> {
async getModules(workspaceSlug: string, projectId: string): Promise<IModule[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`)
.then((response) => response?.data)
.catch((error) => {

View File

@ -2,7 +2,7 @@ import { API_BASE_URL } from "helpers/common.helper";
// services
import { APIService } from "services/api.service";
// types
import { IPage, IPageBlock, RecentPagesResponse, IIssue } from "types";
import { IPage, IPageBlock, IIssue } from "types";
export class PageService extends APIService {
constructor() {
@ -50,7 +50,7 @@ export class PageService extends APIService {
});
}
async getProjectPages(workspaceSlug: string, projectId: string): Promise<Record<string, IPage>> {
async getProjectPages(workspaceSlug: string, projectId: string): Promise<IPage[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`)
.then((response) => response?.data)
.catch((error) => {
@ -74,18 +74,6 @@ export class PageService extends APIService {
});
}
async getRecentPages(workspaceSlug: string, projectId: string): Promise<RecentPagesResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, {
params: {
page_view: "recent",
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getPageDetails(workspaceSlug: string, projectId: string, pageId: string): Promise<IPage> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`)
.then((response) => response?.data)
@ -189,7 +177,7 @@ export class PageService extends APIService {
});
}
async getArchivedPages(workspaceSlug: string, projectId: string): Promise<Record<string, IPage>> {
async getArchivedPages(workspaceSlug: string, projectId: string): Promise<IPage[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-pages/`)
.then((response) => response?.data)
.catch((error) => {

View File

@ -2,7 +2,7 @@ import { API_BASE_URL } from "helpers/common.helper";
// services
import { APIService } from "services/api.service";
// types
import type { IProjectBulkAddFormData, IProjectMember, IProjectMemberInvitation } from "types";
import type { IProjectBulkAddFormData, IProjectMember } from "types";
export class ProjectMemberService extends APIService {
constructor() {

View File

@ -36,7 +36,7 @@ export class ProjectService extends APIService {
});
}
async getProjects(workspaceSlug: string): Promise<Record<string, IProject>> {
async getProjects(workspaceSlug: string): Promise<IProject[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/`)
.then((response) => response?.data)
.catch((error) => {

View File

@ -23,7 +23,7 @@ export class WorkspaceService extends APIService {
super(API_BASE_URL);
}
async userWorkspaces(): Promise<Record<string, IWorkspace>> {
async userWorkspaces(): Promise<IWorkspace[]> {
return this.get("/api/users/me/workspaces/")
.then((response) => response?.data)
.catch((error) => {

View File

@ -15,12 +15,8 @@ export interface ICycleStore {
loader: boolean;
error: any | null;
// observables
cycleMap: {
[cycleId: string]: ICycle;
};
activeCycleMap: {
[cycleId: string]: ICycle;
};
cycleMap: Record<string, ICycle>;
activeCycleMap: Record<string, ICycle>;
// computed
projectAllCycles: string[] | null;
projectCompletedCycles: string[] | null;
@ -32,8 +28,8 @@ export interface ICycleStore {
getActiveCycleById: (cycleId: string) => ICycle | null;
// actions
validateDate: (workspaceSlug: string, projectId: string, payload: CycleDateCheckData) => Promise<any>;
fetchAllCycles: (workspaceSlug: string, projectId: string) => Promise<Record<string, ICycle>>;
fetchActiveCycle: (workspaceSlug: string, projectId: string) => Promise<Record<string, ICycle>>;
fetchAllCycles: (workspaceSlug: string, projectId: string) => Promise<ICycle[]>;
fetchActiveCycle: (workspaceSlug: string, projectId: string) => Promise<ICycle[]>;
fetchCycleDetails: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<ICycle>;
createCycle: (workspaceSlug: string, projectId: string, data: Partial<ICycle>) => Promise<ICycle>;
updateCycleDetails: (
@ -52,10 +48,8 @@ export class CycleStore implements ICycleStore {
loader: boolean = false;
error: any | null = null;
// observables
cycleMap: {
[cycleId: string]: ICycle;
} = {};
activeCycleMap: { [cycleId: string]: ICycle } = {};
cycleMap: Record<string, ICycle> = {};
activeCycleMap: Record<string, ICycle> = {};
// root store
rootStore;
// services
@ -196,7 +190,7 @@ export class CycleStore implements ICycleStore {
const cyclesResponse = await this.cycleService.getCyclesWithParams(workspaceSlug, projectId);
runInAction(() => {
Object.values(cyclesResponse).forEach((cycle) => {
cyclesResponse.forEach((cycle) => {
set(this.cycleMap, [cycle.id], cycle);
});
this.loader = false;
@ -221,7 +215,7 @@ export class CycleStore implements ICycleStore {
const cyclesResponse = await this.cycleService.getCyclesWithParams(workspaceSlug, projectId, "current");
runInAction(() => {
Object.values(cyclesResponse).forEach((cycle) => {
cyclesResponse.forEach((cycle) => {
set(this.activeCycleMap, [cycle.id], cycle);
});
this.loader = false;

View File

@ -12,15 +12,13 @@ export interface IModuleStore {
loader: boolean;
error: any | null;
// observables
moduleMap: {
[moduleId: string]: IModule;
};
moduleMap: Record<string, IModule>;
// computed
projectModules: string[] | null;
// computed actions
getModuleById: (moduleId: string) => IModule | null;
// actions
fetchModules: (workspaceSlug: string, projectId: string) => void;
fetchModules: (workspaceSlug: string, projectId: string) => Promise<IModule[]>;
fetchModuleDetails: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<IModule>;
createModule: (workspaceSlug: string, projectId: string, data: Partial<IModule>) => Promise<IModule>;
updateModuleDetails: (
@ -53,9 +51,7 @@ export class ModulesStore implements IModuleStore {
loader: boolean = false;
error: any | null = null;
// observables
moduleMap: {
[moduleId: string]: IModule;
} = {};
moduleMap: Record<string, IModule> = {};
// root store
rootStore;
// services
@ -108,7 +104,6 @@ export class ModulesStore implements IModuleStore {
getModuleById = (moduleId: string) => this.moduleMap?.[moduleId] || null;
// actions
fetchModules = async (workspaceSlug: string, projectId: string) => {
try {
runInAction(() => {
@ -119,12 +114,14 @@ export class ModulesStore implements IModuleStore {
const modulesResponse = await this.moduleService.getModules(workspaceSlug, projectId);
runInAction(() => {
Object.values(modulesResponse).forEach((module) => {
modulesResponse.forEach((module) => {
set(this.moduleMap, [module.id], module);
});
this.loader = false;
this.error = null;
});
return modulesResponse;
} catch (error) {
console.error("Failed to fetch modules list in module store", error);
@ -132,6 +129,8 @@ export class ModulesStore implements IModuleStore {
this.loader = false;
this.error = error;
});
throw error;
}
};

View File

@ -24,8 +24,8 @@ export interface IPageStore {
getUnArchivedPageById: (pageId: string) => IPage | null;
getArchivedPageById: (pageId: string) => IPage | null;
// fetch actions
fetchProjectPages: (workspaceSlug: string, projectId: string) => Promise<Record<string, IPage>>;
fetchArchivedProjectPages: (workspaceSlug: string, projectId: string) => Promise<Record<string, IPage>>;
fetchProjectPages: (workspaceSlug: string, projectId: string) => Promise<IPage[]>;
fetchArchivedProjectPages: (workspaceSlug: string, projectId: string) => Promise<IPage[]>;
// favorites actions
addToFavorites: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
removeFromFavorites: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
@ -202,10 +202,11 @@ export class PageStore implements IPageStore {
const response = await this.pageService.getProjectPages(workspaceSlug, projectId);
runInAction(() => {
Object.values(response).forEach((page) => {
response.forEach((page) => {
set(this.pages, [page.id], page);
});
});
return response;
} catch (error) {
throw error;
@ -223,7 +224,7 @@ export class PageStore implements IPageStore {
const response = await this.pageService.getArchivedPages(workspaceSlug, projectId);
runInAction(() => {
Object.values(response).forEach((page) => {
response.forEach((page) => {
set(this.archivedPages, [page.id], page);
});
});

View File

@ -1,24 +1,21 @@
import set from "lodash/set";
import { observable, action, makeObservable, runInAction } from "mobx";
import { omit, set } from "lodash";
import { observable, action, makeObservable, runInAction, computed } from "mobx";
// services
import { ViewService } from "services/view.service";
import { RootStore } from "store/root.store";
// types
import { IProjectView } from "types";
export interface IProjectViewsStore {
export interface IProjectViewStore {
// states
loader: boolean;
error: any | null;
// observables
viewId: string | null;
viewMap: {
[projectId: string]: {
[viewId: string]: IProjectView;
};
};
viewMap: Record<string, IProjectView>;
// computed
projectViews: string[] | null;
// computed actions
getViewById: (viewId: string) => IProjectView;
// actions
fetchViews: (workspaceSlug: string, projectId: string) => Promise<IProjectView[]>;
fetchViewDetails: (workspaceSlug: string, projectId: string, viewId: string) => Promise<IProjectView>;
@ -34,22 +31,14 @@ export interface IProjectViewsStore {
removeViewFromFavorites: (workspaceSlug: string, projectId: string, viewId: string) => Promise<any>;
}
export class ProjectViewsStore implements IProjectViewsStore {
export class ProjectViewStore implements IProjectViewStore {
// states
loader: boolean = false;
error: any | null = null;
// observables
viewId: string | null = null;
viewMap: {
[projectId: string]: {
[viewId: string]: IProjectView;
};
} = {};
viewMap: Record<string, IProjectView> = {};
// root store
rootStore;
// services
viewService;
@ -58,11 +47,12 @@ export class ProjectViewsStore implements IProjectViewsStore {
// states
loader: observable.ref,
error: observable.ref,
// observables
viewId: observable.ref,
viewMap: observable,
// computed
projectViews: computed,
// computed actions
getViewById: action,
// actions
fetchViews: action,
fetchViewDetails: action,
@ -78,11 +68,19 @@ export class ProjectViewsStore implements IProjectViewsStore {
this.viewService = new ViewService();
}
setViewId = (viewId: string | null) => {
this.viewId = viewId;
};
get projectViews() {
const projectId = this.rootStore.app.router.projectId;
fetchViews = async (workspaceSlug: string, projectId: string): Promise<IProjectView[]> => {
if (!projectId) return null;
const viewIds = Object.keys(this.viewMap ?? {})?.filter((viewId) => this.viewMap?.[viewId]?.project === projectId);
return viewIds;
}
getViewById = (viewId: string) => this.viewMap?.[viewId] ?? null;
fetchViews = async (workspaceSlug: string, projectId: string) => {
try {
runInAction(() => {
this.loader = true;
@ -92,7 +90,9 @@ export class ProjectViewsStore implements IProjectViewsStore {
runInAction(() => {
this.loader = false;
set(this.viewMap, [projectId], response);
response.forEach((view) => {
set(this.viewMap, [view.id], view);
});
});
return response;
@ -116,7 +116,7 @@ export class ProjectViewsStore implements IProjectViewsStore {
runInAction(() => {
this.loader = false;
set(this.viewMap, [projectId, viewId], response);
set(this.viewMap, [viewId], response);
});
return response;
@ -136,7 +136,7 @@ export class ProjectViewsStore implements IProjectViewsStore {
runInAction(() => {
this.loader = false;
set(this.viewMap, [projectId, response.id], response);
set(this.viewMap, [response.id], response);
});
return response;
@ -156,10 +156,10 @@ export class ProjectViewsStore implements IProjectViewsStore {
data: Partial<IProjectView>
): Promise<IProjectView> => {
try {
const currentView = this.viewMap[projectId][viewId];
const currentView = this.getViewById(viewId);
runInAction(() => {
set(this.viewMap, [projectId, viewId], { ...currentView, ...data });
set(this.viewMap, [viewId], { ...currentView, ...data });
});
const response = await this.viewService.patchView(workspaceSlug, projectId, viewId, data);
@ -178,10 +178,8 @@ export class ProjectViewsStore implements IProjectViewsStore {
deleteView = async (workspaceSlug: string, projectId: string, viewId: string): Promise<any> => {
try {
if (!this.viewMap?.[projectId]?.[viewId]) return;
runInAction(() => {
delete this.viewMap[projectId][viewId];
omit(this.viewMap, [viewId]);
});
await this.viewService.deleteView(workspaceSlug, projectId, viewId);
@ -198,12 +196,12 @@ export class ProjectViewsStore implements IProjectViewsStore {
addViewToFavorites = async (workspaceSlug: string, projectId: string, viewId: string) => {
try {
const currentView = this.viewMap[projectId][viewId];
const currentView = this.getViewById(viewId);
if (currentView.is_favorite) return;
if (currentView?.is_favorite) return;
runInAction(() => {
set(this.viewMap, [projectId, viewId, "is_favorite"], true);
set(this.viewMap, [viewId, "is_favorite"], true);
});
await this.viewService.addViewToFavorites(workspaceSlug, projectId, {
@ -213,19 +211,19 @@ export class ProjectViewsStore implements IProjectViewsStore {
console.error("Failed to add view to favorites in view store", error);
runInAction(() => {
set(this.viewMap, [projectId, viewId, "is_favorite"], false);
set(this.viewMap, [viewId, "is_favorite"], false);
});
}
};
removeViewFromFavorites = async (workspaceSlug: string, projectId: string, viewId: string) => {
try {
const currentView = this.viewMap[projectId][viewId];
const currentView = this.getViewById(viewId);
if (!currentView.is_favorite) return;
if (!currentView?.is_favorite) return;
runInAction(() => {
set(this.viewMap, [projectId, viewId, "is_favorite"], false);
set(this.viewMap, [viewId, "is_favorite"], false);
});
await this.viewService.removeViewFromFavorites(workspaceSlug, projectId, viewId);
@ -233,7 +231,7 @@ export class ProjectViewsStore implements IProjectViewsStore {
console.error("Failed to remove view from favorites in view store", error);
runInAction(() => {
set(this.viewMap, [projectId, viewId, "is_favorite"], true);
set(this.viewMap, [viewId, "is_favorite"], true);
});
}
};

View File

@ -26,7 +26,7 @@ export interface IProjectStore {
setSearchQuery: (query: string) => void;
getProjectById: (projectId: string) => IProject | null;
fetchProjects: (workspaceSlug: string) => Promise<void>;
fetchProjects: (workspaceSlug: string) => Promise<IProject[]>;
fetchProjectDetails: (workspaceSlug: string, projectId: string) => Promise<any>;
addProjectToFavorites: (workspaceSlug: string, projectId: string) => Promise<any>;
@ -146,11 +146,15 @@ export class ProjectStore implements IProjectStore {
*/
fetchProjects = async (workspaceSlug: string) => {
try {
const currentProjectMap = await this.projectService.getProjects(workspaceSlug);
const projectsResponse = await this.projectService.getProjects(workspaceSlug);
runInAction(() => {
this.projectMap = currentProjectMap;
projectsResponse.forEach((project) => {
set(this.projectMap, [project.id], project);
});
});
return projectsResponse;
} catch (error) {
console.log("Failed to fetch project from workspace store");
throw error;

View File

@ -3,7 +3,7 @@ import { enableStaticRendering } from "mobx-react-lite";
import { AppRootStore, IAppRootStore } from "./application";
import { IProjectRootStore, ProjectRootStore } from "./project";
import { CycleStore, ICycleStore } from "./cycle.store";
import { IProjectViewsStore, ProjectViewsStore } from "./project-view.store";
import { IProjectViewStore, ProjectViewStore } from "./project-view.store";
import { IModuleStore, ModulesStore } from "./module.store";
import { IUserStore, UserStore } from "./user";
import { IWorkspaceRootStore, WorkspaceRootStore } from "./workspace";
@ -22,7 +22,7 @@ export class RootStore {
labelRoot: ILabelRootStore;
cycle: ICycleStore;
module: IModuleStore;
projectView: IProjectViewsStore;
projectView: IProjectViewStore;
page: IPageStore;
issue: IIssueRootStore;
state: IStateStore;
@ -38,7 +38,7 @@ export class RootStore {
this.issue = new IssueRootStore(this);
this.cycle = new CycleStore(this);
this.module = new ModulesStore(this);
this.projectView = new ProjectViewsStore(this);
this.projectView = new ProjectViewStore(this);
this.page = new PageStore(this);
}
}

View File

@ -5,8 +5,10 @@ import { ProjectMemberService } from "services/project";
import { UserService } from "services/user.service";
import { WorkspaceService } from "services/workspace.service";
// interfaces
import { IWorkspaceMemberMe, IProjectMember, TUserProjectRole, TUserWorkspaceRole } from "types";
import { IWorkspaceMemberMe, IProjectMember } from "types";
import { RootStore } from "../root.store";
import { EUserProjectRoles } from "constants/project";
import { EUserWorkspaceRoles } from "constants/workspace";
export interface IUserMembershipStore {
workspaceMemberInfo: {
@ -24,8 +26,8 @@ export interface IUserMembershipStore {
currentProjectMemberInfo: IProjectMember | undefined;
currentWorkspaceMemberInfo: IWorkspaceMemberMe | undefined;
currentProjectRole: TUserProjectRole | undefined;
currentWorkspaceRole: TUserWorkspaceRole | undefined;
currentProjectRole: EUserProjectRoles | undefined;
currentWorkspaceRole: EUserWorkspaceRoles | undefined;
hasPermissionToCurrentWorkspace: boolean | undefined;
hasPermissionToCurrentProject: boolean | undefined;

View File

@ -22,7 +22,7 @@ export interface IWorkspaceRootStore {
getWorkspaceBySlug: (workspaceSlug: string) => IWorkspace | null;
getWorkspaceById: (workspaceId: string) => IWorkspace | null;
// actions
fetchWorkspaces: () => Promise<Record<string, IWorkspace>>;
fetchWorkspaces: () => Promise<IWorkspace[]>;
createWorkspace: (data: Partial<IWorkspace>) => Promise<IWorkspace>;
updateWorkspace: (workspaceSlug: string, data: Partial<IWorkspace>) => Promise<IWorkspace>;
deleteWorkspace: (workspaceSlug: string) => Promise<void>;
@ -126,7 +126,9 @@ export class WorkspaceRootStore implements IWorkspaceRootStore {
const workspaceResponse = await this.workspaceService.userWorkspaces();
runInAction(() => {
this.workspaces = workspaceResponse;
workspaceResponse.forEach((workspace) => {
set(this.workspaces, [workspace.id], workspace);
});
this.loader = false;
this.error = null;
});

View File

@ -7,8 +7,9 @@ import { WorkspaceService } from "services/workspace.service";
import { AuthService } from "services/auth.service";
// interfaces
import { IUser, IUserSettings } from "types/users";
import { IWorkspaceMemberMe, IProjectMember, TUserProjectRole, TUserWorkspaceRole } from "types";
import { IWorkspaceMemberMe, IProjectMember, TUserWorkspaceRole } from "types";
import { RootStore } from "./root";
import { EUserProjectRoles } from "constants/project";
export interface IUserStore {
loader: boolean;
@ -37,7 +38,7 @@ export interface IUserStore {
currentProjectMemberInfo: IProjectMember | undefined;
currentWorkspaceMemberInfo: IWorkspaceMemberMe | undefined;
currentProjectRole: TUserProjectRole | undefined;
currentProjectRole: EUserProjectRoles | undefined;
currentWorkspaceRole: TUserWorkspaceRole | undefined;
hasPermissionToCurrentWorkspace: boolean | undefined;

View File

@ -34,10 +34,6 @@ export interface IRecentPages {
[key: string]: string[];
}
export interface RecentPagesResponse {
[key: string]: IPage[];
}
export interface IPageBlock {
completed_at: Date | null;
created_at: Date;

View File

@ -1,6 +1,5 @@
import type { IUserLite, IWorkspace, IWorkspaceLite, IUserMemberLite, TStateGroups, IProjectViewProps } from ".";
export type TUserProjectRole = 5 | 10 | 15 | 20;
import { EUserProjectRoles } from "constants/project";
import type { IUserLite, IWorkspace, IWorkspaceLite, TStateGroups } from ".";
export interface IProject {
archive_in: number;
@ -34,7 +33,7 @@ export interface IProject {
is_deployed: boolean;
is_favorite: boolean;
is_member: boolean;
member_role: TUserProjectRole | null;
member_role: EUserProjectRoles | null;
members: IProjectMemberLite[];
issue_views_view: boolean;
module_view: boolean;
@ -73,44 +72,12 @@ export interface IProjectMemberLite {
export interface IProjectMember {
id: string;
member: IUserMemberLite;
project: IProjectLite;
workspace: IWorkspaceLite;
comment: string;
role: TUserProjectRole;
preferences: ProjectPreferences;
view_props: IProjectViewProps;
default_props: IProjectViewProps;
created_at: Date;
updated_at: Date;
created_by: string;
updated_by: string;
}
export interface IProjectMemberInvitation {
id: string;
project: IProject;
workspace: IWorkspace;
email: string;
accepted: boolean;
token: string;
message: string;
responded_at: Date;
role: TUserProjectRole;
created_at: Date;
updated_at: Date;
created_by: string;
updated_by: string;
member: string;
role: EUserProjectRoles;
}
export interface IProjectBulkAddFormData {
members: { role: TUserProjectRole; member_id: string }[];
members: { role: EUserProjectRoles; member_id: string }[];
}
export interface IGithubRepository {

View File

@ -61,11 +61,10 @@ export interface IUserTheme {
export interface IUserLite {
avatar: string;
created_at: Date;
display_name: string;
email?: string;
first_name: string;
readonly id: string;
id: string;
is_bot: boolean;
last_name: string;
}

View File

@ -1,3 +1,4 @@
import { EUserWorkspaceRoles } from "constants/workspace";
import type { IProjectMember, IUser, IUserLite, IWorkspaceViewProps } from "types";
export type TUserWorkspaceRole = 5 | 10 | 15 | 20;
@ -58,15 +59,9 @@ export type Properties = {
};
export interface IWorkspaceMember {
company_role: string | null;
created_at: Date;
created_by: string;
id: string;
member: IUserLite;
role: TUserWorkspaceRole;
updated_at: Date;
updated_by: string;
workspace: IWorkspaceLite;
role: EUserWorkspaceRoles;
}
export interface IWorkspaceMemberMe {