mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: implement the new label root store
This commit is contained in:
parent
2e74dfa12c
commit
960f170fd4
@ -1,9 +1,9 @@
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// cmdk
|
|
||||||
import { Command } from "cmdk";
|
import { Command } from "cmdk";
|
||||||
|
// hooks
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { useProjectState } from "hooks/store";
|
||||||
// ui
|
// ui
|
||||||
import { Spinner, StateGroupIcon } from "@plane/ui";
|
import { Spinner, StateGroupIcon } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
@ -18,14 +18,14 @@ type Props = {
|
|||||||
|
|
||||||
export const ChangeIssueState: React.FC<Props> = observer((props) => {
|
export const ChangeIssueState: React.FC<Props> = observer((props) => {
|
||||||
const { closePalette, issue } = props;
|
const { closePalette, issue } = props;
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
projectState: { projectStates },
|
|
||||||
projectIssues: { updateIssue },
|
projectIssues: { updateIssue },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const { projectStates } = useProjectState();
|
||||||
|
|
||||||
const submitChanges = async (formData: Partial<IIssue>) => {
|
const submitChanges = async (formData: Partial<IIssue>) => {
|
||||||
if (!workspaceSlug || !projectId || !issue) return;
|
if (!workspaceSlug || !projectId || !issue) return;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { useEffect } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
// hooks
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useLabel } from "hooks/store";
|
||||||
// hook
|
// hook
|
||||||
import useEstimateOption from "hooks/use-estimate-option";
|
import useEstimateOption from "hooks/use-estimate-option";
|
||||||
// icons
|
// icons
|
||||||
@ -27,7 +28,6 @@ import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
|||||||
import { capitalizeFirstLetter } from "helpers/string.helper";
|
import { capitalizeFirstLetter } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssueActivity } from "types";
|
import { IIssueActivity } from "types";
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
const IssueLink = ({ activity }: { activity: IIssueActivity }) => {
|
const IssueLink = ({ activity }: { activity: IIssueActivity }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -74,11 +74,10 @@ const UserLink = ({ activity }: { activity: IIssueActivity }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const LabelPill = observer(({ labelId, workspaceSlug }: { labelId: string; workspaceSlug: string }) => {
|
const LabelPill = observer(({ labelId, workspaceSlug }: { labelId: string; workspaceSlug: string }) => {
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
workspace: { labels, fetchWorkspaceLabels },
|
workspaceLabel: { workspaceLabels, fetchWorkspaceLabels },
|
||||||
} = useMobxStore();
|
} = useLabel();
|
||||||
|
|
||||||
const workspaceLabels = labels[workspaceSlug];
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!workspaceLabels) fetchWorkspaceLabels(workspaceSlug);
|
if (!workspaceLabels) fetchWorkspaceLabels(workspaceSlug);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { useApplication, useLabel, useProject, useProjectState, useUser } from "hooks/store";
|
||||||
import useLocalStorage from "hooks/use-local-storage";
|
import useLocalStorage from "hooks/use-local-storage";
|
||||||
// components
|
// components
|
||||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||||
@ -25,27 +25,34 @@ import { EFilterType } from "store_legacy/issues/types";
|
|||||||
import { EProjectStore } from "store_legacy/command-palette.store";
|
import { EProjectStore } from "store_legacy/command-palette.store";
|
||||||
|
|
||||||
export const CycleIssuesHeader: React.FC = observer(() => {
|
export const CycleIssuesHeader: React.FC = observer(() => {
|
||||||
|
// states
|
||||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId } = router.query as {
|
const { workspaceSlug, projectId, cycleId } = router.query as {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
cycleId: string;
|
cycleId: string;
|
||||||
};
|
};
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
cycle: cycleStore,
|
cycle: cycleStore,
|
||||||
projectIssuesFilter: projectIssueFiltersStore,
|
projectIssuesFilter: projectIssueFiltersStore,
|
||||||
project: { currentProjectDetails },
|
|
||||||
projectMember: { projectMembers },
|
projectMember: { projectMembers },
|
||||||
projectLabel: { projectLabels },
|
|
||||||
projectState: projectStateStore,
|
|
||||||
commandPalette: commandPaletteStore,
|
|
||||||
trackEvent: { setTrackElement },
|
|
||||||
cycleIssuesFilter: { issueFilters, updateFilters },
|
cycleIssuesFilter: { issueFilters, updateFilters },
|
||||||
user: { currentProjectRole },
|
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
|
commandPalette: { toggleCreateIssueModal },
|
||||||
|
eventTracker: { setTrackElement },
|
||||||
|
} = useApplication();
|
||||||
|
const {
|
||||||
|
membership: { currentProjectRole },
|
||||||
|
} = useUser();
|
||||||
|
const { currentProjectDetails } = useProject();
|
||||||
|
const { projectStates } = useProjectState();
|
||||||
|
const {
|
||||||
|
project: { projectLabels },
|
||||||
|
} = useLabel();
|
||||||
|
|
||||||
const activeLayout = projectIssueFiltersStore.issueFilters?.displayFilters?.layout;
|
const activeLayout = projectIssueFiltersStore.issueFilters?.displayFilters?.layout;
|
||||||
|
|
||||||
@ -180,9 +187,9 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||||||
layoutDisplayFiltersOptions={
|
layoutDisplayFiltersOptions={
|
||||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
||||||
}
|
}
|
||||||
labels={projectLabels ?? undefined}
|
labels={projectLabels}
|
||||||
members={projectMembers?.map((m) => m.member)}
|
members={projectMembers?.map((m) => m.member)}
|
||||||
states={projectStateStore.states?.[projectId ?? ""] ?? undefined}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
@ -205,7 +212,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTrackElement("CYCLE_PAGE_HEADER");
|
setTrackElement("CYCLE_PAGE_HEADER");
|
||||||
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.CYCLE);
|
toggleCreateIssueModal(true, EProjectStore.CYCLE);
|
||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
prependIcon={<Plus />}
|
prependIcon={<Plus />}
|
||||||
|
@ -2,7 +2,8 @@ import { useCallback, useState } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
// hooks
|
||||||
|
import { useLabel, useUser } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "components/issues";
|
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "components/issues";
|
||||||
@ -29,19 +30,23 @@ type Props = {
|
|||||||
|
|
||||||
export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
||||||
const { activeLayout } = props;
|
const { activeLayout } = props;
|
||||||
|
// states
|
||||||
const [createViewModal, setCreateViewModal] = useState(false);
|
const [createViewModal, setCreateViewModal] = useState(false);
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query as { workspaceSlug: string };
|
const { workspaceSlug } = router.query;
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
workspace: { workspaceLabels },
|
|
||||||
workspaceMember: { workspaceMembers },
|
workspaceMember: { workspaceMembers },
|
||||||
project: { workspaceProjects },
|
project: { workspaceProjects },
|
||||||
user: { currentWorkspaceRole },
|
|
||||||
workspaceGlobalIssuesFilter: { issueFilters, updateFilters },
|
workspaceGlobalIssuesFilter: { issueFilters, updateFilters },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
|
membership: { currentWorkspaceRole },
|
||||||
|
} = useUser();
|
||||||
|
const {
|
||||||
|
workspace: { workspaceLabels },
|
||||||
|
} = useLabel();
|
||||||
|
|
||||||
const handleFiltersUpdate = useCallback(
|
const handleFiltersUpdate = useCallback(
|
||||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||||
@ -57,7 +62,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
|||||||
else newValues.push(value);
|
else newValues.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFilters(workspaceSlug, EFilterType.FILTERS, { [key]: newValues });
|
updateFilters(workspaceSlug.toString(), EFilterType.FILTERS, { [key]: newValues });
|
||||||
},
|
},
|
||||||
[workspaceSlug, issueFilters, updateFilters]
|
[workspaceSlug, issueFilters, updateFilters]
|
||||||
);
|
);
|
||||||
@ -65,7 +70,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
|||||||
const handleDisplayFilters = useCallback(
|
const handleDisplayFilters = useCallback(
|
||||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
updateFilters(workspaceSlug, EFilterType.DISPLAY_FILTERS, updatedDisplayFilter);
|
updateFilters(workspaceSlug.toString(), EFilterType.DISPLAY_FILTERS, updatedDisplayFilter);
|
||||||
},
|
},
|
||||||
[workspaceSlug, updateFilters]
|
[workspaceSlug, updateFilters]
|
||||||
);
|
);
|
||||||
@ -73,7 +78,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
|||||||
const handleDisplayProperties = useCallback(
|
const handleDisplayProperties = useCallback(
|
||||||
(property: Partial<IIssueDisplayProperties>) => {
|
(property: Partial<IIssueDisplayProperties>) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
updateFilters(workspaceSlug, EFilterType.DISPLAY_PROPERTIES, property);
|
updateFilters(workspaceSlug.toString(), EFilterType.DISPLAY_PROPERTIES, property);
|
||||||
},
|
},
|
||||||
[workspaceSlug, updateFilters]
|
[workspaceSlug, updateFilters]
|
||||||
);
|
);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { useApplication, useLabel, useProject, useProjectState, useUser } from "hooks/store";
|
||||||
import useLocalStorage from "hooks/use-local-storage";
|
import useLocalStorage from "hooks/use-local-storage";
|
||||||
// components
|
// components
|
||||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||||
@ -25,28 +25,33 @@ import { EFilterType } from "store_legacy/issues/types";
|
|||||||
import { EProjectStore } from "store_legacy/command-palette.store";
|
import { EProjectStore } from "store_legacy/command-palette.store";
|
||||||
|
|
||||||
export const ModuleIssuesHeader: React.FC = observer(() => {
|
export const ModuleIssuesHeader: React.FC = observer(() => {
|
||||||
|
// states
|
||||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, moduleId } = router.query as {
|
const { workspaceSlug, projectId, moduleId } = router.query as {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
moduleId: string;
|
moduleId: string;
|
||||||
};
|
};
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
module: moduleStore,
|
module: moduleStore,
|
||||||
project: projectStore,
|
|
||||||
projectMember: { projectMembers },
|
projectMember: { projectMembers },
|
||||||
projectState: projectStateStore,
|
|
||||||
commandPalette: commandPaletteStore,
|
|
||||||
trackEvent: { setTrackElement },
|
|
||||||
projectLabel: { projectLabels },
|
|
||||||
moduleIssuesFilter: { issueFilters, updateFilters },
|
moduleIssuesFilter: { issueFilters, updateFilters },
|
||||||
user: { currentProjectRole },
|
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
const { currentProjectDetails } = projectStore;
|
commandPalette: { toggleCreateIssueModal },
|
||||||
|
eventTracker: { setTrackElement },
|
||||||
|
} = useApplication();
|
||||||
|
const {
|
||||||
|
membership: { currentProjectRole },
|
||||||
|
} = useUser();
|
||||||
|
const { currentProjectDetails } = useProject();
|
||||||
|
const {
|
||||||
|
project: { projectLabels },
|
||||||
|
} = useLabel();
|
||||||
|
const { projectStates } = useProjectState();
|
||||||
|
|
||||||
const { setValue, storedValue } = useLocalStorage("module_sidebar_collapsed", "false");
|
const { setValue, storedValue } = useLocalStorage("module_sidebar_collapsed", "false");
|
||||||
|
|
||||||
@ -181,9 +186,9 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||||||
layoutDisplayFiltersOptions={
|
layoutDisplayFiltersOptions={
|
||||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
||||||
}
|
}
|
||||||
labels={projectLabels ?? undefined}
|
labels={projectLabels}
|
||||||
members={projectMembers?.map((m) => m.member)}
|
members={projectMembers?.map((m) => m.member)}
|
||||||
states={projectStateStore.states?.[projectId ?? ""] ?? undefined}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
@ -206,7 +211,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTrackElement("MODULE_PAGE_HEADER");
|
setTrackElement("MODULE_PAGE_HEADER");
|
||||||
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.MODULE);
|
toggleCreateIssueModal(true, EProjectStore.MODULE);
|
||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
prependIcon={<Plus />}
|
prependIcon={<Plus />}
|
||||||
|
@ -1,32 +1,35 @@
|
|||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { ArrowLeft } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useLabel, useProject, useProjectState } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// constants
|
// constants
|
||||||
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
|
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
|
||||||
// ui
|
// ui
|
||||||
import { Breadcrumbs, LayersIcon } from "@plane/ui";
|
import { Breadcrumbs, LayersIcon } from "@plane/ui";
|
||||||
// icons
|
|
||||||
import { ArrowLeft } from "lucide-react";
|
|
||||||
// components
|
// components
|
||||||
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "components/issues";
|
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "components/issues";
|
||||||
|
// helpers
|
||||||
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
// types
|
// types
|
||||||
import type { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "types";
|
import type { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "types";
|
||||||
// helper
|
|
||||||
import { renderEmoji } from "helpers/emoji.helper";
|
|
||||||
|
|
||||||
export const ProjectArchivedIssuesHeader: FC = observer(() => {
|
export const ProjectArchivedIssuesHeader: FC = observer(() => {
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
project: { currentProjectDetails },
|
|
||||||
projectLabel: { projectLabels },
|
|
||||||
projectMember: { projectMembers },
|
projectMember: { projectMembers },
|
||||||
archivedIssueFilters: archivedIssueFiltersStore,
|
archivedIssueFilters: archivedIssueFiltersStore,
|
||||||
projectState: projectStateStore,
|
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const { currentProjectDetails } = useProject();
|
||||||
|
const { projectStates } = useProjectState();
|
||||||
|
const {
|
||||||
|
project: { projectLabels },
|
||||||
|
} = useLabel();
|
||||||
|
|
||||||
// for archived issues list layout is the only option
|
// for archived issues list layout is the only option
|
||||||
const activeLayout = "list";
|
const activeLayout = "list";
|
||||||
@ -118,9 +121,9 @@ export const ProjectArchivedIssuesHeader: FC = observer(() => {
|
|||||||
layoutDisplayFiltersOptions={
|
layoutDisplayFiltersOptions={
|
||||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.archived_issues[activeLayout] : undefined
|
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.archived_issues[activeLayout] : undefined
|
||||||
}
|
}
|
||||||
labels={projectLabels ?? undefined}
|
labels={projectLabels}
|
||||||
members={projectMembers?.map((m) => m.member)}
|
members={projectMembers?.map((m) => m.member)}
|
||||||
states={projectStateStore.states?.[projectId?.toString() ?? ""] ?? undefined}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
|
@ -2,6 +2,7 @@ import { FC, useCallback } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useLabel, useProject, useProjectState } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||||
@ -14,16 +15,19 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption
|
|||||||
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
|
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
|
||||||
|
|
||||||
export const ProjectDraftIssueHeader: FC = observer(() => {
|
export const ProjectDraftIssueHeader: FC = observer(() => {
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string };
|
const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string };
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
project: { currentProjectDetails },
|
|
||||||
projectLabel: { projectLabels },
|
|
||||||
projectMember: { projectMembers },
|
projectMember: { projectMembers },
|
||||||
projectState: projectStateStore,
|
|
||||||
projectDraftIssuesFilter: { issueFilters, updateFilters },
|
projectDraftIssuesFilter: { issueFilters, updateFilters },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const { currentProjectDetails } = useProject();
|
||||||
|
const { projectStates } = useProjectState();
|
||||||
|
const {
|
||||||
|
project: { projectLabels },
|
||||||
|
} = useLabel();
|
||||||
|
|
||||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||||
|
|
||||||
@ -112,9 +116,9 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
|
|||||||
layoutDisplayFiltersOptions={
|
layoutDisplayFiltersOptions={
|
||||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
||||||
}
|
}
|
||||||
labels={projectLabels ?? undefined}
|
labels={projectLabels}
|
||||||
members={projectMembers?.map((m) => m.member)}
|
members={projectMembers?.map((m) => m.member)}
|
||||||
states={projectStateStore.states?.[projectId ?? ""] ?? undefined}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
|
@ -2,7 +2,8 @@ import { useCallback } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
// mobx store
|
// hooks
|
||||||
|
import { useApplication, useLabel, useProject, useProjectState, useUser } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||||
@ -21,24 +22,31 @@ import { EFilterType } from "store_legacy/issues/types";
|
|||||||
import { EProjectStore } from "store_legacy/command-palette.store";
|
import { EProjectStore } from "store_legacy/command-palette.store";
|
||||||
|
|
||||||
export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, viewId } = router.query as {
|
const { workspaceSlug, projectId, viewId } = router.query as {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
};
|
};
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
project: { currentProjectDetails },
|
|
||||||
projectLabel: { projectLabels },
|
|
||||||
projectMember: { projectMembers },
|
projectMember: { projectMembers },
|
||||||
projectState: projectStateStore,
|
|
||||||
projectViews: projectViewsStore,
|
projectViews: projectViewsStore,
|
||||||
viewIssuesFilter: { issueFilters, updateFilters },
|
viewIssuesFilter: { issueFilters, updateFilters },
|
||||||
commandPalette: commandPaletteStore,
|
|
||||||
trackEvent: { setTrackElement },
|
|
||||||
user: { currentProjectRole },
|
|
||||||
} = useMobxStore();
|
} = 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;
|
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||||
|
|
||||||
@ -164,9 +172,9 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
|||||||
layoutDisplayFiltersOptions={
|
layoutDisplayFiltersOptions={
|
||||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
||||||
}
|
}
|
||||||
labels={projectLabels ?? undefined}
|
labels={projectLabels}
|
||||||
members={projectMembers?.map((m) => m.member)}
|
members={projectMembers?.map((m) => m.member)}
|
||||||
states={projectStateStore.states?.[projectId ?? ""] ?? undefined}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
@ -184,7 +192,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTrackElement("PROJECT_VIEW_PAGE_HEADER");
|
setTrackElement("PROJECT_VIEW_PAGE_HEADER");
|
||||||
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT_VIEW);
|
toggleCreateIssueModal(true, EProjectStore.PROJECT_VIEW);
|
||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
prependIcon={<Plus />}
|
prependIcon={<Plus />}
|
||||||
|
@ -4,9 +4,9 @@ import { observer } from "mobx-react-lite";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { AlertTriangle, CheckCircle2, Clock, Copy, ExternalLink, Inbox, XCircle } from "lucide-react";
|
import { AlertTriangle, CheckCircle2, Clock, Copy, ExternalLink, Inbox, XCircle } from "lucide-react";
|
||||||
|
// hooks
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { useProjectState, useUser } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
import { IssueDescriptionForm, IssueDetailsSidebar, IssueReaction, IssueUpdateStatus } from "components/issues";
|
import { IssueDescriptionForm, IssueDetailsSidebar, IssueReaction, IssueUpdateStatus } from "components/issues";
|
||||||
import { InboxIssueActivity } from "components/inbox";
|
import { InboxIssueActivity } from "components/inbox";
|
||||||
@ -28,19 +28,19 @@ const defaultValues: Partial<IInboxIssue> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const InboxMainContent: React.FC = observer(() => {
|
export const InboxMainContent: React.FC = observer(() => {
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, projectId, inboxId, inboxIssueId } = router.query;
|
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
||||||
|
// router
|
||||||
|
const router = useRouter();
|
||||||
|
const { workspaceSlug, projectId, inboxId, inboxIssueId } = router.query;
|
||||||
|
// store hooks
|
||||||
|
const { inboxIssues: inboxIssuesStore, inboxIssueDetails: inboxIssueDetailsStore } = useMobxStore();
|
||||||
const {
|
const {
|
||||||
inboxIssues: inboxIssuesStore,
|
currentUser,
|
||||||
inboxIssueDetails: inboxIssueDetailsStore,
|
membership: { currentProjectRole },
|
||||||
user: { currentUser, currentProjectRole },
|
} = useUser();
|
||||||
projectState: { states },
|
const { projectStates } = useProjectState();
|
||||||
} = useMobxStore();
|
// form info
|
||||||
|
|
||||||
const { reset, control, watch } = useForm<IIssue>({
|
const { reset, control, watch } = useForm<IIssue>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
});
|
});
|
||||||
@ -60,9 +60,7 @@ export const InboxMainContent: React.FC = observer(() => {
|
|||||||
|
|
||||||
const issuesList = inboxId ? inboxIssuesStore.inboxIssues[inboxId.toString()] : undefined;
|
const issuesList = inboxId ? inboxIssuesStore.inboxIssues[inboxId.toString()] : undefined;
|
||||||
const issueDetails = inboxIssueId ? inboxIssueDetailsStore.issueDetails[inboxIssueId.toString()] : undefined;
|
const issueDetails = inboxIssueId ? inboxIssueDetailsStore.issueDetails[inboxIssueId.toString()] : undefined;
|
||||||
const currentIssueState = projectId
|
const currentIssueState = projectStates?.find((s) => s.id === issueDetails?.state);
|
||||||
? states[projectId.toString()]?.find((s) => s.id === issueDetails?.state)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const submitChanges = useCallback(
|
const submitChanges = useCallback(
|
||||||
async (formData: Partial<IInboxIssue>) => {
|
async (formData: Partial<IInboxIssue>) => {
|
||||||
|
@ -4,22 +4,22 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
||||||
|
import { Sparkle } from "lucide-react";
|
||||||
// mobx store
|
// hooks
|
||||||
|
import { useApplication, useWorkspace } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
|
import useEditorSuggestions from "hooks/use-editor-suggestions";
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
|
import { AIService } from "services/ai.service";
|
||||||
// components
|
// components
|
||||||
import { IssuePrioritySelect } from "components/issues/select";
|
import { IssuePrioritySelect } from "components/issues/select";
|
||||||
|
import { GptAssistantModal } from "components/core";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input, ToggleSwitch } from "@plane/ui";
|
import { Button, Input, ToggleSwitch } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
import useEditorSuggestions from "hooks/use-editor-suggestions";
|
|
||||||
import { GptAssistantModal } from "components/core";
|
|
||||||
import { Sparkle } from "lucide-react";
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { AIService } from "services/ai.service";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -40,30 +40,29 @@ const fileService = new FileService();
|
|||||||
|
|
||||||
export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
||||||
const { isOpen, onClose } = props;
|
const { isOpen, onClose } = props;
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [createMore, setCreateMore] = useState(false);
|
const [createMore, setCreateMore] = useState(false);
|
||||||
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
||||||
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
||||||
|
// refs
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
|
// toast alert
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
const editorSuggestion = useEditorSuggestions();
|
const editorSuggestion = useEditorSuggestions();
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, inboxId } = router.query as {
|
const { workspaceSlug, projectId, inboxId } = router.query as {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
inboxId: string;
|
inboxId: string;
|
||||||
};
|
};
|
||||||
|
// store hooks
|
||||||
|
const { inboxIssueDetails: inboxIssueDetailsStore } = useMobxStore();
|
||||||
const {
|
const {
|
||||||
inboxIssueDetails: inboxIssueDetailsStore,
|
config: { envConfig },
|
||||||
trackEvent: { postHogEventTracker },
|
eventTracker: { postHogEventTracker },
|
||||||
appConfig: { envConfig },
|
} = useApplication();
|
||||||
workspace: { currentWorkspace },
|
const { currentWorkspace } = useWorkspace();
|
||||||
} = useMobxStore();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
|
@ -2,10 +2,9 @@ import React, { useState } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
|
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useApplication, useWorkspace } from "hooks/store";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// icons
|
// icons
|
||||||
import { AlertTriangle } from "lucide-react";
|
import { AlertTriangle } from "lucide-react";
|
||||||
@ -21,16 +20,17 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const DeleteInboxIssueModal: React.FC<Props> = observer(({ isOpen, onClose, data }) => {
|
export const DeleteInboxIssueModal: React.FC<Props> = observer(({ isOpen, onClose, data }) => {
|
||||||
|
// states
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, inboxId } = router.query;
|
const { workspaceSlug, projectId, inboxId } = router.query;
|
||||||
|
// store hooks
|
||||||
|
const { inboxIssueDetails: inboxIssueDetailsStore } = useMobxStore();
|
||||||
const {
|
const {
|
||||||
inboxIssueDetails: inboxIssueDetailsStore,
|
eventTracker: { postHogEventTracker },
|
||||||
trackEvent: { postHogEventTracker },
|
} = useApplication();
|
||||||
workspace: { currentWorkspace },
|
const { currentWorkspace } = useWorkspace();
|
||||||
} = useMobxStore();
|
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { PlusIcon } from "lucide-react";
|
import { PlusIcon } from "lucide-react";
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useApplication, useUser } from "hooks/store";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { EmptyState } from "components/common";
|
import { EmptyState } from "components/common";
|
||||||
@ -28,13 +28,15 @@ export const CycleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId, cycleId } = props;
|
const { workspaceSlug, projectId, cycleId } = props;
|
||||||
// states
|
// states
|
||||||
const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false);
|
const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false);
|
||||||
|
// store hooks
|
||||||
|
const { cycleIssues: cycleIssueStore } = useMobxStore();
|
||||||
const {
|
const {
|
||||||
cycleIssues: cycleIssueStore,
|
commandPalette: { toggleCreateIssueModal },
|
||||||
commandPalette: commandPaletteStore,
|
eventTracker: { setTrackElement },
|
||||||
trackEvent: { setTrackElement },
|
} = useApplication();
|
||||||
user: { currentProjectRole: userRole },
|
const {
|
||||||
} = useMobxStore();
|
membership: { currentProjectRole: userRole },
|
||||||
|
} = useUser();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -72,7 +74,7 @@ export const CycleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setTrackElement("CYCLE_EMPTY_STATE");
|
setTrackElement("CYCLE_EMPTY_STATE");
|
||||||
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.CYCLE);
|
toggleCreateIssueModal(true, EProjectStore.CYCLE);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
secondaryButton={
|
secondaryButton={
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
import { PlusIcon } from "lucide-react";
|
import { PlusIcon } from "lucide-react";
|
||||||
|
// hooks
|
||||||
|
import { useApplication, useUser } from "hooks/store";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { EmptyState } from "components/common";
|
import { EmptyState } from "components/common";
|
||||||
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
// assets
|
// assets
|
||||||
import emptyIssue from "public/empty-state/issue.svg";
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
import { ExistingIssuesListModal } from "components/core";
|
// types
|
||||||
import { observer } from "mobx-react-lite";
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
import { ISearchIssueResponse } from "types";
|
import { ISearchIssueResponse } from "types";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useState } from "react";
|
|
||||||
// constants
|
// constants
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
@ -23,14 +27,16 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId, moduleId } = props;
|
const { workspaceSlug, projectId, moduleId } = props;
|
||||||
// states
|
// states
|
||||||
const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false);
|
const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false);
|
||||||
|
// store hooks
|
||||||
|
const { moduleIssues: moduleIssueStore } = useMobxStore();
|
||||||
const {
|
const {
|
||||||
moduleIssues: moduleIssueStore,
|
commandPalette: { toggleCreateIssueModal },
|
||||||
commandPalette: commandPaletteStore,
|
eventTracker: { setTrackElement },
|
||||||
trackEvent: { setTrackElement },
|
} = useApplication();
|
||||||
user: { currentProjectRole: userRole },
|
const {
|
||||||
} = useMobxStore();
|
membership: { currentProjectRole: userRole },
|
||||||
|
} = useUser();
|
||||||
|
// toast alert
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const handleAddIssuesToModule = async (data: ISearchIssueResponse[]) => {
|
const handleAddIssuesToModule = async (data: ISearchIssueResponse[]) => {
|
||||||
@ -67,7 +73,7 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setTrackElement("MODULE_EMPTY_STATE");
|
setTrackElement("MODULE_EMPTY_STATE");
|
||||||
commandPaletteStore.toggleCreateIssueModal(true);
|
toggleCreateIssueModal(true);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
secondaryButton={
|
secondaryButton={
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { X } from "lucide-react";
|
||||||
|
// hooks
|
||||||
|
import { useUser } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
AppliedDateFilters,
|
AppliedDateFilters,
|
||||||
@ -10,8 +12,6 @@ import {
|
|||||||
AppliedStateFilters,
|
AppliedStateFilters,
|
||||||
AppliedStateGroupFilters,
|
AppliedStateGroupFilters,
|
||||||
} from "components/issues";
|
} from "components/issues";
|
||||||
// icons
|
|
||||||
import { X } from "lucide-react";
|
|
||||||
// helpers
|
// helpers
|
||||||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -34,10 +34,10 @@ const dateFilters = ["start_date", "target_date"];
|
|||||||
|
|
||||||
export const AppliedFiltersList: React.FC<Props> = observer((props) => {
|
export const AppliedFiltersList: React.FC<Props> = observer((props) => {
|
||||||
const { appliedFilters, handleClearAllFilters, handleRemoveFilter, labels, members, projects, states } = props;
|
const { appliedFilters, handleClearAllFilters, handleRemoveFilter, labels, members, projects, states } = props;
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
user: { currentProjectRole },
|
membership: { currentProjectRole },
|
||||||
} = useMobxStore();
|
} = useUser();
|
||||||
|
|
||||||
if (!appliedFilters) return null;
|
if (!appliedFilters) return null;
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { Fragment, useState } from "react";
|
import { Fragment, useState } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
|
||||||
import { usePopper } from "react-popper";
|
import { usePopper } from "react-popper";
|
||||||
|
import { Check, ChevronDown, Search, Tags } from "lucide-react";
|
||||||
|
// hooks
|
||||||
|
import { useApplication, useLabel } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
import { Combobox } from "@headlessui/react";
|
import { Combobox } from "@headlessui/react";
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
import { Check, ChevronDown, Search, Tags } from "lucide-react";
|
|
||||||
// types
|
// types
|
||||||
import { Placement } from "@popperjs/core";
|
import { Placement } from "@popperjs/core";
|
||||||
import { RootStore } from "store_legacy/root";
|
|
||||||
import { IIssueLabel } from "types";
|
import { IIssueLabel } from "types";
|
||||||
|
|
||||||
export interface IIssuePropertyLabels {
|
export interface IIssuePropertyLabels {
|
||||||
@ -44,18 +43,19 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
|||||||
noLabelBorder = false,
|
noLabelBorder = false,
|
||||||
placeholderText,
|
placeholderText,
|
||||||
} = props;
|
} = props;
|
||||||
|
// states
|
||||||
const {
|
|
||||||
workspace: workspaceStore,
|
|
||||||
projectLabel: { fetchProjectLabels, labels },
|
|
||||||
}: RootStore = useMobxStore();
|
|
||||||
const workspaceSlug = workspaceStore?.workspaceSlug;
|
|
||||||
|
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
// popper-js refs
|
||||||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
||||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState<Boolean>(false);
|
const [isLoading, setIsLoading] = useState<Boolean>(false);
|
||||||
|
// store hooks
|
||||||
|
const {
|
||||||
|
router: { workspaceSlug },
|
||||||
|
} = useApplication();
|
||||||
|
const {
|
||||||
|
project: { fetchProjectLabels, projectLabels: storeLabels },
|
||||||
|
} = useLabel();
|
||||||
|
|
||||||
const fetchLabels = () => {
|
const fetchLabels = () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -65,7 +65,6 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
|||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
|
|
||||||
let projectLabels: IIssueLabel[] = defaultOptions;
|
let projectLabels: IIssueLabel[] = defaultOptions;
|
||||||
const storeLabels = projectId && labels ? labels[projectId] : [];
|
|
||||||
if (storeLabels && storeLabels.length > 0) projectLabels = storeLabels;
|
if (storeLabels && storeLabels.length > 0) projectLabels = storeLabels;
|
||||||
|
|
||||||
const options = projectLabels.map((label) => ({
|
const options = projectLabels.map((label) => ({
|
||||||
|
@ -3,12 +3,11 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
import { MinusCircle } from "lucide-react";
|
import { MinusCircle } from "lucide-react";
|
||||||
// mobx store
|
// hooks
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useApplication, useProject, useProjectState, useUser, useWorkspace } from "hooks/store";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// services
|
// services
|
||||||
import { IssueService, IssueCommentService } from "services/issue";
|
import { IssueService, IssueCommentService } from "services/issue";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
AddComment,
|
AddComment,
|
||||||
@ -49,19 +48,19 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId, issueId } = router.query;
|
const { workspaceSlug, projectId, issueId } = router.query;
|
||||||
// toast alert
|
// toast alert
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
// mobx store
|
|
||||||
const {
|
const {
|
||||||
user: { currentUser, currentProjectRole },
|
eventTracker: { postHogEventTracker },
|
||||||
project: projectStore,
|
} = useApplication();
|
||||||
projectState: { states },
|
const {
|
||||||
trackEvent: { postHogEventTracker },
|
currentUser,
|
||||||
workspace: { currentWorkspace },
|
membership: { currentProjectRole },
|
||||||
} = useMobxStore();
|
} = useUser();
|
||||||
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
const { getProjectById } = useProject();
|
||||||
|
const { projectStates } = useProjectState();
|
||||||
|
|
||||||
const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : undefined;
|
const projectDetails = projectId ? getProjectById(projectId.toString()) : null;
|
||||||
const currentIssueState = projectId
|
const currentIssueState = projectStates?.find((s) => s.id === issueDetails.state);
|
||||||
? states[projectId.toString()]?.find((s) => s.id === issueDetails.state)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const { data: siblingIssues } = useSWR(
|
const { data: siblingIssues } = useSWR(
|
||||||
workspaceSlug && projectId && issueDetails?.parent ? SUB_ISSUES(issueDetails.parent) : null,
|
workspaceSlug && projectId && issueDetails?.parent ? SUB_ISSUES(issueDetails.parent) : null,
|
||||||
@ -94,7 +93,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
{
|
{
|
||||||
isGrouping: true,
|
isGrouping: true,
|
||||||
groupType: "Workspace_metrics",
|
groupType: "Workspace_metrics",
|
||||||
gorupId: currentWorkspace?.id!,
|
groupId: currentWorkspace?.id!,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -117,7 +116,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
{
|
{
|
||||||
isGrouping: true,
|
isGrouping: true,
|
||||||
groupType: "Workspace_metrics",
|
groupType: "Workspace_metrics",
|
||||||
gorupId: currentWorkspace?.id!,
|
groupId: currentWorkspace?.id!,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -139,7 +138,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
{
|
{
|
||||||
isGrouping: true,
|
isGrouping: true,
|
||||||
groupType: "Workspace_metrics",
|
groupType: "Workspace_metrics",
|
||||||
gorupId: currentWorkspace?.id!,
|
groupId: currentWorkspace?.id!,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@ -260,12 +259,12 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
activity={issueActivity}
|
activity={issueActivity}
|
||||||
handleCommentUpdate={handleCommentUpdate}
|
handleCommentUpdate={handleCommentUpdate}
|
||||||
handleCommentDelete={handleCommentDelete}
|
handleCommentDelete={handleCommentDelete}
|
||||||
showAccessSpecifier={projectDetails && projectDetails.is_deployed}
|
showAccessSpecifier={Boolean(projectDetails && projectDetails.is_deployed)}
|
||||||
/>
|
/>
|
||||||
<AddComment
|
<AddComment
|
||||||
onSubmit={handleAddComment}
|
onSubmit={handleAddComment}
|
||||||
disabled={uneditable}
|
disabled={uneditable}
|
||||||
showAccessSpecifier={projectDetails && projectDetails.is_deployed}
|
showAccessSpecifier={Boolean(projectDetails && projectDetails.is_deployed)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -3,13 +3,13 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// services
|
|
||||||
import { IssueDraftService } from "services/issue";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useApplication, useUser, useWorkspace } from "hooks/store";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
import useLocalStorage from "hooks/use-local-storage";
|
import useLocalStorage from "hooks/use-local-storage";
|
||||||
|
// services
|
||||||
|
import { IssueDraftService } from "services/issue";
|
||||||
// components
|
// components
|
||||||
import { IssueForm, ConfirmIssueDiscard } from "components/issues";
|
import { IssueForm, ConfirmIssueDiscard } from "components/issues";
|
||||||
// types
|
// types
|
||||||
@ -57,14 +57,13 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
currentStore = EProjectStore.PROJECT,
|
currentStore = EProjectStore.PROJECT,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [createMore, setCreateMore] = useState(false);
|
const [createMore, setCreateMore] = useState(false);
|
||||||
const [formDirtyState, setFormDirtyState] = useState<any>(null);
|
const [formDirtyState, setFormDirtyState] = useState<any>(null);
|
||||||
const [showConfirmDiscard, setShowConfirmDiscard] = useState(false);
|
const [showConfirmDiscard, setShowConfirmDiscard] = useState(false);
|
||||||
const [activeProject, setActiveProject] = useState<string | null>(null);
|
const [activeProject, setActiveProject] = useState<string | null>(null);
|
||||||
const [prePopulateData, setPreloadedData] = useState<Partial<IIssue>>({});
|
const [prePopulateData, setPreloadedData] = useState<Partial<IIssue>>({});
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query as {
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query as {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
@ -72,7 +71,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
cycleId: string | undefined;
|
cycleId: string | undefined;
|
||||||
moduleId: string | undefined;
|
moduleId: string | undefined;
|
||||||
};
|
};
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
project: projectStore,
|
project: projectStore,
|
||||||
projectIssues: projectIssueStore,
|
projectIssues: projectIssueStore,
|
||||||
@ -80,12 +79,12 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
workspaceProfileIssues: profileIssueStore,
|
workspaceProfileIssues: profileIssueStore,
|
||||||
cycleIssues: cycleIssueStore,
|
cycleIssues: cycleIssueStore,
|
||||||
moduleIssues: moduleIssueStore,
|
moduleIssues: moduleIssueStore,
|
||||||
user: userStore,
|
|
||||||
trackEvent: { postHogEventTracker },
|
|
||||||
workspace: { currentWorkspace },
|
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
const user = userStore.currentUser;
|
eventTracker: { postHogEventTracker },
|
||||||
|
} = useApplication();
|
||||||
|
const { currentUser } = useUser();
|
||||||
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
|
||||||
const issueStores = {
|
const issueStores = {
|
||||||
[EProjectStore.PROJECT]: {
|
[EProjectStore.PROJECT]: {
|
||||||
@ -100,7 +99,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
},
|
},
|
||||||
[EProjectStore.PROFILE]: {
|
[EProjectStore.PROFILE]: {
|
||||||
store: profileIssueStore,
|
store: profileIssueStore,
|
||||||
dataIdToUpdate: user?.id || undefined,
|
dataIdToUpdate: currentUser?.id || undefined,
|
||||||
viewId: undefined,
|
viewId: undefined,
|
||||||
},
|
},
|
||||||
[EProjectStore.CYCLE]: {
|
[EProjectStore.CYCLE]: {
|
||||||
@ -150,10 +149,10 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
setPreloadedData((prevData) => ({
|
setPreloadedData((prevData) => ({
|
||||||
...(prevData ?? {}),
|
...(prevData ?? {}),
|
||||||
...prePopulateDataProps,
|
...prePopulateDataProps,
|
||||||
assignees: prePopulateDataProps?.assignees ?? [user?.id ?? ""],
|
assignees: prePopulateDataProps?.assignees ?? [currentUser?.id ?? ""],
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}, [prePopulateDataProps, cycleId, moduleId, router.asPath, user?.id]);
|
}, [prePopulateDataProps, cycleId, moduleId, router.asPath, currentUser?.id]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -260,7 +259,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
{
|
{
|
||||||
isGrouping: true,
|
isGrouping: true,
|
||||||
groupType: "Workspace_metrics",
|
groupType: "Workspace_metrics",
|
||||||
gorupId: currentWorkspace?.id!,
|
groupId: currentWorkspace?.id!,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
||||||
@ -280,7 +279,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
{
|
{
|
||||||
isGrouping: true,
|
isGrouping: true,
|
||||||
groupType: "Workspace_metrics",
|
groupType: "Workspace_metrics",
|
||||||
gorupId: currentWorkspace?.id!,
|
groupId: currentWorkspace?.id!,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -289,7 +288,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createDraftIssue = async () => {
|
const createDraftIssue = async () => {
|
||||||
if (!workspaceSlug || !activeProject || !user) return;
|
if (!workspaceSlug || !activeProject || !currentUser) return;
|
||||||
|
|
||||||
const payload: Partial<IIssue> = {
|
const payload: Partial<IIssue> = {
|
||||||
...formDirtyState,
|
...formDirtyState,
|
||||||
@ -308,7 +307,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
setFormDirtyState(null);
|
setFormDirtyState(null);
|
||||||
setShowConfirmDiscard(false);
|
setShowConfirmDiscard(false);
|
||||||
|
|
||||||
if (payload.assignees?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE(workspaceSlug as string));
|
if (payload.assignees?.some((assignee) => assignee === currentUser?.id))
|
||||||
|
mutate(USER_ISSUE(workspaceSlug as string));
|
||||||
|
|
||||||
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
||||||
})
|
})
|
||||||
@ -343,7 +343,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
{
|
{
|
||||||
isGrouping: true,
|
isGrouping: true,
|
||||||
groupType: "Workspace_metrics",
|
groupType: "Workspace_metrics",
|
||||||
gorupId: currentWorkspace?.id!,
|
groupId: currentWorkspace?.id!,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@ -361,7 +361,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
{
|
{
|
||||||
isGrouping: true,
|
isGrouping: true,
|
||||||
groupType: "Workspace_metrics",
|
groupType: "Workspace_metrics",
|
||||||
gorupId: currentWorkspace?.id!,
|
groupId: currentWorkspace?.id!,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
import { CalendarDays, Link2, Plus, Signal, Tag, Triangle, LayoutPanelTop } from "lucide-react";
|
||||||
|
// hooks
|
||||||
|
import { useProject, useUser } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// ui icons
|
// ui icons
|
||||||
import { DiceIcon, DoubleCircleIcon, UserGroupIcon, ContrastIcon } from "@plane/ui";
|
import { DiceIcon, DoubleCircleIcon, UserGroupIcon, ContrastIcon } from "@plane/ui";
|
||||||
import { CalendarDays, Link2, Plus, Signal, Tag, Triangle, LayoutPanelTop } from "lucide-react";
|
|
||||||
import {
|
import {
|
||||||
SidebarAssigneeSelect,
|
SidebarAssigneeSelect,
|
||||||
SidebarCycleSelect,
|
SidebarCycleSelect,
|
||||||
@ -39,13 +39,15 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
// states
|
// states
|
||||||
const [linkModal, setLinkModal] = useState(false);
|
const [linkModal, setLinkModal] = useState(false);
|
||||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
user: { currentProjectRole },
|
|
||||||
issueDetail: { fetchPeekIssueDetails },
|
issueDetail: { fetchPeekIssueDetails },
|
||||||
project: { getProjectById },
|
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
|
membership: { currentProjectRole },
|
||||||
|
} = useUser();
|
||||||
|
const { getProjectById } = useProject();
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
|
@ -4,15 +4,13 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { TwitterPicker } from "react-color";
|
import { TwitterPicker } from "react-color";
|
||||||
import { Popover, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
// mobx store
|
import { Plus, X } from "lucide-react";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useLabel } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// ui
|
// ui
|
||||||
import { Input } from "@plane/ui";
|
import { Input } from "@plane/ui";
|
||||||
import { IssueLabelSelect } from "../select";
|
import { IssueLabelSelect } from "../select";
|
||||||
// icons
|
|
||||||
import { Plus, X } from "lucide-react";
|
|
||||||
// types
|
// types
|
||||||
import { IIssue, IIssueLabel } from "types";
|
import { IIssue, IIssueLabel } from "types";
|
||||||
|
|
||||||
@ -40,8 +38,8 @@ export const SidebarLabelSelect: React.FC<Props> = observer((props) => {
|
|||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
// mobx store
|
// mobx store
|
||||||
const {
|
const {
|
||||||
projectLabel: { projectLabels, createLabel },
|
project: { projectLabels, createLabel },
|
||||||
} = useMobxStore();
|
} = useLabel();
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
@ -3,9 +3,10 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
import { Controller, UseFormWatch } from "react-hook-form";
|
import { Controller, UseFormWatch } from "react-hook-form";
|
||||||
// mobx store
|
import { Bell, CalendarDays, LinkIcon, Plus, Signal, Tag, Trash2, Triangle, LayoutPanelTop } from "lucide-react";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useProjectState, useUser } from "hooks/store";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
import useUserIssueNotificationSubscription from "hooks/use-issue-notification-subscription";
|
import useUserIssueNotificationSubscription from "hooks/use-issue-notification-subscription";
|
||||||
import useEstimateOption from "hooks/use-estimate-option";
|
import useEstimateOption from "hooks/use-estimate-option";
|
||||||
@ -32,7 +33,6 @@ import {
|
|||||||
// ui
|
// ui
|
||||||
import { CustomDatePicker } from "components/ui";
|
import { CustomDatePicker } from "components/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Bell, CalendarDays, LinkIcon, Plus, Signal, Tag, Trash2, Triangle, LayoutPanelTop } from "lucide-react";
|
|
||||||
import { Button, ContrastIcon, DiceIcon, DoubleCircleIcon, StateGroupIcon, UserGroupIcon } from "@plane/ui";
|
import { Button, ContrastIcon, DiceIcon, DoubleCircleIcon, StateGroupIcon, UserGroupIcon } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
@ -75,18 +75,21 @@ const moduleService = new ModuleService();
|
|||||||
|
|
||||||
export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||||
const { control, submitChanges, issueDetail, watch: watchIssue, fieldsToShow = ["all"], uneditable = false } = props;
|
const { control, submitChanges, issueDetail, watch: watchIssue, fieldsToShow = ["all"], uneditable = false } = props;
|
||||||
|
// states
|
||||||
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
||||||
const [linkModal, setLinkModal] = useState(false);
|
const [linkModal, setLinkModal] = useState(false);
|
||||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
user: { currentUser, currentProjectRole },
|
|
||||||
projectState: { states },
|
|
||||||
projectIssues: { removeIssue },
|
projectIssues: { removeIssue },
|
||||||
issueDetail: { createIssueLink, updateIssueLink, deleteIssueLink },
|
issueDetail: { createIssueLink, updateIssueLink, deleteIssueLink },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
|
currentUser,
|
||||||
|
membership: { currentProjectRole },
|
||||||
|
} = useUser();
|
||||||
|
const { projectStates } = useProjectState();
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, issueId, inboxIssueId } = router.query;
|
const { workspaceSlug, projectId, issueId, inboxIssueId } = router.query;
|
||||||
|
|
||||||
@ -190,9 +193,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
const currentIssueState = projectId
|
const currentIssueState = projectStates?.find((s) => s.id === issueDetail?.state);
|
||||||
? states[projectId.toString()]?.find((s) => s.id === issueDetail?.state)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -3,8 +3,10 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
import { Plus, ChevronRight, ChevronDown } from "lucide-react";
|
import { Plus, ChevronRight, ChevronDown } from "lucide-react";
|
||||||
// mobx store
|
// hooks
|
||||||
|
import { useUser } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { ExistingIssuesListModal } from "components/core";
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
@ -12,8 +14,6 @@ import { SubIssuesRootList } from "./issues-list";
|
|||||||
import { ProgressBar } from "./progressbar";
|
import { ProgressBar } from "./progressbar";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu } from "@plane/ui";
|
import { CustomMenu } from "@plane/ui";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -43,13 +43,15 @@ const issueService = new IssueService();
|
|||||||
|
|
||||||
export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
||||||
const { parentIssue, user } = props;
|
const { parentIssue, user } = props;
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
user: { currentProjectRole },
|
|
||||||
issue: { updateIssueStructure },
|
issue: { updateIssueStructure },
|
||||||
projectIssues: { updateIssue, removeIssue },
|
projectIssues: { updateIssue, removeIssue },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
|
membership: { currentProjectRole },
|
||||||
|
} = useUser();
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { TwitterPicker } from "react-color";
|
import { TwitterPicker } from "react-color";
|
||||||
import { Dialog, Popover, Transition } from "@headlessui/react";
|
import { Dialog, Popover, Transition } from "@headlessui/react";
|
||||||
|
import { ChevronDown } from "lucide-react";
|
||||||
// store
|
// hooks
|
||||||
import { observer } from "mobx-react-lite";
|
import { useLabel } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import useToast from "hooks/use-toast";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
// icons
|
|
||||||
import { ChevronDown } from "lucide-react";
|
|
||||||
// types
|
// types
|
||||||
import type { IIssueLabel, IState } from "types";
|
import type { IIssueLabel, IState } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { LABEL_COLOR_OPTIONS, getRandomLabelColor } from "constants/label";
|
import { LABEL_COLOR_OPTIONS, getRandomLabelColor } from "constants/label";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
// types
|
// types
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -32,13 +30,14 @@ const defaultValues: Partial<IState> = {
|
|||||||
|
|
||||||
export const CreateLabelModal: React.FC<Props> = observer((props) => {
|
export const CreateLabelModal: React.FC<Props> = observer((props) => {
|
||||||
const { isOpen, projectId, handleClose, onSuccess } = props;
|
const { isOpen, projectId, handleClose, onSuccess } = props;
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
// store hooks
|
||||||
// store
|
const {
|
||||||
const { projectLabel: projectLabelStore } = useMobxStore();
|
project: { createLabel },
|
||||||
|
} = useLabel();
|
||||||
|
// form info
|
||||||
const {
|
const {
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -72,8 +71,7 @@ export const CreateLabelModal: React.FC<Props> = observer((props) => {
|
|||||||
const onSubmit = async (formData: IIssueLabel) => {
|
const onSubmit = async (formData: IIssueLabel) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
await projectLabelStore
|
await createLabel(workspaceSlug.toString(), projectId.toString(), formData)
|
||||||
.createLabel(workspaceSlug.toString(), projectId.toString(), formData)
|
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
onClose();
|
onClose();
|
||||||
if (onSuccess) onSuccess(res);
|
if (onSuccess) onSuccess(res);
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
import React, { forwardRef, useEffect } from "react";
|
import React, { forwardRef, useEffect } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
import { TwitterPicker } from "react-color";
|
import { TwitterPicker } from "react-color";
|
||||||
import { Controller, SubmitHandler, useForm } from "react-hook-form";
|
import { Controller, SubmitHandler, useForm } from "react-hook-form";
|
||||||
|
|
||||||
// stores
|
|
||||||
import { observer } from "mobx-react-lite";
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// headless ui
|
|
||||||
import { Popover, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
|
// hooks
|
||||||
|
import { useLabel } from "hooks/store";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IIssueLabel } from "types";
|
import { IIssueLabel } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { getRandomLabelColor, LABEL_COLOR_OPTIONS } from "constants/label";
|
import { getRandomLabelColor, LABEL_COLOR_OPTIONS } from "constants/label";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
labelForm: boolean;
|
labelForm: boolean;
|
||||||
@ -32,16 +30,16 @@ const defaultValues: Partial<IIssueLabel> = {
|
|||||||
export const CreateUpdateLabelInline = observer(
|
export const CreateUpdateLabelInline = observer(
|
||||||
forwardRef<HTMLFormElement, Props>(function CreateUpdateLabelInline(props, ref) {
|
forwardRef<HTMLFormElement, Props>(function CreateUpdateLabelInline(props, ref) {
|
||||||
const { labelForm, setLabelForm, isUpdating, labelToUpdate, onClose } = props;
|
const { labelForm, setLabelForm, isUpdating, labelToUpdate, onClose } = props;
|
||||||
|
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
// store
|
const {
|
||||||
const { projectLabel: projectLabelStore } = useMobxStore();
|
project: { createLabel, updateLabel },
|
||||||
|
} = useLabel();
|
||||||
|
// toast alert
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
// form info
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
@ -63,8 +61,7 @@ export const CreateUpdateLabelInline = observer(
|
|||||||
const handleLabelCreate: SubmitHandler<IIssueLabel> = async (formData) => {
|
const handleLabelCreate: SubmitHandler<IIssueLabel> = async (formData) => {
|
||||||
if (!workspaceSlug || !projectId || isSubmitting) return;
|
if (!workspaceSlug || !projectId || isSubmitting) return;
|
||||||
|
|
||||||
await projectLabelStore
|
await createLabel(workspaceSlug.toString(), projectId.toString(), formData)
|
||||||
.createLabel(workspaceSlug.toString(), projectId.toString(), formData)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
handleClose();
|
handleClose();
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
@ -82,8 +79,7 @@ export const CreateUpdateLabelInline = observer(
|
|||||||
const handleLabelUpdate: SubmitHandler<IIssueLabel> = async (formData) => {
|
const handleLabelUpdate: SubmitHandler<IIssueLabel> = async (formData) => {
|
||||||
if (!workspaceSlug || !projectId || isSubmitting) return;
|
if (!workspaceSlug || !projectId || isSubmitting) return;
|
||||||
|
|
||||||
await projectLabelStore
|
await updateLabel(workspaceSlug.toString(), projectId.toString(), labelToUpdate?.id!, formData)
|
||||||
.updateLabel(workspaceSlug.toString(), projectId.toString(), labelToUpdate?.id!, formData)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
handleClose();
|
handleClose();
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
||||||
|
import { Search } from "lucide-react";
|
||||||
// store
|
// hooks
|
||||||
import { observer } from "mobx-react-lite";
|
import { useLabel } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
|
|
||||||
// icons
|
// icons
|
||||||
import { LayerStackIcon } from "@plane/ui";
|
import { LayerStackIcon } from "@plane/ui";
|
||||||
import { Search } from "lucide-react";
|
|
||||||
// types
|
// types
|
||||||
import { IIssueLabel } from "types";
|
import { IIssueLabel } from "types";
|
||||||
|
|
||||||
@ -21,18 +19,15 @@ type Props = {
|
|||||||
|
|
||||||
export const LabelsListModal: React.FC<Props> = observer((props) => {
|
export const LabelsListModal: React.FC<Props> = observer((props) => {
|
||||||
const { isOpen, handleClose, parent } = props;
|
const { isOpen, handleClose, parent } = props;
|
||||||
|
// states
|
||||||
|
const [query, setQuery] = useState("");
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
// store
|
|
||||||
const {
|
const {
|
||||||
projectLabel: { projectLabels, fetchProjectLabels, updateLabel },
|
project: { projectLabels, fetchProjectLabels, updateLabel },
|
||||||
} = useMobxStore();
|
} = useLabel();
|
||||||
|
|
||||||
// states
|
|
||||||
const [query, setQuery] = useState("");
|
|
||||||
|
|
||||||
// api call to fetch project details
|
// api call to fetch project details
|
||||||
useSWR(
|
useSWR(
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React, { Dispatch, SetStateAction, useState } from "react";
|
import React, { Dispatch, SetStateAction, useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
import { DraggableProvidedDragHandleProps, DraggableStateSnapshot } from "@hello-pangea/dnd";
|
import { DraggableProvidedDragHandleProps, DraggableStateSnapshot } from "@hello-pangea/dnd";
|
||||||
|
import { X, Pencil } from "lucide-react";
|
||||||
|
// hooks
|
||||||
|
import { useLabel } from "hooks/store";
|
||||||
// types
|
// types
|
||||||
import { IIssueLabel } from "types";
|
import { IIssueLabel } from "types";
|
||||||
//icons
|
// components
|
||||||
import { X, Pencil } from "lucide-react";
|
|
||||||
//components
|
|
||||||
import { ICustomMenuItem, LabelItemBlock } from "./label-block/label-item-block";
|
import { ICustomMenuItem, LabelItemBlock } from "./label-block/label-item-block";
|
||||||
import { CreateUpdateLabelInline } from "./create-update-label-inline";
|
import { CreateUpdateLabelInline } from "./create-update-label-inline";
|
||||||
|
|
||||||
@ -21,23 +21,21 @@ type Props = {
|
|||||||
|
|
||||||
export const ProjectSettingLabelItem: React.FC<Props> = (props) => {
|
export const ProjectSettingLabelItem: React.FC<Props> = (props) => {
|
||||||
const { label, setIsUpdating, handleLabelDelete, draggableSnapshot, dragHandleProps, isChild } = props;
|
const { label, setIsUpdating, handleLabelDelete, draggableSnapshot, dragHandleProps, isChild } = props;
|
||||||
|
|
||||||
const { combineTargetFor, isDragging } = draggableSnapshot;
|
const { combineTargetFor, isDragging } = draggableSnapshot;
|
||||||
|
// states
|
||||||
|
const [isEditLabelForm, setEditLabelForm] = useState(false);
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
// store
|
const {
|
||||||
const { projectLabel: projectLabelStore } = useMobxStore();
|
project: { updateLabel },
|
||||||
|
} = useLabel();
|
||||||
//state
|
|
||||||
const [isEditLabelForm, setEditLabelForm] = useState(false);
|
|
||||||
|
|
||||||
const removeFromGroup = (label: IIssueLabel) => {
|
const removeFromGroup = (label: IIssueLabel) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
projectLabelStore.updateLabel(workspaceSlug.toString(), projectId.toString(), label.id, {
|
updateLabel(workspaceSlug.toString(), projectId.toString(), label.id, {
|
||||||
parent: null,
|
parent: null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -10,9 +10,8 @@ import {
|
|||||||
DropResult,
|
DropResult,
|
||||||
Droppable,
|
Droppable,
|
||||||
} from "@hello-pangea/dnd";
|
} from "@hello-pangea/dnd";
|
||||||
// store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useLabel } from "hooks/store";
|
||||||
import useDraggableInPortal from "hooks/use-draggable-portal";
|
import useDraggableInPortal from "hooks/use-draggable-portal";
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
@ -32,23 +31,22 @@ import { IIssueLabel } from "types";
|
|||||||
const LABELS_ROOT = "labels.root";
|
const LABELS_ROOT = "labels.root";
|
||||||
|
|
||||||
export const ProjectSettingsLabelList: React.FC = observer(() => {
|
export const ProjectSettingsLabelList: React.FC = observer(() => {
|
||||||
// router
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, projectId } = router.query;
|
|
||||||
|
|
||||||
const renderDraggable = useDraggableInPortal();
|
|
||||||
|
|
||||||
// store
|
|
||||||
const {
|
|
||||||
projectLabel: { fetchProjectLabels, projectLabels, updateLabelPosition, projectLabelsTree },
|
|
||||||
} = useMobxStore();
|
|
||||||
// states
|
// states
|
||||||
const [showLabelForm, setLabelForm] = useState(false);
|
const [showLabelForm, setLabelForm] = useState(false);
|
||||||
const [isUpdating, setIsUpdating] = useState(false);
|
const [isUpdating, setIsUpdating] = useState(false);
|
||||||
const [selectDeleteLabel, setSelectDeleteLabel] = useState<IIssueLabel | null>(null);
|
const [selectDeleteLabel, setSelectDeleteLabel] = useState<IIssueLabel | null>(null);
|
||||||
const [isDraggingGroup, setIsDraggingGroup] = useState(false);
|
const [isDraggingGroup, setIsDraggingGroup] = useState(false);
|
||||||
// ref
|
// refs
|
||||||
const scrollToRef = useRef<HTMLFormElement>(null);
|
const scrollToRef = useRef<HTMLFormElement>(null);
|
||||||
|
// router
|
||||||
|
const router = useRouter();
|
||||||
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
|
const {
|
||||||
|
project: { fetchProjectLabels, projectLabels, updateLabelPosition, projectLabelsTree },
|
||||||
|
} = useLabel();
|
||||||
|
// portal
|
||||||
|
const renderDraggable = useDraggableInPortal();
|
||||||
|
|
||||||
// api call to fetch project details
|
// api call to fetch project details
|
||||||
useSWR(
|
useSWR(
|
||||||
|
@ -2,9 +2,9 @@ import { useState } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useProject, useUser } from "hooks/store";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { ConfirmProjectMemberRemove } from "components/project";
|
import { ConfirmProjectMemberRemove } from "components/project";
|
||||||
@ -28,14 +28,16 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
// store
|
|
||||||
const {
|
const {
|
||||||
user: { currentUser, currentProjectMemberInfo, currentProjectRole, leaveProject },
|
|
||||||
projectMember: { removeMemberFromProject, updateMember },
|
projectMember: { removeMemberFromProject, updateMember },
|
||||||
project: { fetchProjects },
|
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// hooks
|
const {
|
||||||
|
currentUser,
|
||||||
|
membership: { currentProjectMemberInfo, currentProjectRole, leaveProject },
|
||||||
|
} = useUser();
|
||||||
|
const { fetchProjects } = useProject();
|
||||||
|
// toast alert
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
// derived values
|
// derived values
|
||||||
|
@ -2,7 +2,8 @@ import { useState } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
// hooks
|
||||||
|
import { useApplication } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
import { ProjectMemberListItem, SendProjectInvitationModal } from "components/project";
|
import { ProjectMemberListItem, SendProjectInvitationModal } from "components/project";
|
||||||
@ -12,19 +13,19 @@ import { Button, Loader } from "@plane/ui";
|
|||||||
import { Search } from "lucide-react";
|
import { Search } from "lucide-react";
|
||||||
|
|
||||||
export const ProjectMemberList: React.FC = observer(() => {
|
export const ProjectMemberList: React.FC = observer(() => {
|
||||||
// router
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, projectId } = router.query;
|
|
||||||
|
|
||||||
// store
|
|
||||||
const {
|
|
||||||
projectMember: { projectMembers, fetchProjectMembers },
|
|
||||||
trackEvent: { setTrackElement },
|
|
||||||
} = useMobxStore();
|
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [inviteModal, setInviteModal] = useState(false);
|
const [inviteModal, setInviteModal] = useState(false);
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
// router
|
||||||
|
const router = useRouter();
|
||||||
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
|
const {
|
||||||
|
projectMember: { projectMembers, fetchProjectMembers },
|
||||||
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
|
eventTracker: { setTrackElement },
|
||||||
|
} = useApplication();
|
||||||
|
|
||||||
const searchedMembers = (projectMembers ?? []).filter((member) => {
|
const searchedMembers = (projectMembers ?? []).filter((member) => {
|
||||||
const fullName = `${member.member.first_name} ${member.member.last_name}`.toLowerCase();
|
const fullName = `${member.member.first_name} ${member.member.last_name}`.toLowerCase();
|
||||||
|
@ -4,14 +4,14 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { useForm, Controller, useFieldArray } from "react-hook-form";
|
import { useForm, Controller, useFieldArray } from "react-hook-form";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
import { ChevronDown, Plus, X } from "lucide-react";
|
import { ChevronDown, Plus, X } from "lucide-react";
|
||||||
// mobx store
|
// hooks
|
||||||
|
import { useApplication, useUser, useWorkspace } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// ui
|
// ui
|
||||||
import { Avatar, Button, CustomSelect, CustomSearchSelect } from "@plane/ui";
|
import { Avatar, Button, CustomSelect, CustomSearchSelect } from "@plane/ui";
|
||||||
// services
|
// services
|
||||||
import { ProjectMemberService } from "services/project";
|
import { ProjectMemberService } from "services/project";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// types
|
// types
|
||||||
import { IProjectMember, TUserProjectRole } from "types";
|
import { IProjectMember, TUserProjectRole } from "types";
|
||||||
// constants
|
// constants
|
||||||
@ -47,19 +47,23 @@ const projectMemberService = new ProjectMemberService();
|
|||||||
|
|
||||||
export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
|
export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
|
||||||
const { isOpen, members, onClose, onSuccess } = props;
|
const { isOpen, members, onClose, onSuccess } = props;
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// toast alert
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
user: { currentProjectRole },
|
|
||||||
workspaceMember: { workspaceMembers },
|
workspaceMember: { workspaceMembers },
|
||||||
trackEvent: { postHogEventTracker },
|
|
||||||
workspace: { currentWorkspace },
|
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const {
|
||||||
|
eventTracker: { postHogEventTracker },
|
||||||
|
} = useApplication();
|
||||||
|
const {
|
||||||
|
membership: { currentProjectRole },
|
||||||
|
} = useUser();
|
||||||
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
// form info
|
||||||
const {
|
const {
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
reset,
|
reset,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
// hooks
|
||||||
// mobx store
|
import { useLabel, useProjectState } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
import { AppliedFiltersList, FilterSelection, FiltersDropdown } from "components/issues";
|
import { AppliedFiltersList, FilterSelection, FiltersDropdown } from "components/issues";
|
||||||
@ -25,12 +25,16 @@ const defaultValues: Partial<IProjectView> = {
|
|||||||
description: "",
|
description: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ProjectViewForm: React.FC<Props> = observer(({ handleFormSubmit, handleClose, data, preLoadedData }) => {
|
export const ProjectViewForm: React.FC<Props> = observer((props) => {
|
||||||
|
const { handleFormSubmit, handleClose, data, preLoadedData } = props;
|
||||||
|
// store hooks
|
||||||
const {
|
const {
|
||||||
projectLabel: { projectLabels },
|
|
||||||
projectState: projectStateStore,
|
|
||||||
projectMember: { projectMembers },
|
projectMember: { projectMembers },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
const { projectStates } = useProjectState();
|
||||||
|
const {
|
||||||
|
project: { projectLabels },
|
||||||
|
} = useLabel();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -176,7 +180,7 @@ export const ProjectViewForm: React.FC<Props> = observer(({ handleFormSubmit, ha
|
|||||||
layoutDisplayFiltersOptions={ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues.list}
|
layoutDisplayFiltersOptions={ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues.list}
|
||||||
labels={projectLabels ?? undefined}
|
labels={projectLabels ?? undefined}
|
||||||
members={projectMembers?.map((m) => m.member) ?? undefined}
|
members={projectMembers?.map((m) => m.member) ?? undefined}
|
||||||
states={projectStateStore.projectStates ?? undefined}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
)}
|
)}
|
||||||
@ -190,7 +194,7 @@ export const ProjectViewForm: React.FC<Props> = observer(({ handleFormSubmit, ha
|
|||||||
handleRemoveFilter={handleRemoveFilter}
|
handleRemoveFilter={handleRemoveFilter}
|
||||||
labels={projectLabels ?? []}
|
labels={projectLabels ?? []}
|
||||||
members={projectMembers?.map((m) => m.member) ?? []}
|
members={projectMembers?.map((m) => m.member) ?? []}
|
||||||
states={projectStateStore.projectStates ?? []}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -3,9 +3,9 @@ import Link from "next/link";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { LinkIcon, PencilIcon, StarIcon, TrashIcon } from "lucide-react";
|
import { LinkIcon, PencilIcon, StarIcon, TrashIcon } from "lucide-react";
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useUser } from "hooks/store";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { CreateUpdateProjectViewModal, DeleteProjectViewModal } from "components/views";
|
import { CreateUpdateProjectViewModal, DeleteProjectViewModal } from "components/views";
|
||||||
@ -25,19 +25,19 @@ type Props = {
|
|||||||
|
|
||||||
export const ProjectViewListItem: React.FC<Props> = observer((props) => {
|
export const ProjectViewListItem: React.FC<Props> = observer((props) => {
|
||||||
const { view } = props;
|
const { view } = props;
|
||||||
|
// states
|
||||||
const [createUpdateViewModal, setCreateUpdateViewModal] = useState(false);
|
const [createUpdateViewModal, setCreateUpdateViewModal] = useState(false);
|
||||||
const [deleteViewModal, setDeleteViewModal] = useState(false);
|
const [deleteViewModal, setDeleteViewModal] = useState(false);
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// toast alert
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
// store hooks
|
||||||
|
const { projectViews: projectViewsStore } = useMobxStore();
|
||||||
const {
|
const {
|
||||||
projectViews: projectViewsStore,
|
membership: { currentProjectRole },
|
||||||
user: { currentProjectRole },
|
} = useUser();
|
||||||
} = useMobxStore();
|
|
||||||
|
|
||||||
const handleAddToFavorites = () => {
|
const handleAddToFavorites = () => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { Plus, Search } from "lucide-react";
|
||||||
// mobx store
|
// hooks
|
||||||
|
import { useApplication, useUser } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
import { ProjectViewListItem } from "components/views";
|
import { ProjectViewListItem } from "components/views";
|
||||||
@ -11,22 +12,23 @@ import { NewEmptyState } from "components/common/new-empty-state";
|
|||||||
import { Input, Loader } from "@plane/ui";
|
import { Input, Loader } from "@plane/ui";
|
||||||
// assets
|
// assets
|
||||||
import emptyView from "public/empty-state/empty_view.webp";
|
import emptyView from "public/empty-state/empty_view.webp";
|
||||||
// icons
|
|
||||||
import { Plus, Search } from "lucide-react";
|
|
||||||
// constants
|
// constants
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export const ProjectViewsList = observer(() => {
|
export const ProjectViewsList = observer(() => {
|
||||||
|
// states
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { projectId } = router.query;
|
const { projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
|
const { projectViews: projectViewsStore } = useMobxStore();
|
||||||
const {
|
const {
|
||||||
projectViews: projectViewsStore,
|
commandPalette: { toggleCreateViewModal },
|
||||||
commandPalette: commandPaletteStore,
|
} = useApplication();
|
||||||
user: { currentProjectRole },
|
const {
|
||||||
} = useMobxStore();
|
membership: { currentProjectRole },
|
||||||
|
} = useUser();
|
||||||
|
|
||||||
const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined;
|
const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined;
|
||||||
|
|
||||||
@ -79,7 +81,7 @@ export const ProjectViewsList = observer(() => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
icon: <Plus size={14} strokeWidth={2} />,
|
icon: <Plus size={14} strokeWidth={2} />,
|
||||||
text: "Build your first view",
|
text: "Build your first view",
|
||||||
onClick: () => commandPaletteStore.toggleCreateViewModal(true),
|
onClick: () => toggleCreateViewModal(true),
|
||||||
}}
|
}}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
|
@ -4,9 +4,9 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
import { ChevronDown, Dot, XCircle } from "lucide-react";
|
import { ChevronDown, Dot, XCircle } from "lucide-react";
|
||||||
// mobx store
|
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useUser } from "hooks/store";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { ConfirmWorkspaceMemberRemove } from "components/workspace";
|
import { ConfirmWorkspaceMemberRemove } from "components/workspace";
|
||||||
@ -35,17 +35,21 @@ type Props = {
|
|||||||
|
|
||||||
export const WorkspaceMembersListItem: FC<Props> = observer((props) => {
|
export const WorkspaceMembersListItem: FC<Props> = observer((props) => {
|
||||||
const { member } = props;
|
const { member } = props;
|
||||||
|
// states
|
||||||
|
const [removeMemberModal, setRemoveMemberModal] = useState(false);
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store
|
// store hooks
|
||||||
const {
|
const {
|
||||||
workspaceMember: { removeMember, updateMember, updateMemberInvitation, deleteWorkspaceInvitation },
|
workspaceMember: { removeMember, updateMember, updateMemberInvitation, deleteWorkspaceInvitation },
|
||||||
user: { currentWorkspaceMemberInfo, currentWorkspaceRole, currentUser, currentUserSettings, leaveWorkspace },
|
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// states
|
const {
|
||||||
const [removeMemberModal, setRemoveMemberModal] = useState(false);
|
currentUser,
|
||||||
// hooks
|
currentUserSettings,
|
||||||
|
membership: { currentWorkspaceMemberInfo, currentWorkspaceRole, leaveWorkspace },
|
||||||
|
} = useUser();
|
||||||
|
// toast alert
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const handleLeaveWorkspace = async () => {
|
const handleLeaveWorkspace = async () => {
|
||||||
|
@ -2,10 +2,10 @@ import { useContext } from "react";
|
|||||||
// mobx store
|
// mobx store
|
||||||
import { MobxStoreContext } from "lib/mobx/store-provider";
|
import { MobxStoreContext } from "lib/mobx/store-provider";
|
||||||
// types
|
// types
|
||||||
import { ILabelStore } from "store/label.store";
|
import { ILabelRootStore } from "store/label";
|
||||||
|
|
||||||
export const useLabel = (): ILabelStore => {
|
export const useLabel = (): ILabelRootStore => {
|
||||||
const context = useContext(MobxStoreContext);
|
const context = useContext(MobxStoreContext);
|
||||||
if (context === undefined) throw new Error("useMobxStore must be used within MobxStoreProvider");
|
if (context === undefined) throw new Error("useMobxStore must be used within MobxStoreProvider");
|
||||||
return context.label;
|
return context.labelRoot;
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
// hooks
|
// hooks
|
||||||
|
import { useApplication, useCycle, useLabel, useModule, useProjectState, useUser } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
import { Spinner } from "@plane/ui";
|
import { Spinner } from "@plane/ui";
|
||||||
@ -10,7 +11,6 @@ import { JoinProject } from "components/auth-screens";
|
|||||||
import { EmptyState } from "components/common";
|
import { EmptyState } from "components/common";
|
||||||
// images
|
// images
|
||||||
import emptyProject from "public/empty-state/project.svg";
|
import emptyProject from "public/empty-state/project.svg";
|
||||||
import { useApplication, useCycle, useModule, useProjectState, useUser } from "hooks/store";
|
|
||||||
|
|
||||||
interface IProjectAuthWrapper {
|
interface IProjectAuthWrapper {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -21,7 +21,6 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
|
|||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
project: { fetchProjectDetails, workspaceProjects },
|
project: { fetchProjectDetails, workspaceProjects },
|
||||||
projectLabel: { fetchProjectLabels },
|
|
||||||
projectMember: { fetchProjectMembers },
|
projectMember: { fetchProjectMembers },
|
||||||
projectEstimates: { fetchProjectEstimates },
|
projectEstimates: { fetchProjectEstimates },
|
||||||
projectViews: { fetchAllViews },
|
projectViews: { fetchAllViews },
|
||||||
@ -36,6 +35,9 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
|
|||||||
const { fetchAllCycles } = useCycle();
|
const { fetchAllCycles } = useCycle();
|
||||||
const { fetchModules } = useModule();
|
const { fetchModules } = useModule();
|
||||||
const { fetchProjectStates } = useProjectState();
|
const { fetchProjectStates } = useProjectState();
|
||||||
|
const {
|
||||||
|
project: { fetchProjectLabels },
|
||||||
|
} = useLabel();
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
@ -4,7 +4,7 @@ import Link from "next/link";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useProject, useUser } from "hooks/store";
|
import { useLabel, useProject, useUser } from "hooks/store";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// icons
|
// icons
|
||||||
import { Button, Spinner } from "@plane/ui";
|
import { Button, Spinner } from "@plane/ui";
|
||||||
@ -17,13 +17,15 @@ export const WorkspaceAuthWrapper: FC<IWorkspaceAuthWrapper> = observer((props)
|
|||||||
const { children } = props;
|
const { children } = props;
|
||||||
// store hooks
|
// store hooks
|
||||||
const {
|
const {
|
||||||
workspace: { fetchWorkspaceLabels },
|
|
||||||
workspaceMember: { fetchWorkspaceMembers, fetchWorkspaceUserProjectsRole },
|
workspaceMember: { fetchWorkspaceMembers, fetchWorkspaceUserProjectsRole },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
const {
|
const {
|
||||||
membership: { currentWorkspaceMemberInfo, hasPermissionToCurrentWorkspace, fetchUserWorkspaceInfo },
|
membership: { currentWorkspaceMemberInfo, hasPermissionToCurrentWorkspace, fetchUserWorkspaceInfo },
|
||||||
} = useUser();
|
} = useUser();
|
||||||
const { fetchProjects } = useProject();
|
const { fetchProjects } = useProject();
|
||||||
|
const {
|
||||||
|
workspace: { fetchWorkspaceLabels },
|
||||||
|
} = useLabel();
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
47
web/store/label/index.ts
Normal file
47
web/store/label/index.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { computed, observable, makeObservable } from "mobx";
|
||||||
|
import { RootStore } from "../root.store";
|
||||||
|
// types
|
||||||
|
import { IIssueLabel } from "types";
|
||||||
|
import { IProjectLabelStore, ProjectLabelStore } from "./project-label.store";
|
||||||
|
import { IWorkspaceLabelStore, WorkspaceLabelStore } from "./workspace-label.store";
|
||||||
|
|
||||||
|
export interface ILabelRootStore {
|
||||||
|
// observables
|
||||||
|
labelMap: Record<string, IIssueLabel>;
|
||||||
|
// computed actions
|
||||||
|
getLabelById: (labelId: string) => IIssueLabel | null;
|
||||||
|
// sub-stores
|
||||||
|
project: IProjectLabelStore;
|
||||||
|
workspace: IWorkspaceLabelStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LabelRootStore implements ILabelRootStore {
|
||||||
|
// observables
|
||||||
|
labelMap: Record<string, IIssueLabel> = {};
|
||||||
|
// root store
|
||||||
|
rootStore;
|
||||||
|
// sub-stores
|
||||||
|
project: IProjectLabelStore;
|
||||||
|
workspace: IWorkspaceLabelStore;
|
||||||
|
|
||||||
|
constructor(_rootStore: RootStore) {
|
||||||
|
makeObservable(this, {
|
||||||
|
// observables
|
||||||
|
labelMap: observable,
|
||||||
|
// computed actions
|
||||||
|
getLabelById: computed,
|
||||||
|
});
|
||||||
|
|
||||||
|
// root store
|
||||||
|
this.rootStore = _rootStore;
|
||||||
|
// sub-stores
|
||||||
|
this.project = new ProjectLabelStore(_rootStore);
|
||||||
|
this.workspace = new WorkspaceLabelStore(_rootStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get label info from the map of labels in the store using label id
|
||||||
|
* @param labelId
|
||||||
|
*/
|
||||||
|
getLabelById = (labelId: string): IIssueLabel | null => this.labelMap?.[labelId] || null;
|
||||||
|
}
|
231
web/store/label/project-label.store.ts
Normal file
231
web/store/label/project-label.store.ts
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
import { action, computed, makeObservable, runInAction } from "mobx";
|
||||||
|
import { set } from "lodash";
|
||||||
|
// services
|
||||||
|
import { IssueLabelService } from "services/issue";
|
||||||
|
// helpers
|
||||||
|
import { buildTree } from "helpers/array.helper";
|
||||||
|
// types
|
||||||
|
import { RootStore } from "store/root.store";
|
||||||
|
import { IIssueLabel } from "types";
|
||||||
|
|
||||||
|
export interface IProjectLabelStore {
|
||||||
|
// computed
|
||||||
|
projectLabels: IIssueLabel[] | undefined;
|
||||||
|
projectLabelsTree: IIssueLabel[] | undefined;
|
||||||
|
// actions
|
||||||
|
fetchProjectLabels: (workspaceSlug: string, projectId: string) => Promise<IIssueLabel[]>;
|
||||||
|
createLabel: (workspaceSlug: string, projectId: string, data: Partial<IIssueLabel>) => Promise<IIssueLabel>;
|
||||||
|
updateLabel: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
labelId: string,
|
||||||
|
data: Partial<IIssueLabel>
|
||||||
|
) => Promise<IIssueLabel>;
|
||||||
|
updateLabelPosition: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
labelId: string,
|
||||||
|
parentId: string | null | undefined,
|
||||||
|
index: number,
|
||||||
|
isSameParent: boolean,
|
||||||
|
prevIndex: number | undefined
|
||||||
|
) => Promise<IIssueLabel | undefined>;
|
||||||
|
deleteLabel: (workspaceSlug: string, projectId: string, labelId: string) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ProjectLabelStore implements IProjectLabelStore {
|
||||||
|
// root store
|
||||||
|
rootStore;
|
||||||
|
// root store labelMap
|
||||||
|
labelMap: Record<string, IIssueLabel> = {};
|
||||||
|
// services
|
||||||
|
issueLabelService;
|
||||||
|
|
||||||
|
constructor(_rootStore: RootStore) {
|
||||||
|
makeObservable(this, {
|
||||||
|
// computed
|
||||||
|
projectLabels: computed,
|
||||||
|
projectLabelsTree: computed,
|
||||||
|
// actions
|
||||||
|
fetchProjectLabels: action,
|
||||||
|
createLabel: action,
|
||||||
|
updateLabel: action,
|
||||||
|
updateLabelPosition: action,
|
||||||
|
deleteLabel: action,
|
||||||
|
});
|
||||||
|
|
||||||
|
// root store
|
||||||
|
this.rootStore = _rootStore;
|
||||||
|
this.labelMap = this.rootStore.labelRoot.labelMap;
|
||||||
|
// services
|
||||||
|
this.issueLabelService = new IssueLabelService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the labelMap belongs to a specific project
|
||||||
|
*/
|
||||||
|
get projectLabels() {
|
||||||
|
const projectId = this.rootStore.app.router.query?.projectId;
|
||||||
|
if (!projectId) return;
|
||||||
|
return Object.values(this.labelMap).filter((label) => label.project === projectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the labelMap in a tree format
|
||||||
|
*/
|
||||||
|
get projectLabelsTree() {
|
||||||
|
if (!this.projectLabels) return;
|
||||||
|
return buildTree(this.projectLabels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all the labelMap belongs to a specific project
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param projectId
|
||||||
|
* @returns Promise<IIssueLabel[]>
|
||||||
|
*/
|
||||||
|
fetchProjectLabels = async (workspaceSlug: string, projectId: string) => {
|
||||||
|
const response = await this.issueLabelService.getProjectIssueLabels(workspaceSlug, projectId);
|
||||||
|
runInAction(() => {
|
||||||
|
response.forEach((label) => {
|
||||||
|
set(this.labelMap, [label.id], label);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new label for a specific project and add it to the store
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param projectId
|
||||||
|
* @param data
|
||||||
|
* @returns Promise<IIssueLabel>
|
||||||
|
*/
|
||||||
|
createLabel = async (workspaceSlug: string, projectId: string, data: Partial<IIssueLabel>) => {
|
||||||
|
const response = await this.issueLabelService.createIssueLabel(workspaceSlug, projectId, data);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
set(this.labelMap, [response.id], response);
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a label for a specific project and update it in the store
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param projectId
|
||||||
|
* @param labelId
|
||||||
|
* @param data
|
||||||
|
* @returns Promise<IIssueLabel>
|
||||||
|
*/
|
||||||
|
updateLabel = async (workspaceSlug: string, projectId: string, labelId: string, data: Partial<IIssueLabel>) => {
|
||||||
|
const originalLabel = this.labelMap[labelId];
|
||||||
|
try {
|
||||||
|
runInAction(() => {
|
||||||
|
set(this.labelMap, [labelId], { ...this.labelMap[labelId], ...data });
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await this.issueLabelService.patchIssueLabel(workspaceSlug, projectId, labelId, data);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Failed to update label from project store");
|
||||||
|
runInAction(() => {
|
||||||
|
set(this.labelMap, [labelId], originalLabel);
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updates the sort order of a label and updates the label information using API.
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param projectId
|
||||||
|
* @param labelId
|
||||||
|
* @param parentId
|
||||||
|
* @param index
|
||||||
|
* @param isSameParent
|
||||||
|
* @param prevIndex
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
updateLabelPosition = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
labelId: string,
|
||||||
|
parentId: string | null | undefined,
|
||||||
|
index: number,
|
||||||
|
isSameParent: boolean,
|
||||||
|
prevIndex: number | undefined
|
||||||
|
) => {
|
||||||
|
const currLabel = this.labelMap?.[labelId];
|
||||||
|
const labelTree = this.projectLabelsTree;
|
||||||
|
|
||||||
|
let currentArray: IIssueLabel[];
|
||||||
|
|
||||||
|
if (!currLabel || !labelTree) return;
|
||||||
|
|
||||||
|
const data: Partial<IIssueLabel> = { parent: parentId };
|
||||||
|
//find array in which the label is to be added
|
||||||
|
if (!parentId) currentArray = labelTree;
|
||||||
|
else currentArray = labelTree?.find((label) => label.id === parentId)?.children || [];
|
||||||
|
|
||||||
|
//Add the array at the destination
|
||||||
|
if (isSameParent && prevIndex !== undefined) currentArray.splice(prevIndex, 1);
|
||||||
|
|
||||||
|
currentArray.splice(index, 0, currLabel);
|
||||||
|
|
||||||
|
//if currently adding to a new array, then let backend assign a sort order
|
||||||
|
if (currentArray.length > 1) {
|
||||||
|
let prevSortOrder: number | undefined, nextSortOrder: number | undefined;
|
||||||
|
|
||||||
|
if (typeof currentArray[index - 1] !== "undefined") {
|
||||||
|
prevSortOrder = currentArray[index - 1].sort_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof currentArray[index + 1] !== "undefined") {
|
||||||
|
nextSortOrder = currentArray[index + 1].sort_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sortOrder: number;
|
||||||
|
|
||||||
|
//based on the next and previous labelMap calculate current sort order
|
||||||
|
if (prevSortOrder && nextSortOrder) {
|
||||||
|
sortOrder = (prevSortOrder + nextSortOrder) / 2;
|
||||||
|
} else if (nextSortOrder) {
|
||||||
|
sortOrder = nextSortOrder + 10000;
|
||||||
|
} else {
|
||||||
|
sortOrder = prevSortOrder! / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.sort_order = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.updateLabel(workspaceSlug, projectId, labelId, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the label from the project and remove it from the labelMap object
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param projectId
|
||||||
|
* @param labelId
|
||||||
|
*/
|
||||||
|
deleteLabel = async (workspaceSlug: string, projectId: string, labelId: string) => {
|
||||||
|
const originalLabel = this.labelMap[labelId];
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!this.labelMap[labelId]) return;
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
delete this.labelMap[labelId];
|
||||||
|
});
|
||||||
|
|
||||||
|
// deleting using api
|
||||||
|
await this.issueLabelService.deleteIssueLabel(workspaceSlug, projectId, labelId);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Failed to delete label from project store");
|
||||||
|
// reverting back to original label list
|
||||||
|
runInAction(() => {
|
||||||
|
set(this.labelMap, [labelId], originalLabel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
63
web/store/label/workspace-label.store.ts
Normal file
63
web/store/label/workspace-label.store.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { action, computed, makeObservable, runInAction } from "mobx";
|
||||||
|
import { set } from "lodash";
|
||||||
|
// services
|
||||||
|
import { IssueLabelService } from "services/issue";
|
||||||
|
// types
|
||||||
|
import { RootStore } from "store/root.store";
|
||||||
|
import { IIssueLabel } from "types";
|
||||||
|
|
||||||
|
export interface IWorkspaceLabelStore {
|
||||||
|
// computed
|
||||||
|
workspaceLabels: IIssueLabel[] | undefined;
|
||||||
|
// actions
|
||||||
|
fetchWorkspaceLabels: (workspaceSlug: string) => Promise<IIssueLabel[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WorkspaceLabelStore implements IWorkspaceLabelStore {
|
||||||
|
// root store
|
||||||
|
rootStore;
|
||||||
|
// root store labelMap
|
||||||
|
labelMap: Record<string, IIssueLabel> = {};
|
||||||
|
// services
|
||||||
|
issueLabelService;
|
||||||
|
|
||||||
|
constructor(_rootStore: RootStore) {
|
||||||
|
makeObservable(this, {
|
||||||
|
// computed
|
||||||
|
workspaceLabels: computed,
|
||||||
|
// actions
|
||||||
|
fetchWorkspaceLabels: action,
|
||||||
|
});
|
||||||
|
|
||||||
|
// root store
|
||||||
|
this.rootStore = _rootStore;
|
||||||
|
this.labelMap = this.rootStore.labelRoot.labelMap;
|
||||||
|
// services
|
||||||
|
this.issueLabelService = new IssueLabelService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the labelMap belongs to a specific workspace
|
||||||
|
*/
|
||||||
|
get workspaceLabels() {
|
||||||
|
const currentWorkspaceDetails = this.rootStore.workspaceRoot.currentWorkspace;
|
||||||
|
if (!currentWorkspaceDetails) return;
|
||||||
|
return Object.values(this.labelMap).filter((label) => label.workspace === currentWorkspaceDetails.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all the labelMap belongs to a specific project
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param projectId
|
||||||
|
* @returns Promise<IIssueLabel[]>
|
||||||
|
*/
|
||||||
|
fetchWorkspaceLabels = async (workspaceSlug: string) => {
|
||||||
|
const response = await this.issueLabelService.getWorkspaceIssueLabels(workspaceSlug);
|
||||||
|
runInAction(() => {
|
||||||
|
response.forEach((label) => {
|
||||||
|
set(this.labelMap, [label.id], label);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
}
|
@ -8,22 +8,20 @@ import { IssueLabelService, IssueService } from "services/issue";
|
|||||||
import { ProjectService, ProjectStateService } from "services/project";
|
import { ProjectService, ProjectStateService } from "services/project";
|
||||||
|
|
||||||
export interface IProjectStore {
|
export interface IProjectStore {
|
||||||
|
// states
|
||||||
loader: boolean;
|
loader: boolean;
|
||||||
error: any | null;
|
error: any | null;
|
||||||
|
// observables
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
projectId: string | null;
|
|
||||||
projectMap: {
|
projectMap: {
|
||||||
[projectId: string]: IProject; // projectId: project Info
|
[projectId: string]: IProject; // projectId: project Info
|
||||||
};
|
};
|
||||||
|
|
||||||
// computed
|
// computed
|
||||||
searchedProjects: string[];
|
searchedProjects: string[];
|
||||||
workspaceProjects: string[] | null;
|
workspaceProjects: string[] | null;
|
||||||
joinedProjects: string[];
|
joinedProjects: string[];
|
||||||
favoriteProjects: string[];
|
favoriteProjects: string[];
|
||||||
currentProjectDetails: IProject | undefined;
|
currentProjectDetails: IProject | undefined;
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
setSearchQuery: (query: string) => void;
|
setSearchQuery: (query: string) => void;
|
||||||
getProjectById: (projectId: string) => IProject | null;
|
getProjectById: (projectId: string) => IProject | null;
|
||||||
@ -43,15 +41,14 @@ export interface IProjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ProjectStore implements IProjectStore {
|
export class ProjectStore implements IProjectStore {
|
||||||
|
// states
|
||||||
loader: boolean = false;
|
loader: boolean = false;
|
||||||
error: any | null = null;
|
error: any | null = null;
|
||||||
|
// observables
|
||||||
projectId: string | null = null;
|
|
||||||
searchQuery: string = "";
|
searchQuery: string = "";
|
||||||
projectMap: {
|
projectMap: {
|
||||||
[projectId: string]: IProject; // projectId: project Info
|
[projectId: string]: IProject; // projectId: project Info
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
// root store
|
// root store
|
||||||
rootStore: RootStore;
|
rootStore: RootStore;
|
||||||
// service
|
// service
|
||||||
@ -62,24 +59,19 @@ export class ProjectStore implements IProjectStore {
|
|||||||
|
|
||||||
constructor(_rootStore: RootStore) {
|
constructor(_rootStore: RootStore) {
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
// states
|
||||||
loader: observable.ref,
|
loader: observable.ref,
|
||||||
error: observable.ref,
|
error: observable.ref,
|
||||||
|
// observables
|
||||||
searchQuery: observable.ref,
|
searchQuery: observable.ref,
|
||||||
projectId: observable.ref,
|
|
||||||
projectMap: observable,
|
projectMap: observable,
|
||||||
|
|
||||||
// computed
|
// computed
|
||||||
searchedProjects: computed,
|
searchedProjects: computed,
|
||||||
workspaceProjects: computed,
|
workspaceProjects: computed,
|
||||||
|
|
||||||
currentProjectDetails: computed,
|
currentProjectDetails: computed,
|
||||||
|
|
||||||
joinedProjects: computed,
|
joinedProjects: computed,
|
||||||
favoriteProjects: computed,
|
favoriteProjects: computed,
|
||||||
|
// actions
|
||||||
// action
|
|
||||||
setSearchQuery: action,
|
setSearchQuery: action,
|
||||||
fetchProjects: action,
|
fetchProjects: action,
|
||||||
fetchProjectDetails: action,
|
fetchProjectDetails: action,
|
||||||
|
@ -6,11 +6,11 @@ import { CycleStore, ICycleStore } from "./cycle.store";
|
|||||||
import { IProjectViewsStore, ProjectViewsStore } from "./project-view.store";
|
import { IProjectViewsStore, ProjectViewsStore } from "./project-view.store";
|
||||||
import { IModuleStore, ModulesStore } from "./module.store";
|
import { IModuleStore, ModulesStore } from "./module.store";
|
||||||
import { IUserStore, UserStore } from "./user";
|
import { IUserStore, UserStore } from "./user";
|
||||||
import { ILabelStore, LabelStore } from "./label.store";
|
|
||||||
import { IWorkspaceRootStore, WorkspaceRootStore } from "./workspace";
|
import { IWorkspaceRootStore, WorkspaceRootStore } from "./workspace";
|
||||||
import { IssueRootStore, IIssueRootStore } from "./issue/root.store";
|
import { IssueRootStore, IIssueRootStore } from "./issue/root.store";
|
||||||
import { IStateStore, StateStore } from "./state.store";
|
import { IStateStore, StateStore } from "./state.store";
|
||||||
import { IPageStore, PageStore } from "./page.store";
|
import { IPageStore, PageStore } from "./page.store";
|
||||||
|
import { ILabelRootStore, LabelRootStore } from "./label";
|
||||||
|
|
||||||
enableStaticRendering(typeof window === "undefined");
|
enableStaticRendering(typeof window === "undefined");
|
||||||
|
|
||||||
@ -19,11 +19,11 @@ export class RootStore {
|
|||||||
user: IUserStore;
|
user: IUserStore;
|
||||||
workspaceRoot: IWorkspaceRootStore;
|
workspaceRoot: IWorkspaceRootStore;
|
||||||
projectRoot: IProjectRootStore;
|
projectRoot: IProjectRootStore;
|
||||||
|
labelRoot: ILabelRootStore;
|
||||||
cycle: ICycleStore;
|
cycle: ICycleStore;
|
||||||
module: IModuleStore;
|
module: IModuleStore;
|
||||||
projectView: IProjectViewsStore;
|
projectView: IProjectViewsStore;
|
||||||
page: IPageStore;
|
page: IPageStore;
|
||||||
label: ILabelStore;
|
|
||||||
issue: IIssueRootStore;
|
issue: IIssueRootStore;
|
||||||
state: IStateStore;
|
state: IStateStore;
|
||||||
|
|
||||||
@ -32,8 +32,8 @@ export class RootStore {
|
|||||||
this.user = new UserStore(this);
|
this.user = new UserStore(this);
|
||||||
this.workspaceRoot = new WorkspaceRootStore(this);
|
this.workspaceRoot = new WorkspaceRootStore(this);
|
||||||
this.projectRoot = new ProjectRootStore(this);
|
this.projectRoot = new ProjectRootStore(this);
|
||||||
|
this.labelRoot = new LabelRootStore(this);
|
||||||
// independent stores
|
// independent stores
|
||||||
this.label = new LabelStore(this);
|
|
||||||
this.state = new StateStore(this);
|
this.state = new StateStore(this);
|
||||||
this.issue = new IssueRootStore(this);
|
this.issue = new IssueRootStore(this);
|
||||||
this.cycle = new CycleStore(this);
|
this.cycle = new CycleStore(this);
|
||||||
|
@ -42,8 +42,8 @@ export class WorkspaceRootStore implements IWorkspaceRootStore {
|
|||||||
// root store
|
// root store
|
||||||
rootStore;
|
rootStore;
|
||||||
// sub-stores
|
// sub-stores
|
||||||
webhook: WebhookStore;
|
webhook: IWebhookStore;
|
||||||
apiToken: ApiTokenStore;
|
apiToken: IApiTokenStore;
|
||||||
|
|
||||||
constructor(_rootStore: RootStore) {
|
constructor(_rootStore: RootStore) {
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
|
Loading…
Reference in New Issue
Block a user