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