forked from github/plane
refactor: spreadsheet layout
This commit is contained in:
parent
8aebf0bbd2
commit
0c13d05e27
@ -22,7 +22,6 @@ type Props = {
|
||||
properties: Properties;
|
||||
handleEditIssue: (issue: IIssue) => void;
|
||||
handleDeleteIssue: (issue: IIssue) => void;
|
||||
setCurrentProjectId: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
disableUserActions: boolean;
|
||||
nestingLevel: number;
|
||||
};
|
||||
@ -35,7 +34,6 @@ export const IssueColumn: React.FC<Props> = ({
|
||||
properties,
|
||||
handleEditIssue,
|
||||
handleDeleteIssue,
|
||||
setCurrentProjectId,
|
||||
disableUserActions,
|
||||
nestingLevel,
|
||||
}) => {
|
||||
@ -49,7 +47,7 @@ export const IssueColumn: React.FC<Props> = ({
|
||||
|
||||
const openPeekOverview = () => {
|
||||
const { query } = router;
|
||||
setCurrentProjectId(issue.project_detail.id);
|
||||
|
||||
router.push({
|
||||
pathname: router.pathname,
|
||||
query: { ...query, peekIssue: issue.id },
|
||||
|
@ -14,7 +14,6 @@ type Props = {
|
||||
setExpandedIssues: React.Dispatch<React.SetStateAction<string[]>>;
|
||||
properties: Properties;
|
||||
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
|
||||
setCurrentProjectId: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
disableUserActions: boolean;
|
||||
nestingLevel?: number;
|
||||
};
|
||||
@ -26,7 +25,6 @@ export const SpreadsheetIssuesColumn: React.FC<Props> = ({
|
||||
setExpandedIssues,
|
||||
properties,
|
||||
handleIssueAction,
|
||||
setCurrentProjectId,
|
||||
disableUserActions,
|
||||
nestingLevel = 0,
|
||||
}) => {
|
||||
@ -57,7 +55,6 @@ export const SpreadsheetIssuesColumn: React.FC<Props> = ({
|
||||
properties={properties}
|
||||
handleEditIssue={() => handleIssueAction(issue, "edit")}
|
||||
handleDeleteIssue={() => handleIssueAction(issue, "delete")}
|
||||
setCurrentProjectId={setCurrentProjectId}
|
||||
disableUserActions={disableUserActions}
|
||||
nestingLevel={nestingLevel}
|
||||
/>
|
||||
@ -75,7 +72,6 @@ export const SpreadsheetIssuesColumn: React.FC<Props> = ({
|
||||
setExpandedIssues={setExpandedIssues}
|
||||
properties={properties}
|
||||
handleIssueAction={handleIssueAction}
|
||||
setCurrentProjectId={setCurrentProjectId}
|
||||
disableUserActions={disableUserActions}
|
||||
nestingLevel={nestingLevel + 1}
|
||||
/>
|
||||
|
@ -19,7 +19,7 @@ import { StateSelect } from "components/states";
|
||||
import { copyTextToClipboard } from "helpers/string.helper";
|
||||
import { renderLongDetailDateFormat } from "helpers/date-time.helper";
|
||||
// types
|
||||
import { ICurrentUserResponse, IIssue, IState, ISubIssueResponse, Properties, TIssuePriorities, UserAuth } from "types";
|
||||
import { IUser, IIssue, IState, ISubIssueResponse, Properties, TIssuePriorities, UserAuth } from "types";
|
||||
// constant
|
||||
import {
|
||||
CYCLE_DETAILS,
|
||||
@ -42,7 +42,7 @@ type Props = {
|
||||
handleDeleteIssue: (issue: IIssue) => void;
|
||||
gridTemplateColumns: string;
|
||||
disableUserActions: boolean;
|
||||
user: ICurrentUserResponse | undefined;
|
||||
user: IUser | undefined;
|
||||
userAuth: UserAuth;
|
||||
nestingLevel: number;
|
||||
};
|
||||
@ -159,6 +159,8 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
};
|
||||
|
||||
const handleStateChange = (data: string, states: IState[] | undefined) => {
|
||||
if (!user) return;
|
||||
|
||||
const oldState = states?.find((s) => s.id === issue.state);
|
||||
const newState = states?.find((s) => s.id === data);
|
||||
|
||||
@ -197,6 +199,8 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
};
|
||||
|
||||
const handlePriorityChange = (data: TIssuePriorities) => {
|
||||
if (!user) return;
|
||||
|
||||
partialUpdateIssue({ priority: data }, issue);
|
||||
trackEventServices.trackIssuePartialPropertyUpdateEvent(
|
||||
{
|
||||
@ -213,6 +217,8 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
};
|
||||
|
||||
const handleAssigneeChange = (data: any) => {
|
||||
if (!user) return;
|
||||
|
||||
const newData = issue.assignees ?? [];
|
||||
|
||||
if (newData.includes(data)) newData.splice(newData.indexOf(data), 1);
|
||||
|
@ -6,7 +6,7 @@ import { observer } from "mobx-react-lite";
|
||||
import useLocalStorage from "hooks/use-local-storage";
|
||||
// components
|
||||
import {
|
||||
ListInlineCreateIssueForm,
|
||||
// ListInlineCreateIssueForm,
|
||||
SpreadsheetAssigneeColumn,
|
||||
SpreadsheetCreatedOnColumn,
|
||||
SpreadsheetDueDateColumn,
|
||||
@ -19,7 +19,6 @@ import {
|
||||
SpreadsheetUpdatedOnColumn,
|
||||
} from "components/core";
|
||||
import { CustomMenu, Icon } from "components/ui";
|
||||
import { IssuePeekOverview } from "components/issues";
|
||||
import { Spinner } from "@plane/ui";
|
||||
// types
|
||||
import { IIssue, IIssueDisplayFilterOptions, IIssueDisplayProperties, TIssueOrderByOptions } from "types";
|
||||
@ -32,7 +31,7 @@ type Props = {
|
||||
handleDisplayFilterUpdate: (data: Partial<IIssueDisplayFilterOptions>) => void;
|
||||
issues: IIssue[] | undefined;
|
||||
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
|
||||
handleUpdateIssue: (issueId: string, data: Partial<IIssue>) => void;
|
||||
handleUpdateIssue: (issue: IIssue, data: Partial<IIssue>) => void;
|
||||
openIssuesListModal?: (() => void) | null;
|
||||
disableUserActions: boolean;
|
||||
};
|
||||
@ -50,7 +49,6 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
} = props;
|
||||
|
||||
const [expandedIssues, setExpandedIssues] = useState<string[]>([]);
|
||||
const [currentProjectId, setCurrentProjectId] = useState<string | null>(null);
|
||||
|
||||
const [isInlineCreateIssueFormOpen, setIsInlineCreateIssueFormOpen] = useState(false);
|
||||
|
||||
@ -59,7 +57,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, cycleId, moduleId } = router.query;
|
||||
const { cycleId, moduleId } = router.query;
|
||||
|
||||
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
||||
|
||||
@ -266,10 +264,10 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
);
|
||||
|
||||
const handleScroll = () => {
|
||||
if (containerRef.current) {
|
||||
const scrollLeft = containerRef.current.scrollLeft;
|
||||
setIsScrolled(scrollLeft > 0);
|
||||
}
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const scrollLeft = containerRef.current.scrollLeft;
|
||||
setIsScrolled(scrollLeft > 0);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -288,11 +286,6 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<IssuePeekOverview
|
||||
projectId={currentProjectId ?? ""}
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
readOnly={disableUserActions}
|
||||
/>
|
||||
<div className="relative flex h-full w-full rounded-lg text-custom-text-200 overflow-x-auto whitespace-nowrap bg-custom-background-200">
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<div ref={containerRef} className="flex max-h-full h-full overflow-y-auto">
|
||||
@ -302,7 +295,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
<div
|
||||
className="relative flex flex-col h-max w-full bg-custom-background-100 z-[2]"
|
||||
style={{
|
||||
boxShadow: isScrolled ? "8px -9px 12px rgba(0, 0, 0, 0.15)" : "",
|
||||
boxShadow: isScrolled ? "4px -9px 12px rgba(0, 0, 0, 0.1)" : "",
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center text-sm font-medium z-[2] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-100">
|
||||
@ -312,14 +305,13 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
<span className="flex items-center px-4 py-2.5 h-full w-full flex-grow">Issue</span>
|
||||
</div>
|
||||
|
||||
{issues.map((issue: IIssue, index) => (
|
||||
{issues.map((issue, index) => (
|
||||
<SpreadsheetIssuesColumn
|
||||
key={`${issue.id}_${index}`}
|
||||
issue={issue}
|
||||
projectId={issue.project_detail.id}
|
||||
expandedIssues={expandedIssues}
|
||||
setExpandedIssues={setExpandedIssues}
|
||||
setCurrentProjectId={setCurrentProjectId}
|
||||
properties={displayProperties}
|
||||
handleIssueAction={handleIssueAction}
|
||||
disableUserActions={disableUserActions}
|
||||
@ -361,7 +353,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
</div>
|
||||
|
||||
<div className="border-t border-custom-border-100">
|
||||
<div className="mb-3 z-50 sticky bottom-0 left-0">
|
||||
{/* <div className="mb-3 z-50 sticky bottom-0 left-0">
|
||||
<ListInlineCreateIssueForm
|
||||
isOpen={isInlineCreateIssueFormOpen}
|
||||
handleClose={() => setIsInlineCreateIssueFormOpen(false)}
|
||||
@ -370,7 +362,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
...(moduleId && { module: moduleId.toString() }),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
{type === "issue"
|
||||
? !disableUserActions &&
|
||||
|
@ -1,5 +1,5 @@
|
||||
export * from "./blocks";
|
||||
export * from "./cycle-root";
|
||||
export * from "./module-root";
|
||||
export * from "./project-root";
|
||||
export * from "./project-view-root";
|
||||
export * from "./root";
|
||||
|
@ -11,7 +11,7 @@ import { IssueGanttBlock, IssueGanttSidebarBlock, IssuePeekOverview } from "comp
|
||||
// types
|
||||
import { IIssueUnGroupedStructure } from "store/issue";
|
||||
|
||||
export const GanttLayout: React.FC = observer(() => {
|
||||
export const ProjectGanttLayout: React.FC = observer(() => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
@ -11,6 +11,8 @@ import { observer } from "mobx-react-lite";
|
||||
// mobx
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { RootStore } from "store/root";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
|
||||
export interface IGroupByKanBan {
|
||||
issues: any;
|
||||
@ -20,7 +22,7 @@ export interface IGroupByKanBan {
|
||||
list: any;
|
||||
listKey: string;
|
||||
isDragDisabled: boolean;
|
||||
handleIssues?: (sub_group_by: string | null, group_by: string | null, issue: any) => void;
|
||||
handleIssues?: (sub_group_by: string | null, group_by: string | null, issue: IIssue) => void;
|
||||
display_properties: any;
|
||||
kanBanToggle: any;
|
||||
handleKanBanToggle: any;
|
||||
|
@ -9,10 +9,10 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import {
|
||||
ListLayout,
|
||||
CalendarLayout,
|
||||
GanttLayout,
|
||||
ProjectGanttLayout,
|
||||
KanBanLayout,
|
||||
ProjectAppliedFiltersRoot,
|
||||
SpreadsheetLayout,
|
||||
ProjectSpreadsheetLayout,
|
||||
} from "components/issues";
|
||||
|
||||
export const ProjectLayoutRoot: React.FC = observer(() => {
|
||||
@ -26,6 +26,7 @@ export const ProjectLayoutRoot: React.FC = observer(() => {
|
||||
|
||||
const { issue: issueStore, project: projectStore, issueFilter: issueFilterStore } = useMobxStore();
|
||||
|
||||
// TODO: remove fetch logic from here
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? `PROJECT_ISSUES` : null,
|
||||
async () => {
|
||||
@ -56,9 +57,9 @@ export const ProjectLayoutRoot: React.FC = observer(() => {
|
||||
) : activeLayout === "calendar" ? (
|
||||
<CalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<GanttLayout />
|
||||
<ProjectGanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<SpreadsheetLayout />
|
||||
<ProjectSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from "./cycle-root";
|
||||
export * from "./module-root";
|
||||
export * from "./project-root";
|
||||
export * from "./project-view-root";
|
||||
export * from "./root";
|
||||
|
@ -0,0 +1,62 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// hooks
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
// components
|
||||
import { SpreadsheetView } from "components/core";
|
||||
import { IssuePeekOverview } from "components/issues";
|
||||
// types
|
||||
import { IIssue, IIssueDisplayFilterOptions } from "types";
|
||||
|
||||
export const ProjectSpreadsheetLayout: React.FC = observer(() => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const { projectDetails } = useProjectDetails();
|
||||
|
||||
const { issue: issueStore, issueFilter: issueFilterStore } = useMobxStore();
|
||||
|
||||
const issues = issueStore.getIssues;
|
||||
|
||||
const handleDisplayFiltersUpdate = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
|
||||
display_filters: {
|
||||
...updatedDisplayFilter,
|
||||
},
|
||||
});
|
||||
},
|
||||
[issueFilterStore, projectId, workspaceSlug]
|
||||
);
|
||||
|
||||
const updateIssue = (group_by: string | null, sub_group_by: string | null, issue: IIssue) => {
|
||||
issueStore.updateIssueStructure(group_by, sub_group_by, issue);
|
||||
};
|
||||
|
||||
const isAllowed = projectDetails?.member_role === 20 || projectDetails?.member_role === 15;
|
||||
|
||||
return (
|
||||
<>
|
||||
<IssuePeekOverview
|
||||
projectId={projectId?.toString() ?? ""}
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
readOnly={!isAllowed}
|
||||
/>
|
||||
<SpreadsheetView
|
||||
displayProperties={issueFilterStore.userDisplayProperties}
|
||||
displayFilters={issueFilterStore.userDisplayFilters}
|
||||
handleDisplayFilterUpdate={handleDisplayFiltersUpdate}
|
||||
issues={issues as IIssue[]}
|
||||
handleIssueAction={() => {}}
|
||||
handleUpdateIssue={() => {}}
|
||||
disableUserActions={false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
@ -1,161 +0,0 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// hooks
|
||||
import useUser from "hooks/use-user";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
// components
|
||||
import { SpreadsheetColumns, SpreadsheetIssues } from "components/core";
|
||||
import { IssuePeekOverview } from "components/issues";
|
||||
// ui
|
||||
import { CustomMenu } from "components/ui";
|
||||
import { Spinner } from "@plane/ui";
|
||||
// icon
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import { IIssue, IIssueDisplayFilterOptions, IIssueDisplayProperties } from "types";
|
||||
import { IIssueUnGroupedStructure } from "store/issue";
|
||||
// constants
|
||||
import { SPREADSHEET_COLUMN } from "constants/spreadsheet";
|
||||
|
||||
export const SpreadsheetLayout: React.FC = observer(() => {
|
||||
const [expandedIssues, setExpandedIssues] = useState<string[]>([]);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||
|
||||
const { user } = useUser();
|
||||
const { projectDetails } = useProjectDetails();
|
||||
|
||||
const { issue: issueStore, issueFilter: issueFilterStore } = useMobxStore();
|
||||
|
||||
const issues = issueStore.getIssues;
|
||||
const issueDisplayProperties = issueFilterStore.userDisplayProperties;
|
||||
|
||||
const handleDisplayFiltersUpdate = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
|
||||
display_filters: {
|
||||
...updatedDisplayFilter,
|
||||
},
|
||||
});
|
||||
},
|
||||
[issueFilterStore, projectId, workspaceSlug]
|
||||
);
|
||||
|
||||
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
||||
|
||||
const columnData = SPREADSHEET_COLUMN.map((column) => ({
|
||||
...column,
|
||||
isActive: issueDisplayProperties
|
||||
? column.propertyName === "labels"
|
||||
? issueDisplayProperties[column.propertyName as keyof IIssueDisplayProperties]
|
||||
: column.propertyName === "title"
|
||||
? true
|
||||
: issueDisplayProperties[column.propertyName as keyof IIssueDisplayProperties]
|
||||
: false,
|
||||
}));
|
||||
|
||||
const gridTemplateColumns = columnData
|
||||
.filter((column) => column.isActive)
|
||||
.map((column) => column.colSize)
|
||||
.join(" ");
|
||||
|
||||
const isAllowed = projectDetails?.member_role === 20 || projectDetails?.member_role === 15;
|
||||
|
||||
return (
|
||||
<>
|
||||
<IssuePeekOverview
|
||||
projectId={projectId?.toString() ?? ""}
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
readOnly={!isAllowed}
|
||||
/>
|
||||
<div className="h-full rounded-lg text-custom-text-200 overflow-x-auto whitespace-nowrap bg-custom-background-100">
|
||||
<div className="sticky z-[2] top-0 border-b border-custom-border-200 bg-custom-background-90 w-full min-w-max">
|
||||
<SpreadsheetColumns
|
||||
columnData={columnData}
|
||||
displayFilters={issueFilterStore.userDisplayFilters}
|
||||
gridTemplateColumns={gridTemplateColumns}
|
||||
handleDisplayFiltersUpdate={handleDisplayFiltersUpdate}
|
||||
/>
|
||||
</div>
|
||||
{issues ? (
|
||||
<div className="flex flex-col h-full w-full bg-custom-background-100 rounded-sm ">
|
||||
{(issues as IIssueUnGroupedStructure).map((issue: IIssue, index) => (
|
||||
<SpreadsheetIssues
|
||||
key={`${issue.id}_${index}`}
|
||||
index={index}
|
||||
issue={issue}
|
||||
expandedIssues={expandedIssues}
|
||||
setExpandedIssues={setExpandedIssues}
|
||||
gridTemplateColumns={gridTemplateColumns}
|
||||
properties={issueDisplayProperties}
|
||||
handleIssueAction={() => {}}
|
||||
disableUserActions={!isAllowed}
|
||||
user={user}
|
||||
userAuth={{
|
||||
isViewer: projectDetails?.member_role === 5,
|
||||
isGuest: projectDetails?.member_role === 10,
|
||||
isMember: projectDetails?.member_role === 15,
|
||||
isOwner: projectDetails?.member_role === 20,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<div
|
||||
className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-custom-background-80 border-b border-custom-border-200 w-full min-w-max"
|
||||
style={{ gridTemplateColumns }}
|
||||
>
|
||||
{type === "issue" ? (
|
||||
<button
|
||||
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-custom-text-200 bg-custom-background-100 group-hover:text-custom-text-100 group-hover:bg-custom-background-80 border-custom-border-200 w-full"
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", { key: "c" });
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
Add Issue
|
||||
</button>
|
||||
) : (
|
||||
isAllowed && (
|
||||
<CustomMenu
|
||||
className="sticky left-0 z-[1]"
|
||||
customButton={
|
||||
<button
|
||||
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-custom-text-200 bg-custom-background-100 group-hover:text-custom-text-100 group-hover:bg-custom-background-80 border-custom-border-200 w-full"
|
||||
type="button"
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
Add Issue
|
||||
</button>
|
||||
}
|
||||
position="left"
|
||||
optionsClassName="left-5 !w-36"
|
||||
noBorder
|
||||
>
|
||||
<CustomMenu.MenuItem
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", { key: "c" });
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
>
|
||||
Create new
|
||||
</CustomMenu.MenuItem>
|
||||
{true && <CustomMenu.MenuItem onClick={() => {}}>Add an existing issue</CustomMenu.MenuItem>}
|
||||
</CustomMenu>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<Spinner />
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
@ -99,13 +99,13 @@ class IssueStore implements IIssueStore {
|
||||
return this.issues?.[projectId]?.[issueType] || null;
|
||||
}
|
||||
|
||||
// TODO: params order is different from what is present in components
|
||||
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
||||
const projectId: string | null = issue?.project;
|
||||
const issueType = this.getIssueType;
|
||||
if (!projectId || !issueType) return null;
|
||||
|
||||
let issues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null =
|
||||
this.getIssues;
|
||||
let issues = this.getIssues;
|
||||
if (!issues) return null;
|
||||
|
||||
if (issueType === "grouped" && group_id) {
|
||||
|
Loading…
Reference in New Issue
Block a user