mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
refactor: using label store to get labels
This commit is contained in:
parent
f8ab0aa72b
commit
e9c3a0642e
@ -10,7 +10,7 @@ import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
|||||||
// helpers
|
// helpers
|
||||||
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssueFilterOptions, IIssueLabels, IState, IUserLite, TStateGroups } from "types";
|
import { IIssueFilterOptions, IState, IUserLite, TStateGroups, LabelLite } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { STATE_GROUP_COLORS } from "constants/state";
|
import { STATE_GROUP_COLORS } from "constants/state";
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ type Props = {
|
|||||||
filters: Partial<IIssueFilterOptions>;
|
filters: Partial<IIssueFilterOptions>;
|
||||||
setFilters: (updatedFilter: Partial<IIssueFilterOptions>) => void;
|
setFilters: (updatedFilter: Partial<IIssueFilterOptions>) => void;
|
||||||
clearAllFilters: (...args: any) => void;
|
clearAllFilters: (...args: any) => void;
|
||||||
labels: IIssueLabels[] | undefined;
|
labels: LabelLite[] | undefined;
|
||||||
members: IUserLite[] | undefined;
|
members: IUserLite[] | undefined;
|
||||||
states: IState[] | undefined;
|
states: IState[] | undefined;
|
||||||
};
|
};
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
// services
|
// services
|
||||||
import issuesService from "services/issues.service";
|
|
||||||
import projectService from "services/project.service";
|
import projectService from "services/project.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useProjects from "hooks/use-projects";
|
import useProjects from "hooks/use-projects";
|
||||||
// component
|
// component
|
||||||
import { Avatar, Icon } from "components/ui";
|
import { Avatar, Icon } from "components/ui";
|
||||||
// icons
|
// icons
|
||||||
import { ArrowsPointingInIcon, ArrowsPointingOutIcon, PlusIcon } from "@heroicons/react/24/outline";
|
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||||
import { getPriorityIcon, getStateGroupIcon } from "components/icons";
|
import { getPriorityIcon, getStateGroupIcon } from "components/icons";
|
||||||
// helpers
|
// helpers
|
||||||
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
||||||
@ -20,7 +23,7 @@ import { renderEmoji } from "helpers/emoji.helper";
|
|||||||
// types
|
// types
|
||||||
import { IIssueViewProps, IState } from "types";
|
import { IIssueViewProps, IState } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys";
|
import { PROJECT_MEMBERS } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentState?: IState | null;
|
currentState?: IState | null;
|
||||||
@ -32,7 +35,8 @@ type Props = {
|
|||||||
viewProps: IIssueViewProps;
|
viewProps: IIssueViewProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BoardHeader: React.FC<Props> = ({
|
export const BoardHeader: React.FC<Props> = observer(
|
||||||
|
({
|
||||||
currentState,
|
currentState,
|
||||||
groupTitle,
|
groupTitle,
|
||||||
addIssueToGroup,
|
addIssueToGroup,
|
||||||
@ -40,20 +44,14 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
setIsCollapsed,
|
setIsCollapsed,
|
||||||
disableUserActions,
|
disableUserActions,
|
||||||
viewProps,
|
viewProps,
|
||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { groupedIssues, groupByProperty: selectedGroup } = viewProps;
|
const { groupedIssues, groupByProperty: selectedGroup } = viewProps;
|
||||||
|
|
||||||
const { data: issueLabels } = useSWR(
|
const { label: labelStore } = useMobxStore();
|
||||||
workspaceSlug && projectId && selectedGroup === "labels"
|
const { labels, loadLabels } = labelStore;
|
||||||
? PROJECT_ISSUE_LABELS(projectId.toString())
|
|
||||||
: null,
|
|
||||||
workspaceSlug && projectId && selectedGroup === "labels"
|
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug.toString(), projectId.toString())
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data: members } = useSWR(
|
const { data: members } = useSWR(
|
||||||
workspaceSlug && projectId && selectedGroup === "created_by"
|
workspaceSlug && projectId && selectedGroup === "created_by"
|
||||||
@ -66,6 +64,10 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { projects } = useProjects();
|
const { projects } = useProjects();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [workspaceSlug, projectId, loadLabels]);
|
||||||
|
|
||||||
const getGroupTitle = () => {
|
const getGroupTitle = () => {
|
||||||
let title = addSpaceIfCamelCase(groupTitle);
|
let title = addSpaceIfCamelCase(groupTitle);
|
||||||
|
|
||||||
@ -74,7 +76,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
||||||
break;
|
break;
|
||||||
case "labels":
|
case "labels":
|
||||||
title = issueLabels?.find((label) => label.id === groupTitle)?.name ?? "None";
|
title = labels?.find((label) => label.id === groupTitle)?.name ?? "None";
|
||||||
break;
|
break;
|
||||||
case "project":
|
case "project":
|
||||||
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
|
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
|
||||||
@ -113,8 +115,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
: null);
|
: null);
|
||||||
break;
|
break;
|
||||||
case "labels":
|
case "labels":
|
||||||
const labelColor =
|
const labelColor = labels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
|
||||||
issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
|
|
||||||
icon = (
|
icon = (
|
||||||
<span
|
<span
|
||||||
className="h-3.5 w-3.5 flex-shrink-0 rounded-full"
|
className="h-3.5 w-3.5 flex-shrink-0 rounded-full"
|
||||||
@ -175,7 +176,10 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
className="text-base font-medium text-custom-text-900"
|
className="text-base font-medium text-custom-text-900"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Icon iconName="open_in_full" className="text-base font-medium text-custom-text-900" />
|
<Icon
|
||||||
|
iconName="open_in_full"
|
||||||
|
className="text-base font-medium text-custom-text-900"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
{!disableUserActions && selectedGroup !== "created_by" && (
|
{!disableUserActions && selectedGroup !== "created_by" && (
|
||||||
@ -190,4 +194,5 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
);
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState, useEffect } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
|
|
||||||
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
// react-beautiful-dnd
|
// react-beautiful-dnd
|
||||||
import { DropResult } from "react-beautiful-dnd";
|
import { DropResult } from "react-beautiful-dnd";
|
||||||
// services
|
// services
|
||||||
@ -37,7 +41,6 @@ import {
|
|||||||
MODULE_DETAILS,
|
MODULE_DETAILS,
|
||||||
MODULE_ISSUES_WITH_PARAMS,
|
MODULE_ISSUES_WITH_PARAMS,
|
||||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||||
PROJECT_ISSUE_LABELS,
|
|
||||||
STATES_LIST,
|
STATES_LIST,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
|
|
||||||
@ -46,10 +49,8 @@ type Props = {
|
|||||||
disableUserActions?: boolean;
|
disableUserActions?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IssuesView: React.FC<Props> = ({
|
export const IssuesView: React.FC<Props> = observer((props) => {
|
||||||
openIssuesListModal,
|
const { openIssuesListModal, disableUserActions = false } = props;
|
||||||
disableUserActions = false,
|
|
||||||
}) => {
|
|
||||||
// create issue modal
|
// create issue modal
|
||||||
const [createIssueModal, setCreateIssueModal] = useState(false);
|
const [createIssueModal, setCreateIssueModal] = useState(false);
|
||||||
const [createViewModal, setCreateViewModal] = useState<any>(null);
|
const [createViewModal, setCreateViewModal] = useState<any>(null);
|
||||||
@ -75,6 +76,9 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { user } = useUserAuth();
|
const { user } = useUserAuth();
|
||||||
|
|
||||||
|
const { label: labelStore } = useMobxStore();
|
||||||
|
const { labels, loadLabels } = labelStore;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -99,15 +103,12 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
const states = getStatesList(stateGroups);
|
const states = getStatesList(stateGroups);
|
||||||
|
|
||||||
const { data: labels } = useSWR(
|
|
||||||
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug.toString(), projectId.toString())
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString());
|
const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (workspaceSlug && projectId) loadLabels(workspaceSlug as string, projectId as string);
|
||||||
|
}, [loadLabels, projectId, workspaceSlug]);
|
||||||
|
|
||||||
const handleDeleteIssue = useCallback(
|
const handleDeleteIssue = useCallback(
|
||||||
(issue: IIssue) => {
|
(issue: IIssue) => {
|
||||||
setDeleteIssueModal(true);
|
setDeleteIssueModal(true);
|
||||||
@ -564,4 +565,4 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
// headless ui
|
// headless ui
|
||||||
import { Disclosure, Transition } from "@headlessui/react";
|
import { Disclosure, Transition } from "@headlessui/react";
|
||||||
// services
|
// services
|
||||||
import issuesService from "services/issues.service";
|
|
||||||
import projectService from "services/project.service";
|
import projectService from "services/project.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useProjects from "hooks/use-projects";
|
import useProjects from "hooks/use-projects";
|
||||||
@ -20,16 +25,9 @@ import { getPriorityIcon, getStateGroupIcon } from "components/icons";
|
|||||||
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
||||||
import { renderEmoji } from "helpers/emoji.helper";
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
// types
|
// types
|
||||||
import {
|
import { ICurrentUserResponse, IIssue, IIssueViewProps, IState, UserAuth } from "types";
|
||||||
ICurrentUserResponse,
|
|
||||||
IIssue,
|
|
||||||
IIssueLabels,
|
|
||||||
IIssueViewProps,
|
|
||||||
IState,
|
|
||||||
UserAuth,
|
|
||||||
} from "types";
|
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys";
|
import { PROJECT_MEMBERS } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentState?: IState | null;
|
currentState?: IState | null;
|
||||||
@ -44,7 +42,8 @@ type Props = {
|
|||||||
viewProps: IIssueViewProps;
|
viewProps: IIssueViewProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SingleList: React.FC<Props> = ({
|
export const SingleList: React.FC<Props> = observer((props) => {
|
||||||
|
const {
|
||||||
currentState,
|
currentState,
|
||||||
groupTitle,
|
groupTitle,
|
||||||
addIssueToGroup,
|
addIssueToGroup,
|
||||||
@ -55,7 +54,8 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
user,
|
user,
|
||||||
userAuth,
|
userAuth,
|
||||||
viewProps,
|
viewProps,
|
||||||
}) => {
|
} = props;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
@ -65,12 +65,8 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { groupByProperty: selectedGroup, groupedIssues } = viewProps;
|
const { groupByProperty: selectedGroup, groupedIssues } = viewProps;
|
||||||
|
|
||||||
const { data: issueLabels } = useSWR<IIssueLabels[]>(
|
const { label: labelStore } = useMobxStore();
|
||||||
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
|
const { labels, loadLabels } = labelStore;
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data: members } = useSWR(
|
const { data: members } = useSWR(
|
||||||
workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null,
|
workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null,
|
||||||
@ -81,6 +77,10 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { projects } = useProjects();
|
const { projects } = useProjects();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [workspaceSlug, projectId, loadLabels]);
|
||||||
|
|
||||||
const getGroupTitle = () => {
|
const getGroupTitle = () => {
|
||||||
let title = addSpaceIfCamelCase(groupTitle);
|
let title = addSpaceIfCamelCase(groupTitle);
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
||||||
break;
|
break;
|
||||||
case "labels":
|
case "labels":
|
||||||
title = issueLabels?.find((label) => label.id === groupTitle)?.name ?? "None";
|
title = labels?.find((label) => label.id === groupTitle)?.name ?? "None";
|
||||||
break;
|
break;
|
||||||
case "project":
|
case "project":
|
||||||
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
|
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
|
||||||
@ -128,8 +128,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
: null);
|
: null);
|
||||||
break;
|
break;
|
||||||
case "labels":
|
case "labels":
|
||||||
const labelColor =
|
const labelColor = labels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
|
||||||
issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
|
|
||||||
icon = (
|
icon = (
|
||||||
<span
|
<span
|
||||||
className="h-3 w-3 flex-shrink-0 rounded-full"
|
className="h-3 w-3 flex-shrink-0 rounded-full"
|
||||||
@ -252,4 +251,4 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -2,7 +2,9 @@ import React, { useEffect, useState } from "react";
|
|||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR from "swr";
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { Controller, UseFormWatch, useForm } from "react-hook-form";
|
import { Controller, UseFormWatch, useForm } from "react-hook-form";
|
||||||
@ -10,8 +12,6 @@ import { Controller, UseFormWatch, useForm } from "react-hook-form";
|
|||||||
import { TwitterPicker } from "react-color";
|
import { TwitterPicker } from "react-color";
|
||||||
// headless ui
|
// headless ui
|
||||||
import { Listbox, Popover, Transition } from "@headlessui/react";
|
import { Listbox, Popover, Transition } from "@headlessui/react";
|
||||||
// services
|
|
||||||
import issuesService from "services/issues.service";
|
|
||||||
// hooks
|
// hooks
|
||||||
import useUser from "hooks/use-user";
|
import useUser from "hooks/use-user";
|
||||||
// ui
|
// ui
|
||||||
@ -25,9 +25,7 @@ import {
|
|||||||
XMarkIcon,
|
XMarkIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IIssueLabels } from "types";
|
import { IIssue, LabelForm } from "types";
|
||||||
// fetch-keys
|
|
||||||
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issueDetails: IIssue | undefined;
|
issueDetails: IIssue | undefined;
|
||||||
@ -38,19 +36,13 @@ type Props = {
|
|||||||
uneditable: boolean;
|
uneditable: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValues: Partial<IIssueLabels> = {
|
const defaultValues: Partial<LabelForm> = {
|
||||||
name: "",
|
name: "",
|
||||||
color: "#ff0000",
|
color: "#ff0000",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SidebarLabelSelect: React.FC<Props> = ({
|
export const SidebarLabelSelect: React.FC<Props> = observer((props) => {
|
||||||
issueDetails,
|
const { issueDetails, issueControl, watchIssue, submitChanges, isNotAllowed, uneditable } = props;
|
||||||
issueControl,
|
|
||||||
watchIssue,
|
|
||||||
submitChanges,
|
|
||||||
isNotAllowed,
|
|
||||||
uneditable,
|
|
||||||
}) => {
|
|
||||||
const [createLabelForm, setCreateLabelForm] = useState(false);
|
const [createLabelForm, setCreateLabelForm] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -64,33 +56,38 @@ export const SidebarLabelSelect: React.FC<Props> = ({
|
|||||||
watch,
|
watch,
|
||||||
control: labelControl,
|
control: labelControl,
|
||||||
setFocus,
|
setFocus,
|
||||||
} = useForm<Partial<IIssueLabels>>({
|
} = useForm<LabelForm>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
|
||||||
const { data: issueLabels, mutate: issueLabelMutate } = useSWR<IIssueLabels[]>(
|
const { label: labelStore } = useMobxStore();
|
||||||
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
|
const {
|
||||||
workspaceSlug && projectId
|
labels,
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
|
loadLabels,
|
||||||
: null
|
createLabel,
|
||||||
);
|
getLabelById,
|
||||||
|
getLabelChildren,
|
||||||
|
isLabelsLoading: isLoading,
|
||||||
|
} = labelStore;
|
||||||
|
|
||||||
const handleNewLabel = async (formData: Partial<IIssueLabels>) => {
|
useEffect(() => {
|
||||||
if (!workspaceSlug || !projectId || isSubmitting) return;
|
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [workspaceSlug, projectId, loadLabels]);
|
||||||
|
|
||||||
await issuesService
|
const handleNewLabel = async (formData: LabelForm) => {
|
||||||
.createIssueLabel(workspaceSlug as string, projectId as string, formData, user)
|
if (!workspaceSlug || !projectId || isSubmitting || !user) return;
|
||||||
.then((res) => {
|
|
||||||
|
await createLabel(workspaceSlug.toString(), projectId.toString(), formData, user).then(
|
||||||
|
(res: any) => {
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
|
|
||||||
issueLabelMutate((prevData: any) => [...(prevData ?? []), res], false);
|
|
||||||
|
|
||||||
submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] });
|
submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] });
|
||||||
|
|
||||||
setCreateLabelForm(false);
|
setCreateLabelForm(false);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -110,7 +107,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
|
|||||||
<div className="basis-1/2">
|
<div className="basis-1/2">
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{watchIssue("labels_list")?.map((labelId) => {
|
{watchIssue("labels_list")?.map((labelId) => {
|
||||||
const label = issueLabels?.find((l) => l.id === labelId);
|
const label = getLabelById(labelId);
|
||||||
|
|
||||||
if (label)
|
if (label)
|
||||||
return (
|
return (
|
||||||
@ -168,12 +165,10 @@ export const SidebarLabelSelect: React.FC<Props> = ({
|
|||||||
>
|
>
|
||||||
<Listbox.Options className="absolute right-0 z-10 mt-1 max-h-28 w-40 overflow-auto rounded-md bg-custom-background-80 py-1 text-xs shadow-lg border border-custom-border-100 focus:outline-none">
|
<Listbox.Options className="absolute right-0 z-10 mt-1 max-h-28 w-40 overflow-auto rounded-md bg-custom-background-80 py-1 text-xs shadow-lg border border-custom-border-100 focus:outline-none">
|
||||||
<div className="py-1">
|
<div className="py-1">
|
||||||
{issueLabels ? (
|
{!isLoading ? (
|
||||||
issueLabels.length > 0 ? (
|
labels.length > 0 ? (
|
||||||
issueLabels.map((label: IIssueLabels) => {
|
labels.map((label) => {
|
||||||
const children = issueLabels?.filter(
|
const children = getLabelChildren(label.id);
|
||||||
(l) => l.parent === label.id
|
|
||||||
);
|
|
||||||
|
|
||||||
if (children.length === 0) {
|
if (children.length === 0) {
|
||||||
if (!label.parent)
|
if (!label.parent)
|
||||||
@ -346,4 +341,4 @@ export const SidebarLabelSelect: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR from "swr";
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
// services
|
|
||||||
import issuesService from "services/issues.service";
|
|
||||||
// component
|
// component
|
||||||
import { CreateLabelModal } from "components/labels";
|
import { CreateLabelModal } from "components/labels";
|
||||||
// ui
|
// ui
|
||||||
@ -13,9 +13,7 @@ import { CustomSearchSelect, Tooltip } from "components/ui";
|
|||||||
// icons
|
// icons
|
||||||
import { PlusIcon, TagIcon } from "@heroicons/react/24/outline";
|
import { PlusIcon, TagIcon } from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
import { ICurrentUserResponse, IIssue, IIssueLabels } from "types";
|
import { ICurrentUserResponse, IIssue } from "types";
|
||||||
// fetch-keys
|
|
||||||
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
@ -28,7 +26,8 @@ type Props = {
|
|||||||
isNotAllowed: boolean;
|
isNotAllowed: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewLabelSelect: React.FC<Props> = ({
|
export const ViewLabelSelect: React.FC<Props> = observer((props) => {
|
||||||
|
const {
|
||||||
issue,
|
issue,
|
||||||
partialUpdateIssue,
|
partialUpdateIssue,
|
||||||
position = "left",
|
position = "left",
|
||||||
@ -37,20 +36,21 @@ export const ViewLabelSelect: React.FC<Props> = ({
|
|||||||
user,
|
user,
|
||||||
isNotAllowed,
|
isNotAllowed,
|
||||||
customButton = false,
|
customButton = false,
|
||||||
}) => {
|
} = props;
|
||||||
|
|
||||||
const [labelModal, setLabelModal] = useState(false);
|
const [labelModal, setLabelModal] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { data: issueLabels } = useSWR<IIssueLabels[]>(
|
const { label: labelStore } = useMobxStore();
|
||||||
projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null,
|
const { labels, loadLabels, getLabelById } = labelStore;
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const options = issueLabels?.map((label) => ({
|
useEffect(() => {
|
||||||
|
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [workspaceSlug, projectId, loadLabels]);
|
||||||
|
|
||||||
|
const options = labels?.map((label) => ({
|
||||||
value: label.id,
|
value: label.id,
|
||||||
query: label.name,
|
query: label.name,
|
||||||
content: (
|
content: (
|
||||||
@ -74,7 +74,7 @@ export const ViewLabelSelect: React.FC<Props> = ({
|
|||||||
issue.labels.length > 0
|
issue.labels.length > 0
|
||||||
? issue.labels
|
? issue.labels
|
||||||
.map((labelId) => {
|
.map((labelId) => {
|
||||||
const label = issueLabels?.find((l) => l.id === labelId);
|
const label = getLabelById(labelId);
|
||||||
|
|
||||||
return label?.name ?? "";
|
return label?.name ?? "";
|
||||||
})
|
})
|
||||||
@ -90,7 +90,7 @@ export const ViewLabelSelect: React.FC<Props> = ({
|
|||||||
{issue.labels.length > 0 ? (
|
{issue.labels.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
{issue.labels.slice(0, 4).map((labelId, index) => {
|
{issue.labels.slice(0, 4).map((labelId, index) => {
|
||||||
const label = issueLabels?.find((l) => l.id === labelId);
|
const label = getLabelById(labelId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex h-4 w-4 rounded-full ${index ? "-ml-3.5" : ""}`}>
|
<div className={`flex h-4 w-4 rounded-full ${index ? "-ml-3.5" : ""}`}>
|
||||||
@ -154,4 +154,4 @@ export const ViewLabelSelect: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -4,6 +4,10 @@ import { useRouter } from "next/router";
|
|||||||
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
// services
|
// services
|
||||||
@ -20,9 +24,8 @@ import { checkIfArraysHaveSameElements } from "helpers/array.helper";
|
|||||||
import { getStatesList } from "helpers/state.helper";
|
import { getStatesList } from "helpers/state.helper";
|
||||||
// types
|
// types
|
||||||
import { IQuery, IView } from "types";
|
import { IQuery, IView } from "types";
|
||||||
import issuesService from "services/issues.service";
|
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_ISSUE_LABELS, STATES_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
handleFormSubmit: (values: IView) => Promise<void>;
|
handleFormSubmit: (values: IView) => Promise<void>;
|
||||||
@ -37,13 +40,9 @@ const defaultValues: Partial<IView> = {
|
|||||||
description: "",
|
description: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewForm: React.FC<Props> = ({
|
export const ViewForm: React.FC<Props> = observer((props) => {
|
||||||
handleFormSubmit,
|
const { handleFormSubmit, handleClose, status, data, preLoadedData } = props;
|
||||||
handleClose,
|
|
||||||
status,
|
|
||||||
data,
|
|
||||||
preLoadedData,
|
|
||||||
}) => {
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
@ -69,16 +68,16 @@ export const ViewForm: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
const states = getStatesList(stateGroups);
|
const states = getStatesList(stateGroups);
|
||||||
|
|
||||||
const { data: labels } = useSWR(
|
const { label: labelStore } = useMobxStore();
|
||||||
workspaceSlug && projectId && (filters?.labels ?? []).length > 0
|
const { labels, loadLabels } = labelStore;
|
||||||
? PROJECT_ISSUE_LABELS(projectId.toString())
|
|
||||||
: null,
|
|
||||||
workspaceSlug && projectId && (filters?.labels ?? []).length > 0
|
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug.toString(), projectId.toString())
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString());
|
const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (workspaceSlug && projectId && (filters?.labels ?? []).length > 0)
|
||||||
|
loadLabels(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [workspaceSlug, projectId, loadLabels, filters]);
|
||||||
|
|
||||||
const handleCreateUpdateView = async (formData: IView) => {
|
const handleCreateUpdateView = async (formData: IView) => {
|
||||||
await handleFormSubmit(formData);
|
await handleFormSubmit(formData);
|
||||||
|
|
||||||
@ -211,4 +210,4 @@ export const ViewForm: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import { useState } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
// services
|
// services
|
||||||
import stateService from "services/state.service";
|
import stateService from "services/state.service";
|
||||||
import projectService from "services/project.service";
|
import projectService from "services/project.service";
|
||||||
import issuesService from "services/issues.service";
|
|
||||||
// components
|
// components
|
||||||
import { DueDateFilterModal } from "components/core";
|
import { DueDateFilterModal } from "components/core";
|
||||||
// ui
|
// ui
|
||||||
@ -20,7 +23,7 @@ import { checkIfArraysHaveSameElements } from "helpers/array.helper";
|
|||||||
// types
|
// types
|
||||||
import { IIssueFilterOptions, IQuery } from "types";
|
import { IIssueFilterOptions, IQuery } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATES_LIST } from "constants/fetch-keys";
|
import { PROJECT_MEMBERS, STATES_LIST } from "constants/fetch-keys";
|
||||||
// constants
|
// constants
|
||||||
import { PRIORITIES } from "constants/project";
|
import { PRIORITIES } from "constants/project";
|
||||||
import { DUE_DATES } from "constants/due-dates";
|
import { DUE_DATES } from "constants/due-dates";
|
||||||
@ -32,17 +35,17 @@ type Props = {
|
|||||||
height?: "sm" | "md" | "rg" | "lg";
|
height?: "sm" | "md" | "rg" | "lg";
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SelectFilters: React.FC<Props> = ({
|
export const SelectFilters: React.FC<Props> = observer((props) => {
|
||||||
filters,
|
const { filters, onSelect, direction = "right", height = "md" } = props;
|
||||||
onSelect,
|
|
||||||
direction = "right",
|
|
||||||
height = "md",
|
|
||||||
}) => {
|
|
||||||
const [isDueDateFilterModalOpen, setIsDueDateFilterModalOpen] = useState(false);
|
const [isDueDateFilterModalOpen, setIsDueDateFilterModalOpen] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
|
const { label: labelStore } = useMobxStore();
|
||||||
|
const { labels, loadLabels } = labelStore;
|
||||||
|
|
||||||
const { data: states } = useSWR(
|
const { data: states } = useSWR(
|
||||||
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
@ -58,12 +61,9 @@ export const SelectFilters: React.FC<Props> = ({
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: issueLabels } = useSWR(
|
useEffect(() => {
|
||||||
projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null,
|
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
|
||||||
workspaceSlug && projectId
|
}, [workspaceSlug, projectId, loadLabels]);
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId.toString())
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -160,9 +160,9 @@ export const SelectFilters: React.FC<Props> = ({
|
|||||||
{
|
{
|
||||||
id: "labels",
|
id: "labels",
|
||||||
label: "Labels",
|
label: "Labels",
|
||||||
value: issueLabels,
|
value: labels,
|
||||||
hasChildren: true,
|
hasChildren: true,
|
||||||
children: issueLabels?.map((label) => ({
|
children: labels?.map((label) => ({
|
||||||
id: label.id,
|
id: label.id,
|
||||||
label: (
|
label: (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@ -216,4 +216,4 @@ export const SelectFilters: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -4,6 +4,10 @@ import { useRouter } from "next/router";
|
|||||||
|
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
|
|
||||||
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
// headless ui
|
// headless ui
|
||||||
@ -16,7 +20,6 @@ import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
|||||||
// services
|
// services
|
||||||
import projectService from "services/project.service";
|
import projectService from "services/project.service";
|
||||||
import pagesService from "services/pages.service";
|
import pagesService from "services/pages.service";
|
||||||
import issuesService from "services/issues.service";
|
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
import useUser from "hooks/use-user";
|
import useUser from "hooks/use-user";
|
||||||
@ -56,13 +59,12 @@ import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
|||||||
import { orderArrayBy } from "helpers/array.helper";
|
import { orderArrayBy } from "helpers/array.helper";
|
||||||
// types
|
// types
|
||||||
import type { NextPage } from "next";
|
import type { NextPage } from "next";
|
||||||
import { IIssueLabels, IPage, IPageBlock, IProjectMember } from "types";
|
import { IPage, IPageBlock, IProjectMember } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import {
|
import {
|
||||||
PAGE_BLOCKS_LIST,
|
PAGE_BLOCKS_LIST,
|
||||||
PAGE_DETAILS,
|
PAGE_DETAILS,
|
||||||
PROJECT_DETAILS,
|
PROJECT_DETAILS,
|
||||||
PROJECT_ISSUE_LABELS,
|
|
||||||
USER_PROJECT_VIEW,
|
USER_PROJECT_VIEW,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
|
|
||||||
@ -80,6 +82,9 @@ const SinglePage: NextPage = () => {
|
|||||||
|
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
|
||||||
|
const { label: labelStore } = useMobxStore();
|
||||||
|
const { labels, loadLabels } = labelStore;
|
||||||
|
|
||||||
const { handleSubmit, reset, watch, setValue } = useForm<IPage>({
|
const { handleSubmit, reset, watch, setValue } = useForm<IPage>({
|
||||||
defaultValues: { name: "" },
|
defaultValues: { name: "" },
|
||||||
});
|
});
|
||||||
@ -115,13 +120,6 @@ const SinglePage: NextPage = () => {
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: labels } = useSWR<IIssueLabels[]>(
|
|
||||||
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data: memberDetails } = useSWR(
|
const { data: memberDetails } = useSWR(
|
||||||
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId.toString()) : null,
|
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId.toString()) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
@ -129,6 +127,10 @@ const SinglePage: NextPage = () => {
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [workspaceSlug, projectId, loadLabels]);
|
||||||
|
|
||||||
const updatePage = async (formData: IPage) => {
|
const updatePage = async (formData: IPage) => {
|
||||||
if (!workspaceSlug || !projectId || !pageId) return;
|
if (!workspaceSlug || !projectId || !pageId) return;
|
||||||
|
|
||||||
@ -691,4 +693,4 @@ const SinglePage: NextPage = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SinglePage;
|
export default observer(SinglePage);
|
||||||
|
Loading…
Reference in New Issue
Block a user