From be3988422b19cab625a49325359842aa625cac58 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Wed, 8 Nov 2023 19:41:08 +0530 Subject: [PATCH 1/3] fix: project states fixes --- .../automation/auto-close-automation.tsx | 9 +- .../issue/change-issue-state.tsx | 12 +- .../filters/applied-filters/state.tsx | 10 +- .../filters/header/filters/state.tsx | 11 +- web/components/issues/select/state.tsx | 8 +- .../issues/sidebar-select/state.tsx | 4 +- .../project-setting-state-list-item.tsx | 15 +- .../states/project-setting-state-list.tsx | 95 +++++-- web/helpers/array.helper.ts | 31 +- web/helpers/state.helper.ts | 26 +- web/services/project/project_state.service.ts | 15 +- web/store/project/project.store.ts | 66 +---- web/store/project/project_state.store.ts | 268 +++++++++--------- 13 files changed, 271 insertions(+), 299 deletions(-) diff --git a/web/components/automation/auto-close-automation.tsx b/web/components/automation/auto-close-automation.tsx index b0aad20cd4e..660e5247e54 100644 --- a/web/components/automation/auto-close-automation.tsx +++ b/web/components/automation/auto-close-automation.tsx @@ -13,8 +13,6 @@ import { PROJECT_AUTOMATION_MONTHS } from "constants/project"; import { STATES_LIST } from "constants/fetch-keys"; // types import { IProject } from "types"; -// helper -import { getStatesList } from "helpers/state.helper"; type Props = { projectDetails: IProject | undefined; @@ -30,13 +28,14 @@ export const AutoCloseAutomation: React.FC = ({ projectDetails, handleCha const router = useRouter(); const { workspaceSlug, projectId } = router.query; - const { data: stateGroups } = useSWR( + const { data: statesData } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, workspaceSlug && projectId ? () => projectStateService.getStates(workspaceSlug as string, projectId as string) : null ); - const states = getStatesList(stateGroups); + + const states = statesData || []; const options = states ?.filter((state) => state.group === "cancelled") @@ -53,7 +52,7 @@ export const AutoCloseAutomation: React.FC = ({ projectDetails, handleCha const multipleOptions = (options ?? []).length > 1; - const defaultState = stateGroups && stateGroups.cancelled ? stateGroups.cancelled[0].id : null; + const defaultState = states.find((s) => s.group === "cancelled")?.id || null; const selectedOption = states?.find((s) => s.id === projectDetails?.default_state ?? defaultState); const currentDefaultState = states?.find((s) => s.id === defaultState); diff --git a/web/components/command-palette/issue/change-issue-state.tsx b/web/components/command-palette/issue/change-issue-state.tsx index 03f495603ba..688aeb49f8a 100644 --- a/web/components/command-palette/issue/change-issue-state.tsx +++ b/web/components/command-palette/issue/change-issue-state.tsx @@ -1,9 +1,6 @@ import React, { Dispatch, SetStateAction, useCallback } from "react"; - import { useRouter } from "next/router"; - import useSWR, { mutate } from "swr"; - // cmdk import { Command } from "cmdk"; // services @@ -13,8 +10,6 @@ import { ProjectStateService } from "services/project"; import { Spinner, StateGroupIcon } from "@plane/ui"; // icons import { Check } from "lucide-react"; -// helpers -import { getStatesList } from "helpers/state.helper"; // types import { IUser, IIssue } from "types"; // fetch keys @@ -34,11 +29,10 @@ export const ChangeIssueState: React.FC = ({ setIsPaletteOpen, issue, use const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; - const { data: stateGroups, mutate: mutateIssueDetails } = useSWR( + const { data: states, mutate: mutateStates } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); - const states = getStatesList(stateGroups); const submitChanges = useCallback( async (formData: Partial) => { @@ -60,14 +54,14 @@ export const ChangeIssueState: React.FC = ({ setIsPaletteOpen, issue, use await issueService .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user) .then(() => { - mutateIssueDetails(); + mutateStates(); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); }) .catch((e) => { console.error(e); }); }, - [workspaceSlug, issueId, projectId, mutateIssueDetails, user] + [workspaceSlug, issueId, projectId, mutateStates, user] ); const handleIssueState = (stateId: string) => { diff --git a/web/components/issues/issue-layouts/filters/applied-filters/state.tsx b/web/components/issues/issue-layouts/filters/applied-filters/state.tsx index 5293a623a3b..eadcd88ad14 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/state.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/state.tsx @@ -3,26 +3,22 @@ import { observer } from "mobx-react-lite"; // icons import { StateGroupIcon } from "@plane/ui"; import { X } from "lucide-react"; -// helpers -import { getStatesList } from "helpers/state.helper"; // types -import { IStateResponse } from "types"; +import { IState } from "types"; type Props = { handleRemove: (val: string) => void; - states: IStateResponse | undefined; + states: IState[]; values: string[]; }; export const AppliedStateFilters: React.FC = observer((props) => { const { handleRemove, states, values } = props; - const statesList = getStatesList(states); - return (
{values.map((stateId) => { - const stateDetails = statesList?.find((s) => s.id === stateId); + const stateDetails = states?.find((s) => s.id === stateId); if (!stateDetails) return null; diff --git a/web/components/issues/issue-layouts/filters/header/filters/state.tsx b/web/components/issues/issue-layouts/filters/header/filters/state.tsx index 20caebc20f9..6f193d02938 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/state.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/state.tsx @@ -1,19 +1,16 @@ import React, { useState } from "react"; - // components import { FilterHeader, FilterOption } from "components/issues"; // ui import { Loader, StateGroupIcon } from "@plane/ui"; -// helpers -import { getStatesList } from "helpers/state.helper"; // types -import { IStateResponse } from "types"; +import { IState } from "types"; type Props = { appliedFilters: string[] | null; handleUpdate: (val: string) => void; searchQuery: string; - states: IStateResponse | undefined; + states: IState[] | undefined; }; export const FilterState: React.FC = (props) => { @@ -22,11 +19,9 @@ export const FilterState: React.FC = (props) => { const [itemsToRender, setItemsToRender] = useState(5); const [previewEnabled, setPreviewEnabled] = useState(true); - const statesList = getStatesList(states); - const appliedFiltersCount = appliedFilters?.length ?? 0; - const filteredOptions = statesList?.filter((s) => s.name.toLowerCase().includes(searchQuery.toLowerCase())); + const filteredOptions = states?.filter((s) => s.name.toLowerCase().includes(searchQuery.toLowerCase())); const handleViewToggle = () => { if (!filteredOptions) return; diff --git a/web/components/issues/select/state.tsx b/web/components/issues/select/state.tsx index 024024641fb..a0d16d94c65 100644 --- a/web/components/issues/select/state.tsx +++ b/web/components/issues/select/state.tsx @@ -1,17 +1,12 @@ import React from "react"; - import { useRouter } from "next/router"; - import useSWR from "swr"; - // services import { ProjectStateService } from "services/project"; // ui import { CustomSearchSelect, DoubleCircleIcon, StateGroupIcon } from "@plane/ui"; // icons import { Plus } from "lucide-react"; -// helpers -import { getStatesList } from "helpers/state.helper"; // fetch keys import { STATES_LIST } from "constants/fetch-keys"; @@ -30,11 +25,10 @@ export const IssueStateSelect: React.FC = ({ setIsOpen, value, onChange, const router = useRouter(); const { workspaceSlug } = router.query; - const { data: stateGroups } = useSWR( + const { data: states } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId) : null, workspaceSlug && projectId ? () => projectStateService.getStates(workspaceSlug as string, projectId) : null ); - const states = getStatesList(stateGroups); const options = states?.map((state) => ({ value: state.id, diff --git a/web/components/issues/sidebar-select/state.tsx b/web/components/issues/sidebar-select/state.tsx index a109ddab9a1..326a5cf487c 100644 --- a/web/components/issues/sidebar-select/state.tsx +++ b/web/components/issues/sidebar-select/state.tsx @@ -9,7 +9,6 @@ import { ProjectStateService } from "services/project"; // ui import { CustomSearchSelect, StateGroupIcon } from "@plane/ui"; // helpers -import { getStatesList } from "helpers/state.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper"; // constants import { STATES_LIST } from "constants/fetch-keys"; @@ -27,11 +26,10 @@ export const SidebarStateSelect: React.FC = ({ value, onChange, disabled const router = useRouter(); const { workspaceSlug, projectId, inboxIssueId } = router.query; - const { data: stateGroups } = useSWR( + const { data: states } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); - const states = getStatesList(stateGroups); const selectedOption = states?.find((s) => s.id === value); diff --git a/web/components/states/project-setting-state-list-item.tsx b/web/components/states/project-setting-state-list-item.tsx index b3146f43d7d..b264ad4bb03 100644 --- a/web/components/states/project-setting-state-list-item.tsx +++ b/web/components/states/project-setting-state-list-item.tsx @@ -1,14 +1,12 @@ import { useState } from "react"; import { useRouter } from "next/router"; - -// store import { observer } from "mobx-react-lite"; +// store import { useMobxStore } from "lib/mobx/store-provider"; // ui import { Tooltip, StateGroupIcon } from "@plane/ui"; // icons import { Pencil, X, ArrowDown, ArrowUp } from "lucide-react"; - // helpers import { addSpaceIfCamelCase } from "helpers/string.helper"; // types @@ -30,7 +28,9 @@ export const ProjectSettingListItem: React.FC = observer((props) => { const { workspaceSlug, projectId } = router.query; // store - const { projectState: projectStateStore } = useMobxStore(); + const { + projectState: { markStateAsDefault, moveStatePosition }, + } = useMobxStore(); // states const [isSubmitting, setIsSubmitting] = useState(false); @@ -41,18 +41,15 @@ export const ProjectSettingListItem: React.FC = observer((props) => { const handleMakeDefault = () => { if (!workspaceSlug || !projectId) return; - setIsSubmitting(true); - - projectStateStore.markStateAsDefault(workspaceSlug.toString(), projectId.toString(), state.id).finally(() => { + markStateAsDefault(workspaceSlug.toString(), projectId.toString(), state.id).finally(() => { setIsSubmitting(false); }); }; const handleMove = (state: IState, direction: "up" | "down") => { if (!workspaceSlug || !projectId) return; - - projectStateStore.moveStatePosition(workspaceSlug.toString(), projectId.toString(), state.id, direction, index); + moveStatePosition(workspaceSlug.toString(), projectId.toString(), state.id, direction, index); }; return ( diff --git a/web/components/states/project-setting-state-list.tsx b/web/components/states/project-setting-state-list.tsx index 94a33a11bec..b5ac492ce51 100644 --- a/web/components/states/project-setting-state-list.tsx +++ b/web/components/states/project-setting-state-list.tsx @@ -11,7 +11,8 @@ import { Loader } from "@plane/ui"; // icons import { Plus } from "lucide-react"; // helpers -import { getStatesList, orderStateGroups } from "helpers/state.helper"; +import { orderStateGroups } from "helpers/state.helper"; +import { sortByField } from "helpers/array.helper"; // fetch-keys import { STATES_LIST } from "constants/fetch-keys"; @@ -20,41 +21,99 @@ export const ProjectSettingStateList: React.FC = observer(() => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; // store - const { project: projectStore } = useMobxStore(); - const { currentProjectDetails } = projectStore; + const { + projectState: { groupedProjectStates, projectStates, fetchProjectStates }, + } = useMobxStore(); // state const [activeGroup, setActiveGroup] = useState(null); const [selectedState, setSelectedState] = useState(null); const [selectDeleteState, setSelectDeleteState] = useState(null); - useSWR( - workspaceSlug && projectId ? "PROJECT_DETAILS" : null, - workspaceSlug && projectId - ? () => projectStore.fetchProjectDetails(workspaceSlug.toString(), projectId.toString()) - : null - ); - useSWR( workspaceSlug && projectId ? STATES_LIST(projectId.toString()) : null, - workspaceSlug && projectId - ? () => projectStore.fetchProjectStates(workspaceSlug.toString(), projectId.toString()) - : null + workspaceSlug && projectId ? () => fetchProjectStates(workspaceSlug.toString(), projectId.toString()) : null ); // derived values - const states = projectStore.projectStatesByGroups; - const orderedStateGroups = orderStateGroups(states!); - const statesList = getStatesList(orderedStateGroups); + const orderedStateGroups = orderStateGroups(groupedProjectStates!); + + console.log("groupedStates", groupedProjectStates); + console.log("orderedStateGroups", orderedStateGroups); return ( <> setSelectDeleteState(null)} - data={statesList?.find((s) => s.id === selectDeleteState) ?? null} + data={projectStates?.find((s) => s.id === selectDeleteState) ?? null} />
+ {orderedStateGroups ? ( + <> + {Object.keys(orderedStateGroups).map((group) => ( +
+
+

{group}

+ +
+
+ {group === activeGroup && ( + { + setActiveGroup(null); + setSelectedState(null); + }} + selectedGroup={group as keyof StateGroup} + /> + )} + {sortByField(orderedStateGroups[group], "sequence").map((state, index) => + state.id !== selectedState ? ( + setSelectedState(state.id)} + handleDeleteState={() => setSelectDeleteState(state.id)} + /> + ) : ( +
+ { + setActiveGroup(null); + setSelectedState(null); + }} + groupLength={orderedStateGroups[group].length} + data={projectStates?.find((state) => state.id === selectedState) ?? null} + selectedGroup={group as keyof StateGroup} + /> +
+ ) + )} +
+
+ ))} + + ) : ( + + + + + + + )} +
+ + {/*
{states && currentProjectDetails && orderedStateGroups ? ( Object.keys(orderedStateGroups || {}).map((key) => { if (orderedStateGroups[key].length !== 0) @@ -118,7 +177,7 @@ export const ProjectSettingStateList: React.FC = observer(() => { )} -
+
*/} ); }); diff --git a/web/helpers/array.helper.ts b/web/helpers/array.helper.ts index a682b0a1c12..a55ad8fd90c 100644 --- a/web/helpers/array.helper.ts +++ b/web/helpers/array.helper.ts @@ -7,11 +7,7 @@ export const groupBy = (array: any[], key: string) => { }, {}); }; -export const orderArrayBy = ( - orgArray: any[], - key: string, - ordering: "ascending" | "descending" = "ascending" -) => { +export const orderArrayBy = (orgArray: any[], key: string, ordering: "ascending" | "descending" = "ascending") => { if (!orgArray || !Array.isArray(orgArray) || orgArray.length === 0) return []; const array = [...orgArray]; @@ -53,3 +49,28 @@ export const checkIfArraysHaveSameElements = (arr1: any[] | null, arr2: any[] | return arr1.length === arr2.length && arr1.every((e) => arr2.includes(e)); }; + +type GroupedItems = { [key: string]: T[] }; + +export const groupByField = (array: T[], field: keyof T): GroupedItems => + array.reduce((grouped: GroupedItems, item: T) => { + const key = String(item[field]); + grouped[key] = (grouped[key] || []).concat(item); + return grouped; + }, {}); + +export const sortByField = (array: any[], field: string): any[] => + array.sort((a, b) => (a[field] < b[field] ? -1 : a[field] > b[field] ? 1 : 0)); + +export const orderGroupedDataByField = (groupedData: GroupedItems, orderBy: keyof T): GroupedItems => { + for (const key in groupedData) { + if (groupedData.hasOwnProperty(key)) { + groupedData[key] = groupedData[key].sort((a, b) => { + if (a[orderBy] < b[orderBy]) return -1; + if (a[orderBy] > b[orderBy]) return 1; + return 0; + }); + } + } + return groupedData; +}; diff --git a/web/helpers/state.helper.ts b/web/helpers/state.helper.ts index edf740c1065..ef6c3ba77f0 100644 --- a/web/helpers/state.helper.ts +++ b/web/helpers/state.helper.ts @@ -1,27 +1,7 @@ // types -import { IState, IStateResponse } from "types"; +import { IStateResponse } from "types"; -export const orderStateGroups = ( - unorderedStateGroups: IStateResponse | undefined -): IStateResponse | undefined => { +export const orderStateGroups = (unorderedStateGroups: IStateResponse | undefined): IStateResponse | undefined => { if (!unorderedStateGroups) return undefined; - - return Object.assign( - { backlog: [], unstarted: [], started: [], completed: [], cancelled: [] }, - unorderedStateGroups - ); -}; - -export const getStatesList = (stateGroups: IStateResponse | undefined): IState[] | undefined => { - if (!stateGroups) return undefined; - - // order the unordered state groups first - const orderedStateGroups = orderStateGroups(stateGroups); - - if (!orderedStateGroups) return undefined; - - // extract states from the groups and return them - return Object.keys(orderedStateGroups) - .map((group) => [...orderedStateGroups[group].map((state: IState) => state)]) - .flat(); + return Object.assign({ backlog: [], unstarted: [], started: [], completed: [], cancelled: [] }, unorderedStateGroups); }; diff --git a/web/services/project/project_state.service.ts b/web/services/project/project_state.service.ts index 018df3a2053..44b649327a4 100644 --- a/web/services/project/project_state.service.ts +++ b/web/services/project/project_state.service.ts @@ -4,7 +4,7 @@ import { TrackEventService } from "services/track_event.service"; // helpers import { API_BASE_URL } from "helpers/common.helper"; // types -import type { IUser, IState, IStateResponse } from "types"; +import type { IUser, IState } from "types"; const trackEventService = new TrackEventService(); @@ -13,7 +13,7 @@ export class ProjectStateService extends APIService { super(API_BASE_URL); } - async createState(workspaceSlug: string, projectId: string, data: any, user: IUser | undefined): Promise { + async createState(workspaceSlug: string, projectId: string, data: any, user: IUser | undefined): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data) .then((response) => { trackEventService.trackStateEvent(response?.data, "STATE_CREATE", user as IUser); @@ -24,17 +24,16 @@ export class ProjectStateService extends APIService { }); } - async getStates(workspaceSlug: string, projectId: string): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`) + async markDefault(workspaceSlug: string, projectId: string, stateId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/mark-default/`, {}) .then((response) => response?.data) .catch((error) => { - throw error?.response?.data; + throw error?.response; }); } - async getIssuesByState(workspaceSlug: string, projectId: string): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/?group_by=state`) - + async getStates(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; diff --git a/web/store/project/project.store.ts b/web/store/project/project.store.ts index 976654ee9ee..f207ce9999d 100644 --- a/web/store/project/project.store.ts +++ b/web/store/project/project.store.ts @@ -1,7 +1,7 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx"; // types import { RootStore } from "../root"; -import { IProject, IIssueLabels, IProjectMember, IStateResponse, IState, IEstimate } from "types"; +import { IProject, IIssueLabels, IProjectMember, IEstimate } from "types"; // services import { ProjectService, ProjectStateService, ProjectEstimateService } from "services/project"; import { IssueService, IssueLabelService } from "services/issue"; @@ -16,9 +16,6 @@ export interface IProjectStore { project_details: { [projectId: string]: IProject; // projectId: project Info }; - states: { - [projectId: string]: IStateResponse; // project_id: states - } | null; labels: { [projectId: string]: IIssueLabels[] | null; // project_id: labels } | null; @@ -32,8 +29,6 @@ export interface IProjectStore { // computed searchedProjects: IProject[]; workspaceProjects: IProject[]; - projectStatesByGroups: IStateResponse | null; - projectStates: IState[] | null; projectLabels: IIssueLabels[] | null; projectMembers: IProjectMember[] | null; projectEstimates: IEstimate[] | null; @@ -48,7 +43,6 @@ export interface IProjectStore { setSearchQuery: (query: string) => void; getProjectById: (workspaceSlug: string, projectId: string) => IProject | null; - getProjectStateById: (stateId: string) => IState | null; getProjectLabelById: (labelId: string) => IIssueLabels | null; getProjectMemberById: (memberId: string) => IProjectMember | null; getProjectMemberByUserId: (memberId: string) => IProjectMember | null; @@ -56,7 +50,6 @@ export interface IProjectStore { fetchProjects: (workspaceSlug: string) => Promise; fetchProjectDetails: (workspaceSlug: string, projectId: string) => Promise; - fetchProjectStates: (workspaceSlug: string, projectId: string) => Promise; fetchProjectLabels: (workspaceSlug: string, projectId: string) => Promise; fetchProjectMembers: (workspaceSlug: string, projectId: string) => Promise; fetchProjectEstimates: (workspaceSlug: string, projectId: string) => Promise; @@ -93,9 +86,6 @@ export class ProjectStore implements IProjectStore { project_details: { [projectId: string]: IProject; // projectId: project } = {}; - states: { - [projectId: string]: IStateResponse; // projectId: states - } | null = {}; labels: { [projectId: string]: IIssueLabels[]; // projectId: labels } | null = {}; @@ -125,7 +115,6 @@ export class ProjectStore implements IProjectStore { projectId: observable.ref, projects: observable.ref, project_details: observable.ref, - states: observable.ref, labels: observable.ref, members: observable.ref, estimates: observable.ref, @@ -133,8 +122,6 @@ export class ProjectStore implements IProjectStore { // computed searchedProjects: computed, workspaceProjects: computed, - projectStatesByGroups: computed, - projectStates: computed, projectLabels: computed, projectMembers: computed, projectEstimates: computed, @@ -151,12 +138,10 @@ export class ProjectStore implements IProjectStore { fetchProjectDetails: action, getProjectById: action, - getProjectStateById: action, getProjectLabelById: action, getProjectMemberById: action, getProjectEstimateById: action, - fetchProjectStates: action, fetchProjectLabels: action, fetchProjectMembers: action, fetchProjectEstimates: action, @@ -217,24 +202,6 @@ export class ProjectStore implements IProjectStore { return this.projects?.[this.rootStore.workspace.workspaceSlug]?.filter((p) => p.is_favorite); } - get projectStatesByGroups() { - if (!this.projectId) return null; - return this.states?.[this.projectId] || null; - } - - get projectStates() { - if (!this.projectId) return null; - const stateByGroups: IStateResponse | null = this.projectStatesByGroups; - if (!stateByGroups) return null; - const _states: IState[] = []; - Object.keys(stateByGroups).forEach((_stateGroup: string) => { - stateByGroups[_stateGroup].map((state) => { - _states.push(state); - }); - }); - return _states.length > 0 ? _states : null; - } - get projectLabels() { if (!this.projectId) return null; return this.labels?.[this.projectId] || null; @@ -304,14 +271,6 @@ export class ProjectStore implements IProjectStore { return projectInfo; }; - getProjectStateById = (stateId: string) => { - if (!this.projectId) return null; - const states = this.projectStates; - if (!states) return null; - const stateInfo: IState | null = states.find((state) => state.id === stateId) || null; - return stateInfo; - }; - getProjectLabelById = (labelId: string) => { if (!this.projectId) return null; const labels = this.projectLabels; @@ -344,29 +303,6 @@ export class ProjectStore implements IProjectStore { return estimateInfo; }; - fetchProjectStates = async (workspaceSlug: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const stateResponse = await this.stateService.getStates(workspaceSlug, projectId); - const _states = { - ...this.states, - [projectId]: stateResponse, - }; - - runInAction(() => { - this.states = _states; - this.loader = false; - this.error = null; - }); - } catch (error) { - console.error(error); - this.loader = false; - this.error = error; - } - }; - fetchProjectLabels = async (workspaceSlug: string, projectId: string) => { try { this.loader = true; diff --git a/web/store/project/project_state.store.ts b/web/store/project/project_state.store.ts index 56fc0c203ca..b0b136cb2a3 100644 --- a/web/store/project/project_state.store.ts +++ b/web/store/project/project_state.store.ts @@ -1,17 +1,23 @@ -import { observable, action, makeObservable, runInAction } from "mobx"; +import { observable, action, makeObservable, runInAction, computed } from "mobx"; // types import { RootStore } from "../root"; import { IState } from "types"; // services import { ProjectService, ProjectStateService } from "services/project"; -import { groupBy, orderArrayBy } from "helpers/array.helper"; +import { groupBy, orderArrayBy, groupByField } from "helpers/array.helper"; import { orderStateGroups } from "helpers/state.helper"; export interface IProjectStateStore { loader: boolean; error: any | null; - // states + states: { + [projectId: string]: IState[]; // projectId: states + }; + groupedProjectStates: { [groupId: string]: IState[] } | null; + projectStates: IState[] | null; + + fetchProjectStates: (workspaceSlug: string, projectId: string) => Promise; createState: (workspaceSlug: string, projectId: string, data: Partial) => Promise; updateState: (workspaceSlug: string, projectId: string, stateId: string, data: Partial) => Promise; deleteState: (workspaceSlug: string, projectId: string, stateId: string) => Promise; @@ -28,7 +34,9 @@ export interface IProjectStateStore { export class ProjectStateStore implements IProjectStateStore { loader: boolean = false; error: any | null = null; - + states: { + [projectId: string]: IState[]; // projectId: states + } = {}; // root store rootStore; // service @@ -38,10 +46,13 @@ export class ProjectStateStore implements IProjectStateStore { constructor(_rootStore: RootStore) { makeObservable(this, { // observable - loader: observable, - error: observable, - - // states + loader: observable.ref, + error: observable.ref, + states: observable.ref, + // computed + projectStates: computed, + groupedProjectStates: computed, + // actions createState: action, updateState: action, deleteState: action, @@ -54,6 +65,43 @@ export class ProjectStateStore implements IProjectStateStore { this.stateService = new ProjectStateService(); } + get groupedProjectStates() { + if (!this.rootStore.project.projectId) return null; + const states = this.states[this.rootStore.project.projectId]; + if (!states) return null; + return groupByField(states, "group"); + } + + get projectStates() { + if (!this.rootStore.project.projectId) return null; + const states = this.states[this.rootStore.project.projectId]; + if (!states) return null; + return states; + } + + fetchProjectStates = async (workspaceSlug: string, projectId: string) => { + try { + const states = await this.stateService.getStates(workspaceSlug, projectId); + runInAction(() => { + this.states = { + ...this.states, + [projectId]: states, + }; + }); + return states; + } catch (error) { + throw error; + } + }; + + getProjectStateById = (stateId: string) => { + if (!this.rootStore.project.projectId) return null; + const states = this.states[this.rootStore.project.projectId]; + if (!states) return null; + const stateInfo: IState | null = states.find((state) => state.id === stateId) || null; + return stateInfo; + }; + createState = async (workspaceSlug: string, projectId: string, data: Partial) => { try { const response = await this.stateService.createState( @@ -64,12 +112,9 @@ export class ProjectStateStore implements IProjectStateStore { ); runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: { - ...this.rootStore.project.states?.[projectId], - [response.group]: [...(this.rootStore.project.states?.[projectId]?.[response.group] || []), response], - }, + this.states = { + ...this.states, + [projectId]: [...this.states?.[projectId], response], }; }); @@ -81,21 +126,23 @@ export class ProjectStateStore implements IProjectStateStore { }; updateState = async (workspaceSlug: string, projectId: string, stateId: string, data: Partial) => { - const originalStates = this.rootStore.project.states || {}; - - runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: { - ...this.rootStore.project.states?.[projectId], - [data.group as string]: (this.rootStore.project.states?.[projectId]?.[data.group as string] || []).map( - (state) => (state.id === stateId ? { ...state, ...data } : state) - ), - }, - }; - }); + const originalStates = this.states; try { + runInAction(() => { + this.states = { + ...this.states, + [projectId]: [ + ...this.states?.[projectId].map((state) => { + if (state.id === stateId) { + return { ...state, ...data }; + } + return state; + }), + ], + }; + }); + const response = await this.stateService.patchState( workspaceSlug, projectId, @@ -104,41 +151,30 @@ export class ProjectStateStore implements IProjectStateStore { this.rootStore.user.currentUser! ); - runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: { - ...this.rootStore.project.states?.[projectId], - [response.group]: (this.rootStore.project.states?.[projectId]?.[response.group] || []).map((state) => - state.id === stateId ? { ...state, ...response } : state - ), - }, - }; - }); - return response; } catch (error) { console.log("Failed to update state from project store"); runInAction(() => { - this.rootStore.project.states = originalStates; + this.states = originalStates; }); throw error; } }; deleteState = async (workspaceSlug: string, projectId: string, stateId: string) => { - const originalStates = this.rootStore.project.projectStates; + const originalStates = this.states; try { runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: { - ...this.rootStore.project.states?.[projectId], - [originalStates?.[0]?.group || ""]: ( - this.rootStore.project.states?.[projectId]?.[originalStates?.[0]?.group || ""] || [] - ).filter((state) => state.id !== stateId), - }, + this.states = { + ...this.states, + [projectId]: [ + ...this.states?.[projectId].filter((state) => { + if (state.id !== stateId) { + return stateId; + } + }), + ], }; }); @@ -148,65 +184,41 @@ export class ProjectStateStore implements IProjectStateStore { console.log("Failed to delete state from project store"); // reverting back to original label list runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: { - ...this.rootStore.project.states?.[projectId], - [originalStates?.[0]?.group || ""]: originalStates || [], - }, - }; + this.states = originalStates; }); + throw error; } }; markStateAsDefault = async (workspaceSlug: string, projectId: string, stateId: string) => { - const states = this.rootStore.project.projectStates; - const currentDefaultState = states?.find((state) => state.default); - - let newStateList = - states?.map((state) => { - if (state.id === stateId) return { ...state, default: true }; - if (state.id === currentDefaultState?.id) return { ...state, default: false }; - return state; - }) ?? []; - newStateList = orderArrayBy(newStateList, "sequence", "ascending"); - - const newOrderedStateGroups = orderStateGroups(groupBy(newStateList, "group")); - const oldOrderedStateGroup = this.rootStore.project.states?.[projectId] || {}; // for reverting back to old state group if api fails - - runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: newOrderedStateGroups || {}, - }; - }); - - // updating using api + const originalStates = this.states; try { - this.stateService.patchState( - workspaceSlug, - projectId, - stateId, - { default: true }, - this.rootStore.user.currentUser! - ); + const currentDefaultStateIds = this.projectStates?.filter((s) => s.default).map((state) => state.id); - if (currentDefaultState) - this.stateService.patchState( - workspaceSlug, - projectId, - currentDefaultState.id, - { default: false }, - this.rootStore.user.currentUser! - ); - } catch (err) { - console.log("Failed to mark state as default"); runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: oldOrderedStateGroup, + this.states = { + ...this.states, + [projectId]: [ + ...this.states[projectId].map((state) => { + if (currentDefaultStateIds?.includes(state.id)) { + return { ...state, default: false }; + } else if (state.id === stateId) { + return { ...state, default: true }; + } + return state; + }), + ], }; }); + + // updating using api + await this.stateService.markDefault(workspaceSlug, projectId, stateId); + } catch (error) { + console.log("Failed to mark state as default"); + runInAction(() => { + this.states = originalStates; + }); + throw error; } }; @@ -218,40 +230,35 @@ export class ProjectStateStore implements IProjectStateStore { groupIndex: number ) => { const SEQUENCE_GAP = 15000; - let newSequence = SEQUENCE_GAP; - - const states = this.rootStore.project.projectStates || []; - const groupedStates = groupBy(states || [], "group"); - - const selectedState = states?.find((state) => state.id === stateId); - const groupStates = states?.filter((state) => state.group === selectedState?.group); - const groupLength = groupStates.length; + const originalStates = this.states; - if (direction === "up") { - if (groupIndex === 1) newSequence = groupStates[0].sequence - SEQUENCE_GAP; - else newSequence = (groupStates[groupIndex - 2].sequence + groupStates[groupIndex - 1].sequence) / 2; - } else { - if (groupIndex === groupLength - 2) newSequence = groupStates[groupLength - 1].sequence + SEQUENCE_GAP; - else newSequence = (groupStates[groupIndex + 2].sequence + groupStates[groupIndex + 1].sequence) / 2; - } + try { + let newSequence = SEQUENCE_GAP; + const states = this.projectStates || []; + const selectedState = states?.find((state) => state.id === stateId); + const groupStates = states?.filter((state) => state.group === selectedState?.group); + const groupLength = groupStates.length; + if (direction === "up") { + if (groupIndex === 1) newSequence = groupStates[0].sequence - SEQUENCE_GAP; + else newSequence = (groupStates[groupIndex - 2].sequence + groupStates[groupIndex - 1].sequence) / 2; + } else { + if (groupIndex === groupLength - 2) newSequence = groupStates[groupLength - 1].sequence + SEQUENCE_GAP; + else newSequence = (groupStates[groupIndex + 2].sequence + groupStates[groupIndex + 1].sequence) / 2; + } - const newStateList = states?.map((state) => { - if (state.id === stateId) return { ...state, sequence: newSequence }; - return state; - }); - const newOrderedStateGroups = orderStateGroups( - groupBy(orderArrayBy(newStateList, "sequence", "ascending"), "group") - ); + const newStateList = states?.map((state) => { + if (state.id === stateId) return { ...state, sequence: newSequence }; + return state; + }); - runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: newOrderedStateGroups || {}, - }; - }); + // updating using api + runInAction(() => { + this.states = { + ...this.states, + [projectId]: newStateList, + }; + }); - // updating using api - try { await this.stateService.patchState( workspaceSlug, projectId, @@ -263,10 +270,7 @@ export class ProjectStateStore implements IProjectStateStore { console.log("Failed to move state position"); // reverting back to old state group if api fails runInAction(() => { - this.rootStore.project.states = { - ...this.rootStore.project.states, - [projectId]: groupedStates, - }; + this.states = originalStates; }); } }; From 8098bb2e8e30310017e54d2e7e74ed32e7da494d Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Wed, 8 Nov 2023 20:26:27 +0530 Subject: [PATCH 2/3] fix: states fixes --- web/components/headers/cycle-issues.tsx | 3 +- web/components/headers/module-issues.tsx | 3 +- .../headers/project-archived-issues.tsx | 12 ++-- web/components/headers/project-issues.tsx | 3 +- .../headers/project-view-issues.tsx | 3 +- .../filters/applied-filters/filters-list.tsx | 6 +- .../applied-filters/roots/archived-issue.tsx | 8 ++- .../applied-filters/roots/cycle-root.tsx | 9 ++- .../applied-filters/roots/module-root.tsx | 4 +- .../applied-filters/roots/project-root.tsx | 4 +- .../roots/project-view-root.tsx | 3 +- .../header/filters/filters-selection.tsx | 4 +- .../issue-layouts/kanban/roots/cycle-root.tsx | 3 +- .../kanban/roots/module-root.tsx | 5 +- .../kanban/roots/profile-issues-root.tsx | 3 +- .../kanban/roots/project-root.tsx | 3 +- .../kanban/roots/project-view-root.tsx | 7 +- .../list/roots/archived-issue-root.tsx | 3 +- .../issue-layouts/list/roots/cycle-root.tsx | 3 +- .../issue-layouts/list/roots/module-root.tsx | 3 +- .../list/roots/profile-issues-root.tsx | 3 +- .../issue-layouts/list/roots/project-root.tsx | 3 +- .../list/roots/project-view-root.tsx | 11 +++- .../issues/issue-layouts/properties/state.tsx | 6 +- .../spreadsheet/columns/columns-list.tsx | 11 +--- .../spreadsheet/columns/state-column.tsx | 4 +- .../spreadsheet/roots/cycle-root.tsx | 3 +- .../spreadsheet/roots/module-root.tsx | 3 +- .../spreadsheet/roots/project-root.tsx | 3 +- .../spreadsheet/roots/project-view-root.tsx | 3 +- .../spreadsheet/spreadsheet-column.tsx | 11 +--- .../spreadsheet/spreadsheet-view.tsx | 11 +--- web/components/issues/select/date.tsx | 10 +-- web/components/views/form.tsx | 6 +- web/layouts/auth-layout/project-wrapper.tsx | 66 +++++++------------ 35 files changed, 119 insertions(+), 127 deletions(-) diff --git a/web/components/headers/cycle-issues.tsx b/web/components/headers/cycle-issues.tsx index 42836b0eaa5..0fb8913d52f 100644 --- a/web/components/headers/cycle-issues.tsx +++ b/web/components/headers/cycle-issues.tsx @@ -31,6 +31,7 @@ export const CycleIssuesHeader: React.FC = observer(() => { cycle: cycleStore, cycleIssueFilter: cycleIssueFilterStore, project: projectStore, + projectState: projectStateStore, commandPalette: commandPaletteStore, } = useMobxStore(); const { currentProjectDetails } = projectStore; @@ -178,7 +179,7 @@ export const CycleIssuesHeader: React.FC = observer(() => { } labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined} + states={projectStateStore.states?.[projectId?.toString() ?? ""] ?? undefined} /> diff --git a/web/components/headers/module-issues.tsx b/web/components/headers/module-issues.tsx index 1eec1cff4d0..8364815cac6 100644 --- a/web/components/headers/module-issues.tsx +++ b/web/components/headers/module-issues.tsx @@ -31,6 +31,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => { module: moduleStore, moduleFilter: moduleFilterStore, project: projectStore, + projectState: projectStateStore, commandPalette: commandPaletteStore, } = useMobxStore(); const activeLayout = issueFilterStore.userDisplayFilters.layout; @@ -177,7 +178,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => { } labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined} + states={projectStateStore.states?.[projectId?.toString() ?? ""] ?? undefined} /> diff --git a/web/components/headers/project-archived-issues.tsx b/web/components/headers/project-archived-issues.tsx index e68f4ce8411..7dd06e3a9b3 100644 --- a/web/components/headers/project-archived-issues.tsx +++ b/web/components/headers/project-archived-issues.tsx @@ -5,10 +5,8 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; // constants import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; -// helper -import { truncateText } from "helpers/string.helper"; // ui -import { Breadcrumbs, BreadcrumbItem, LayersIcon } from "@plane/ui"; +import { Breadcrumbs, LayersIcon } from "@plane/ui"; // icons import { ArrowLeft } from "lucide-react"; // components @@ -22,7 +20,11 @@ export const ProjectArchivedIssuesHeader: FC = observer(() => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; - const { project: projectStore, archivedIssueFilters: archivedIssueFiltersStore } = useMobxStore(); + const { + project: projectStore, + archivedIssueFilters: archivedIssueFiltersStore, + projectState: projectStateStore, + } = useMobxStore(); const { currentProjectDetails } = projectStore; @@ -118,7 +120,7 @@ export const ProjectArchivedIssuesHeader: FC = observer(() => { } labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined} + states={projectStateStore.states?.[projectId?.toString() ?? ""] ?? undefined} /> diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx index efe4dcf51ca..e63b348e0fc 100644 --- a/web/components/headers/project-issues.tsx +++ b/web/components/headers/project-issues.tsx @@ -26,6 +26,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => { const { issueFilter: issueFilterStore, project: projectStore, + projectState: projectStateStore, inbox: inboxStore, commandPalette: commandPaletteStore, } = useMobxStore(); @@ -172,7 +173,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => { } labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined} + states={projectStateStore.states?.[projectId?.toString() ?? ""] ?? undefined} /> diff --git a/web/components/headers/project-view-issues.tsx b/web/components/headers/project-view-issues.tsx index 50d97505c95..dfb3a30b2b5 100644 --- a/web/components/headers/project-view-issues.tsx +++ b/web/components/headers/project-view-issues.tsx @@ -23,6 +23,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { issueFilter: issueFilterStore, projectViewFilters: projectViewFiltersStore, project: projectStore, + projectState: projectStateStore, projectViews: projectViewsStore, } = useMobxStore(); @@ -163,7 +164,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { } labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined} + states={projectStateStore.states?.[projectId?.toString() ?? ""] ?? undefined} /> diff --git a/web/components/issues/issue-layouts/filters/applied-filters/filters-list.tsx b/web/components/issues/issue-layouts/filters/applied-filters/filters-list.tsx index 83c072ede28..e8bc9c3720f 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/filters-list.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/filters-list.tsx @@ -15,7 +15,7 @@ import { X } from "lucide-react"; // helpers import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper"; // types -import { IIssueFilterOptions, IIssueLabels, IProject, IStateResponse, IUserLite } from "types"; +import { IIssueFilterOptions, IIssueLabels, IProject, IState, IUserLite } from "types"; type Props = { appliedFilters: IIssueFilterOptions; @@ -24,7 +24,7 @@ type Props = { labels?: IIssueLabels[] | undefined; members?: IUserLite[] | undefined; projects?: IProject[] | undefined; - states?: IStateResponse | undefined; + states?: IState[] | undefined; }; const membersFilters = ["assignees", "mentions", "created_by", "subscriber"]; @@ -70,7 +70,7 @@ export const AppliedFiltersList: React.FC = observer((props) => { {filterKey === "priority" && ( handleRemoveFilter("priority", val)} values={value} /> )} - {filterKey === "state" && ( + {filterKey === "state" && states && ( handleRemoveFilter("state", val)} states={states} diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/archived-issue.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/archived-issue.tsx index 20e20d34e37..d9984c4828b 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/archived-issue.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/archived-issue.tsx @@ -12,7 +12,11 @@ export const ArchivedIssueAppliedFiltersRoot: React.FC = observer(() => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; - const { archivedIssueFilters: archivedIssueFiltersStore, project: projectStore } = useMobxStore(); + const { + archivedIssueFilters: archivedIssueFiltersStore, + project: projectStore, + projectState: projectStateStore, + } = useMobxStore(); const userFilters = archivedIssueFiltersStore.userFilters; @@ -74,7 +78,7 @@ export const ArchivedIssueAppliedFiltersRoot: React.FC = observer(() => { handleRemoveFilter={handleRemoveFilter} labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? []} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""]} + states={projectStateStore.states?.[projectId?.toString() ?? ""]} /> ); diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/cycle-root.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/cycle-root.tsx index 5910eff960a..407aa6425cc 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/cycle-root.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/cycle-root.tsx @@ -1,6 +1,5 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; - // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components @@ -12,7 +11,11 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => { const router = useRouter(); const { workspaceSlug, projectId, cycleId } = router.query; - const { project: projectStore, cycleIssueFilter: cycleIssueFilterStore } = useMobxStore(); + const { + project: projectStore, + cycleIssueFilter: cycleIssueFilterStore, + projectState: projectStateStore, + } = useMobxStore(); const userFilters = cycleIssueFilterStore.cycleFilters; @@ -70,7 +73,7 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => { handleRemoveFilter={handleRemoveFilter} labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? []} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""]} + states={projectStateStore.states?.[projectId?.toString() ?? ""]} /> ); diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/module-root.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/module-root.tsx index 6bcfb40f56d..7875aecd7c5 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/module-root.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/module-root.tsx @@ -12,7 +12,7 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => { const router = useRouter(); const { workspaceSlug, projectId, moduleId } = router.query; - const { project: projectStore, moduleFilter: moduleFilterStore } = useMobxStore(); + const { project: projectStore, moduleFilter: moduleFilterStore, projectState: projectStateStore } = useMobxStore(); const userFilters = moduleFilterStore.moduleFilters; @@ -70,7 +70,7 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => { handleRemoveFilter={handleRemoveFilter} labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? []} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""]} + states={projectStateStore.states?.[projectId?.toString() ?? ""]} /> ); diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-root.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-root.tsx index 505649bce30..acf985051d9 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-root.tsx @@ -12,7 +12,7 @@ export const ProjectAppliedFiltersRoot: React.FC = observer(() => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; - const { issueFilter: issueFilterStore, project: projectStore } = useMobxStore(); + const { issueFilter: issueFilterStore, project: projectStore, projectState: projectStateStore } = useMobxStore(); const userFilters = issueFilterStore.userFilters; @@ -74,7 +74,7 @@ export const ProjectAppliedFiltersRoot: React.FC = observer(() => { handleRemoveFilter={handleRemoveFilter} labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? []} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""]} + states={projectStateStore.states?.[projectId?.toString() ?? ""]} /> ); diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx index c8ee36fe75d..baa1ce20d61 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx @@ -19,6 +19,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => { const { project: projectStore, + projectState: projectStateStore, projectViews: projectViewsStore, projectViewFilters: projectViewFiltersStore, } = useMobxStore(); @@ -99,7 +100,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => { handleRemoveFilter={handleRemoveFilter} labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? []} members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)} - states={projectStore.states?.[projectId?.toString() ?? ""]} + states={projectStateStore.states?.[projectId?.toString() ?? ""]} /> {storedFilters && viewDetails && areFiltersDifferent(storedFilters, viewDetails.query_data ?? {}) && ( ); - } + }, ); Button.displayName = "plane-ui-button"; diff --git a/packages/ui/src/button/helper.tsx b/packages/ui/src/button/helper.tsx index 82489c3e81a..48b1fc94a0f 100644 --- a/packages/ui/src/button/helper.tsx +++ b/packages/ui/src/button/helper.tsx @@ -102,7 +102,7 @@ export const buttonStyling: IButtonStyling = { export const getButtonStyling = ( variant: TButtonVariant, size: TButtonSizes, - disabled: boolean = false + disabled: boolean = false, ): string => { let _variant: string = ``; const currentVariant = buttonStyling[variant]; diff --git a/packages/ui/src/dropdowns/custom-search-select.tsx b/packages/ui/src/dropdowns/custom-search-select.tsx index 3f1e503a8a0..0fb4c67cf32 100644 --- a/packages/ui/src/dropdowns/custom-search-select.tsx +++ b/packages/ui/src/dropdowns/custom-search-select.tsx @@ -35,7 +35,7 @@ export const CustomSearchSelect = (props: ICustomSearchSelectProps) => { const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState( - null + null, ); const { styles, attributes } = usePopper(referenceElement, popperElement, { @@ -46,7 +46,7 @@ export const CustomSearchSelect = (props: ICustomSearchSelectProps) => { query === "" ? options : options?.filter((option) => - option.query.toLowerCase().includes(query.toLowerCase()) + option.query.toLowerCase().includes(query.toLowerCase()), ); const comboboxProps: any = { diff --git a/packages/ui/src/dropdowns/custom-select.tsx b/packages/ui/src/dropdowns/custom-select.tsx index dd4d1d786e3..b62ff2cb3b5 100644 --- a/packages/ui/src/dropdowns/custom-select.tsx +++ b/packages/ui/src/dropdowns/custom-select.tsx @@ -30,7 +30,7 @@ const CustomSelect = (props: ICustomSelectProps) => { const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState( - null + null, ); const { styles, attributes } = usePopper(referenceElement, popperElement, { diff --git a/packages/ui/src/form-fields/index.ts b/packages/ui/src/form-fields/index.ts index 49f6f1552fe..9cac734283e 100644 --- a/packages/ui/src/form-fields/index.ts +++ b/packages/ui/src/form-fields/index.ts @@ -1,3 +1,3 @@ export * from "./input"; export * from "./textarea"; -export * from "./input-color-picker" \ No newline at end of file +export * from "./input-color-picker"; diff --git a/packages/ui/src/form-fields/textarea.tsx b/packages/ui/src/form-fields/textarea.tsx index e53979edca2..8490326b89a 100644 --- a/packages/ui/src/form-fields/textarea.tsx +++ b/packages/ui/src/form-fields/textarea.tsx @@ -10,7 +10,7 @@ export interface TextAreaProps // Updates the height of a