mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
refactor: only using runInAction for assignment
refactor: - using single types instead of lite version, - isLoading logic for label store
This commit is contained in:
parent
37df8684d7
commit
963eeb0a8c
@ -10,7 +10,7 @@ import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
||||
// helpers
|
||||
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
||||
// types
|
||||
import { IIssueFilterOptions, IState, IUserLite, TStateGroups, LabelLite } from "types";
|
||||
import { IIssueFilterOptions, IState, IUserLite, TStateGroups, IIssueLabels } from "types";
|
||||
// constants
|
||||
import { STATE_GROUP_COLORS } from "constants/state";
|
||||
|
||||
@ -18,7 +18,7 @@ type Props = {
|
||||
filters: Partial<IIssueFilterOptions>;
|
||||
setFilters: (updatedFilter: Partial<IIssueFilterOptions>) => void;
|
||||
clearAllFilters: (...args: any) => void;
|
||||
labels: LabelLite[] | undefined;
|
||||
labels: IIssueLabels[] | undefined;
|
||||
members: IUserLite[] | undefined;
|
||||
states: IState[] | undefined;
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ import {
|
||||
TagIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import type { LabelLite } from "types";
|
||||
import type { IIssueLabels } from "types";
|
||||
|
||||
type Props = {
|
||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
@ -42,7 +42,7 @@ export const IssueLabelSelect: React.FC<Props> = observer(
|
||||
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId);
|
||||
}, [workspaceSlug, projectId, loadLabels]);
|
||||
|
||||
const filteredOptions: LabelLite[] = labels?.filter((l) =>
|
||||
const filteredOptions: IIssueLabels[] = labels?.filter((l) =>
|
||||
l.name.toLowerCase().includes(query.toLowerCase())
|
||||
);
|
||||
|
||||
|
@ -19,7 +19,7 @@ import { Input, PrimaryButton, SecondaryButton } from "components/ui";
|
||||
// icons
|
||||
import { ChevronDownIcon } from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import { IIssueLabels, LabelLite } from "types";
|
||||
import { IIssueLabels } from "types";
|
||||
// fetch-keys
|
||||
import { getRandomLabelColor, LABEL_COLOR_OPTIONS } from "constants/label";
|
||||
|
||||
@ -27,7 +27,7 @@ type Props = {
|
||||
labelForm: boolean;
|
||||
setLabelForm: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
isUpdating: boolean;
|
||||
labelToUpdate: LabelLite | null;
|
||||
labelToUpdate: IIssueLabels | null;
|
||||
onClose?: () => void;
|
||||
};
|
||||
|
||||
|
@ -15,12 +15,12 @@ import useToast from "hooks/use-toast";
|
||||
// ui
|
||||
import { DangerButton, SecondaryButton } from "components/ui";
|
||||
// types
|
||||
import type { ICurrentUserResponse, LabelLite } from "types";
|
||||
import type { ICurrentUserResponse, IIssueLabels } from "types";
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
data: LabelLite | null;
|
||||
data: IIssueLabels | null;
|
||||
user: ICurrentUserResponse | undefined;
|
||||
};
|
||||
|
||||
|
@ -11,12 +11,12 @@ import { Combobox, Dialog, Transition } from "@headlessui/react";
|
||||
// icons
|
||||
import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import { ICurrentUserResponse, LabelLite } from "types";
|
||||
import { ICurrentUserResponse, IIssueLabels } from "types";
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
handleClose: () => void;
|
||||
parent: LabelLite | undefined;
|
||||
parent: IIssueLabels | undefined;
|
||||
user: ICurrentUserResponse | undefined;
|
||||
};
|
||||
|
||||
@ -37,7 +37,7 @@ export const LabelsListModal: React.FC<Props> = observer(
|
||||
setQuery("");
|
||||
};
|
||||
|
||||
const addChildLabel = async (label: LabelLite) => {
|
||||
const addChildLabel = async (label: IIssueLabels) => {
|
||||
if (!workspaceSlug || !projectId || !user) return;
|
||||
|
||||
updateLabel(
|
||||
|
@ -20,14 +20,14 @@ import {
|
||||
TrashIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import { ICurrentUserResponse, LabelLite } from "types";
|
||||
import { ICurrentUserResponse, IIssueLabels } from "types";
|
||||
|
||||
type Props = {
|
||||
label: LabelLite;
|
||||
labelChildren: LabelLite[];
|
||||
addLabelToGroup: (parentLabel: LabelLite) => void;
|
||||
editLabel: (label: LabelLite) => void;
|
||||
handleLabelDelete: (label: LabelLite) => void;
|
||||
label: IIssueLabels;
|
||||
labelChildren: IIssueLabels[];
|
||||
addLabelToGroup: (parentLabel: IIssueLabels) => void;
|
||||
editLabel: (label: IIssueLabels) => void;
|
||||
handleLabelDelete: (label: IIssueLabels) => void;
|
||||
user: ICurrentUserResponse | undefined;
|
||||
};
|
||||
|
||||
@ -39,7 +39,7 @@ export const SingleLabelGroup: React.FC<Props> = observer(
|
||||
const { label: labelStore } = useMobxStore();
|
||||
const { updateLabel } = labelStore;
|
||||
|
||||
const removeFromGroup = (label: LabelLite) => {
|
||||
const removeFromGroup = (label: IIssueLabels) => {
|
||||
if (!workspaceSlug || !projectId || !user) return;
|
||||
|
||||
updateLabel(
|
||||
|
@ -3,14 +3,14 @@ import React from "react";
|
||||
// ui
|
||||
import { CustomMenu } from "components/ui";
|
||||
// types
|
||||
import { LabelLite } from "types";
|
||||
import { IIssueLabels } from "types";
|
||||
//icons
|
||||
import { RectangleGroupIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
type Props = {
|
||||
label: LabelLite;
|
||||
addLabelToGroup: (parentLabel: LabelLite) => void;
|
||||
editLabel: (label: LabelLite) => void;
|
||||
label: IIssueLabels;
|
||||
addLabelToGroup: (parentLabel: IIssueLabels) => void;
|
||||
editLabel: (label: IIssueLabels) => void;
|
||||
handleLabelDelete: () => void;
|
||||
};
|
||||
|
||||
|
@ -19,32 +19,32 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
|
||||
const items: BubbleMenuItem[] = [
|
||||
{
|
||||
name: "bold",
|
||||
isActive: () => props.editor.isActive("bold"),
|
||||
command: () => props.editor.chain().focus().toggleBold().run(),
|
||||
isActive: () => props?.editor?.isActive("bold")!,
|
||||
command: () => props?.editor?.chain().focus().toggleBold().run()!,
|
||||
icon: BoldIcon,
|
||||
},
|
||||
{
|
||||
name: "italic",
|
||||
isActive: () => props.editor.isActive("italic"),
|
||||
command: () => props.editor.chain().focus().toggleItalic().run(),
|
||||
isActive: () => props?.editor?.isActive("italic")!,
|
||||
command: () => props?.editor?.chain().focus().toggleItalic().run()!,
|
||||
icon: ItalicIcon,
|
||||
},
|
||||
{
|
||||
name: "underline",
|
||||
isActive: () => props.editor.isActive("underline"),
|
||||
command: () => props.editor.chain().focus().toggleUnderline().run(),
|
||||
isActive: () => props?.editor?.isActive("underline")!,
|
||||
command: () => props?.editor?.chain().focus().toggleUnderline().run()!,
|
||||
icon: UnderlineIcon,
|
||||
},
|
||||
{
|
||||
name: "strike",
|
||||
isActive: () => props.editor.isActive("strike"),
|
||||
command: () => props.editor.chain().focus().toggleStrike().run(),
|
||||
isActive: () => props?.editor?.isActive("strike")!,
|
||||
command: () => props?.editor?.chain().focus().toggleStrike().run()!,
|
||||
icon: StrikethroughIcon,
|
||||
},
|
||||
{
|
||||
name: "code",
|
||||
isActive: () => props.editor.isActive("code"),
|
||||
command: () => props.editor.chain().focus().toggleCode().run(),
|
||||
isActive: () => props?.editor?.isActive("code")!,
|
||||
command: () => props?.editor?.chain().focus().toggleCode().run()!,
|
||||
icon: CodeIcon,
|
||||
},
|
||||
];
|
||||
@ -78,7 +78,7 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
|
||||
className="flex w-fit divide-x divide-custom-border-300 rounded border border-custom-border-300 bg-custom-background-100 shadow-xl"
|
||||
>
|
||||
<NodeSelector
|
||||
editor={props.editor}
|
||||
editor={props?.editor!}
|
||||
isOpen={isNodeSelectorOpen}
|
||||
setIsOpen={() => {
|
||||
setIsNodeSelectorOpen(!isNodeSelectorOpen);
|
||||
@ -86,7 +86,7 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
|
||||
}}
|
||||
/>
|
||||
<LinkSelector
|
||||
editor={props.editor}
|
||||
editor={props?.editor!}
|
||||
isOpen={isLinkSelectorOpen}
|
||||
setIsOpen={() => {
|
||||
setIsLinkSelectorOpen(!isLinkSelectorOpen);
|
||||
|
@ -31,7 +31,7 @@ import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyLabel from "public/empty-state/label.svg";
|
||||
// types
|
||||
import { LabelLite } from "types";
|
||||
import { IIssueLabels } from "types";
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { PROJECT_DETAILS } from "constants/fetch-keys";
|
||||
@ -44,14 +44,14 @@ const LabelsSettings: NextPage = () => {
|
||||
|
||||
// edit label
|
||||
const [isUpdating, setIsUpdating] = useState(false);
|
||||
const [labelToUpdate, setLabelToUpdate] = useState<LabelLite | null>(null);
|
||||
const [labelToUpdate, setLabelToUpdate] = useState<IIssueLabels | null>(null);
|
||||
|
||||
// labels list modal
|
||||
const [labelsListModal, setLabelsListModal] = useState(false);
|
||||
const [parentLabel, setParentLabel] = useState<LabelLite | undefined>(undefined);
|
||||
const [parentLabel, setParentLabel] = useState<IIssueLabels | undefined>(undefined);
|
||||
|
||||
// delete label
|
||||
const [selectDeleteLabel, setSelectDeleteLabel] = useState<LabelLite | null>(null);
|
||||
const [selectDeleteLabel, setSelectDeleteLabel] = useState<IIssueLabels | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
@ -79,12 +79,12 @@ const LabelsSettings: NextPage = () => {
|
||||
setLabelForm(true);
|
||||
};
|
||||
|
||||
const addLabelToGroup = (parentLabel: LabelLite) => {
|
||||
const addLabelToGroup = (parentLabel: IIssueLabels) => {
|
||||
setLabelsListModal(true);
|
||||
setParentLabel(parentLabel);
|
||||
};
|
||||
|
||||
const editLabel = (label: LabelLite) => {
|
||||
const editLabel = (label: IIssueLabels) => {
|
||||
setLabelForm(true);
|
||||
setIsUpdating(true);
|
||||
setLabelToUpdate(label);
|
||||
|
@ -5,10 +5,10 @@ import { action, observable, runInAction, makeAutoObservable } from "mobx";
|
||||
import issueService from "services/issues.service";
|
||||
|
||||
// types
|
||||
import type { IIssueLabels, LabelLite, ICurrentUserResponse, LabelForm } from "types";
|
||||
import type { IIssueLabels, ICurrentUserResponse, LabelForm } from "types";
|
||||
|
||||
class LabelStore {
|
||||
labels: LabelLite[] = [];
|
||||
labels: IIssueLabels[] = [];
|
||||
isLabelsLoading: boolean = false;
|
||||
rootStore: any | null = null;
|
||||
|
||||
@ -30,24 +30,29 @@ class LabelStore {
|
||||
*/
|
||||
|
||||
loadLabels = async (workspaceSlug: string, projectId: string) => {
|
||||
this.isLabelsLoading = true;
|
||||
this.isLabelsLoading = this.labels.length === 0;
|
||||
try {
|
||||
const labelsResponse: IIssueLabels[] = await issueService.getIssueLabels(
|
||||
workspaceSlug,
|
||||
projectId
|
||||
);
|
||||
|
||||
const _labels = [...(labelsResponse || [])].map((label) => ({
|
||||
id: label.id,
|
||||
name: label.name,
|
||||
description: label.description,
|
||||
color: label.color,
|
||||
parent: label.parent,
|
||||
}));
|
||||
|
||||
runInAction(() => {
|
||||
this.labels = labelsResponse.map((label) => ({
|
||||
id: label.id,
|
||||
name: label.name,
|
||||
description: label.description,
|
||||
color: label.color,
|
||||
parent: label.parent,
|
||||
}));
|
||||
this.labels = _labels;
|
||||
this.isLabelsLoading = false;
|
||||
});
|
||||
} catch (error) {
|
||||
this.isLabelsLoading = false;
|
||||
runInAction(() => {
|
||||
this.isLabelsLoading = false;
|
||||
});
|
||||
console.error("Fetching labels error", error);
|
||||
}
|
||||
};
|
||||
@ -59,11 +64,11 @@ class LabelStore {
|
||||
/**
|
||||
* For provided query, this function returns all labels that contain query in their name from the labels store.
|
||||
* @param query - query string
|
||||
* @returns {LabelLite[]} array of labels that contain query in their name
|
||||
* @returns {IIssueLabels[]} array of labels that contain query in their name
|
||||
* @example
|
||||
* getFilteredLabels("labe") // [{ id: "1", name: "label1", description: "", color: "", parent: null }]
|
||||
*/
|
||||
getFilteredLabels = (query: string): LabelLite[] =>
|
||||
getFilteredLabels = (query: string): IIssueLabels[] =>
|
||||
this.labels.filter((label) => label.name.includes(query));
|
||||
|
||||
createLabel = async (
|
||||
@ -80,18 +85,19 @@ class LabelStore {
|
||||
user
|
||||
);
|
||||
|
||||
const _label = [
|
||||
...this.labels,
|
||||
{
|
||||
id: labelResponse.id,
|
||||
name: labelResponse.name,
|
||||
description: labelResponse.description,
|
||||
color: labelResponse.color,
|
||||
parent: labelResponse.parent,
|
||||
},
|
||||
].sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
runInAction(() => {
|
||||
this.labels = [
|
||||
...this.labels,
|
||||
{
|
||||
id: labelResponse.id,
|
||||
name: labelResponse.name,
|
||||
description: labelResponse.description,
|
||||
color: labelResponse.color,
|
||||
parent: labelResponse.parent,
|
||||
},
|
||||
];
|
||||
this.labels.sort((a, b) => a.name.localeCompare(b.name));
|
||||
this.labels = _label;
|
||||
});
|
||||
return labelResponse;
|
||||
} catch (error) {
|
||||
@ -116,18 +122,20 @@ class LabelStore {
|
||||
user
|
||||
);
|
||||
|
||||
const _labels = [...this.labels].map((label) => {
|
||||
if (label.id === labelId) {
|
||||
return {
|
||||
id: labelResponse.id,
|
||||
name: labelResponse.name,
|
||||
description: labelResponse.description,
|
||||
color: labelResponse.color,
|
||||
parent: labelResponse.parent,
|
||||
};
|
||||
}
|
||||
return label;
|
||||
});
|
||||
const _labels = [...this.labels]
|
||||
.map((label) => {
|
||||
if (label.id === labelId) {
|
||||
return {
|
||||
id: labelResponse.id,
|
||||
name: labelResponse.name,
|
||||
description: labelResponse.description,
|
||||
color: labelResponse.color,
|
||||
parent: labelResponse.parent,
|
||||
};
|
||||
}
|
||||
return label;
|
||||
})
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
runInAction(() => {
|
||||
this.labels = _labels;
|
||||
@ -146,8 +154,11 @@ class LabelStore {
|
||||
) => {
|
||||
try {
|
||||
issueService.deleteIssueLabel(workspaceSlug, projectId, labelId, user);
|
||||
|
||||
const _labels = [...this.labels].filter((label) => label.id !== labelId);
|
||||
|
||||
runInAction(() => {
|
||||
this.labels = this.labels.filter((label) => label.id !== labelId);
|
||||
this.labels = _labels;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Deleting label error", error);
|
||||
|
2
apps/app/types/index.d.ts
vendored
2
apps/app/types/index.d.ts
vendored
@ -18,7 +18,7 @@ export * from "./calendar";
|
||||
export * from "./notifications";
|
||||
export * from "./waitlist";
|
||||
export * from "./reaction";
|
||||
|
||||
export * from "./labels";
|
||||
|
||||
export type NestedKeyOf<ObjectType extends object> = {
|
||||
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
|
||||
|
30
apps/app/types/issues.d.ts
vendored
30
apps/app/types/issues.d.ts
vendored
@ -148,36 +148,6 @@ export type IssuePriorities = {
|
||||
user: string;
|
||||
};
|
||||
|
||||
export interface IIssueLabels {
|
||||
id: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
name: string;
|
||||
description: string;
|
||||
color: string;
|
||||
created_by: string;
|
||||
updated_by: string;
|
||||
project: string;
|
||||
project_detail: IProjectLite;
|
||||
workspace: string;
|
||||
workspace_detail: IWorkspaceLite;
|
||||
parent: string | null;
|
||||
}
|
||||
|
||||
export interface LabelForm {
|
||||
name: string;
|
||||
description: string;
|
||||
color: string;
|
||||
parent: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Issue label's lite version
|
||||
*/
|
||||
export interface LabelLite extends LabelForm {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface IIssueActivity {
|
||||
actor: string;
|
||||
actor_detail: IUserLite;
|
||||
|
22
apps/app/types/labels.d.ts
vendored
Normal file
22
apps/app/types/labels.d.ts
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
export interface IIssueLabels {
|
||||
id: string;
|
||||
created_at?: Date;
|
||||
updated_at?: Date;
|
||||
name: string;
|
||||
description: string;
|
||||
color: string;
|
||||
created_by?: string;
|
||||
updated_by?: string;
|
||||
project?: string;
|
||||
project_detail?: IProjectLite;
|
||||
workspace?: string;
|
||||
workspace_detail?: IWorkspaceLite;
|
||||
parent: string | null;
|
||||
}
|
||||
|
||||
export interface LabelForm {
|
||||
name: string;
|
||||
description: string;
|
||||
color: string;
|
||||
parent: string | null;
|
||||
}
|
Loading…
Reference in New Issue
Block a user