forked from github/plane
chore: updated display properties endpoint (#2486)
This commit is contained in:
parent
3a44d4bf35
commit
861ff4ae94
@ -2,4 +2,3 @@ export * from "./date-filter-modal";
|
|||||||
export * from "./date-filter-select";
|
export * from "./date-filter-select";
|
||||||
export * from "./filters-list";
|
export * from "./filters-list";
|
||||||
export * from "./workspace-filters-list";
|
export * from "./workspace-filters-list";
|
||||||
export * from "./issues-view-filter";
|
|
||||||
|
@ -1,361 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
|
|
||||||
// headless ui
|
|
||||||
import { Popover, Transition } from "@headlessui/react";
|
|
||||||
// hooks
|
|
||||||
import useIssuesProperties from "hooks/use-issue-properties";
|
|
||||||
import useIssuesView from "hooks/use-issues-view";
|
|
||||||
import useEstimateOption from "hooks/use-estimate-option";
|
|
||||||
// components
|
|
||||||
import { SelectFilters } from "components/views";
|
|
||||||
// ui
|
|
||||||
import { CustomMenu } from "components/ui";
|
|
||||||
import { ToggleSwitch, Tooltip } from "@plane/ui";
|
|
||||||
// icons
|
|
||||||
import { CalendarDays, ChevronDown, GanttChart, Kanban, List, Sheet } from "lucide-react";
|
|
||||||
// helpers
|
|
||||||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
|
||||||
import { checkIfArraysHaveSameElements } from "helpers/array.helper";
|
|
||||||
// types
|
|
||||||
import { Properties, TIssueLayouts } from "types";
|
|
||||||
// constants
|
|
||||||
import { ISSUE_GROUP_BY_OPTIONS, ISSUE_ORDER_BY_OPTIONS, ISSUE_FILTER_OPTIONS } from "constants/issue";
|
|
||||||
|
|
||||||
const issueViewOptions: { type: TIssueLayouts; Icon: any }[] = [
|
|
||||||
{
|
|
||||||
type: "list",
|
|
||||||
Icon: List,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "kanban",
|
|
||||||
Icon: Kanban,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "calendar",
|
|
||||||
Icon: CalendarDays,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "spreadsheet",
|
|
||||||
Icon: Sheet,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "gantt_chart",
|
|
||||||
Icon: GanttChart,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const issueViewForDraftIssues: { type: TIssueLayouts; Icon: any }[] = [
|
|
||||||
{
|
|
||||||
type: "list",
|
|
||||||
Icon: List,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "kanban",
|
|
||||||
Icon: Kanban,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const IssuesFilterView: React.FC = () => {
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, projectId, viewId } = router.query;
|
|
||||||
const isArchivedIssues = router.pathname.includes("archived-issues");
|
|
||||||
const isDraftIssues = router.pathname?.split("/")?.[4] === "draft-issues";
|
|
||||||
|
|
||||||
const { displayFilters, setDisplayFilters, filters, setFilters, resetFilterToDefault, setNewFilterDefaultView } =
|
|
||||||
useIssuesView();
|
|
||||||
|
|
||||||
const [properties, setProperties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
|
||||||
|
|
||||||
const { isEstimateActive } = useEstimateOption();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
{!isArchivedIssues && !isDraftIssues && (
|
|
||||||
<div className="flex items-center gap-x-1">
|
|
||||||
{issueViewOptions.map((option) => (
|
|
||||||
<Tooltip
|
|
||||||
key={option.type}
|
|
||||||
tooltipContent={<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} Layout</span>}
|
|
||||||
position="bottom"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
|
||||||
displayFilters.layout === option.type
|
|
||||||
? "bg-custom-sidebar-background-80"
|
|
||||||
: "text-custom-sidebar-text-200"
|
|
||||||
}`}
|
|
||||||
onClick={() => setDisplayFilters({ layout: option.type })}
|
|
||||||
>
|
|
||||||
<option.Icon className="h-4 w-4" />
|
|
||||||
</button>
|
|
||||||
</Tooltip>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{isDraftIssues && (
|
|
||||||
<div className="flex items-center gap-x-1">
|
|
||||||
{issueViewForDraftIssues.map((option) => (
|
|
||||||
<Tooltip
|
|
||||||
key={option.type}
|
|
||||||
tooltipContent={<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} View</span>}
|
|
||||||
position="bottom"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
|
||||||
displayFilters.layout === option.type
|
|
||||||
? "bg-custom-sidebar-background-80"
|
|
||||||
: "text-custom-sidebar-text-200"
|
|
||||||
}`}
|
|
||||||
onClick={() => setDisplayFilters({ layout: option.type })}
|
|
||||||
>
|
|
||||||
<option.Icon
|
|
||||||
sx={{
|
|
||||||
fontSize: 16,
|
|
||||||
}}
|
|
||||||
className={option.type === "gantt_chart" ? "rotate-90" : ""}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</Tooltip>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<SelectFilters
|
|
||||||
filters={filters}
|
|
||||||
onSelect={(option) => {
|
|
||||||
const key = option.key as keyof typeof filters;
|
|
||||||
|
|
||||||
if (key === "start_date" || key === "target_date") {
|
|
||||||
const valueExists = checkIfArraysHaveSameElements(filters[key] ?? [], option.value);
|
|
||||||
|
|
||||||
setFilters({
|
|
||||||
[key]: valueExists ? null : option.value,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const valueExists = filters[key]?.includes(option.value);
|
|
||||||
|
|
||||||
if (valueExists)
|
|
||||||
setFilters(
|
|
||||||
{
|
|
||||||
[option.key]: ((filters[key] ?? []) as any[])?.filter((val) => val !== option.value),
|
|
||||||
},
|
|
||||||
!Boolean(viewId)
|
|
||||||
);
|
|
||||||
else
|
|
||||||
setFilters(
|
|
||||||
{
|
|
||||||
[option.key]: [...((filters[key] ?? []) as any[]), option.value],
|
|
||||||
},
|
|
||||||
!Boolean(viewId)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
direction="left"
|
|
||||||
height="rg"
|
|
||||||
/>
|
|
||||||
<Popover className="relative">
|
|
||||||
{({ open }) => (
|
|
||||||
<>
|
|
||||||
<Popover.Button
|
|
||||||
className={`group flex items-center gap-2 rounded-md border border-custom-border-200 px-3 py-1.5 text-xs hover:bg-custom-sidebar-background-90 hover:text-custom-sidebar-text-100 focus:outline-none duration-300 ${
|
|
||||||
open ? "bg-custom-sidebar-background-90 text-custom-sidebar-text-100" : "text-custom-sidebar-text-200"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
Display
|
|
||||||
<ChevronDown className="h-3 w-3" />
|
|
||||||
</Popover.Button>
|
|
||||||
|
|
||||||
<Transition
|
|
||||||
as={React.Fragment}
|
|
||||||
enter="transition ease-out duration-200"
|
|
||||||
enterFrom="opacity-0 translate-y-1"
|
|
||||||
enterTo="opacity-100 translate-y-0"
|
|
||||||
leave="transition ease-in duration-150"
|
|
||||||
leaveFrom="opacity-100 translate-y-0"
|
|
||||||
leaveTo="opacity-0 translate-y-1"
|
|
||||||
>
|
|
||||||
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
|
||||||
<div className="relative divide-y-2 divide-custom-border-200">
|
|
||||||
<div className="space-y-4 pb-3 text-xs">
|
|
||||||
{displayFilters.layout !== "calendar" &&
|
|
||||||
displayFilters.layout !== "spreadsheet" &&
|
|
||||||
displayFilters.layout !== "gantt_chart" && (
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h4 className="text-custom-text-200">Group by</h4>
|
|
||||||
<div className="w-28">
|
|
||||||
<CustomMenu
|
|
||||||
label={
|
|
||||||
ISSUE_GROUP_BY_OPTIONS.find((option) => option.key === displayFilters.group_by)
|
|
||||||
?.title ?? "Select"
|
|
||||||
}
|
|
||||||
className="!w-full"
|
|
||||||
buttonClassName="w-full"
|
|
||||||
>
|
|
||||||
{ISSUE_GROUP_BY_OPTIONS.map((option) => {
|
|
||||||
if (displayFilters.layout === "kanban" && option.key === null) return null;
|
|
||||||
if (option.key === "project") return null;
|
|
||||||
|
|
||||||
if (isDraftIssues && option.key === "state_detail.group") return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CustomMenu.MenuItem
|
|
||||||
key={option.key}
|
|
||||||
onClick={() => setDisplayFilters({ group_by: option.key })}
|
|
||||||
>
|
|
||||||
{option.title}
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</CustomMenu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{displayFilters.layout !== "calendar" && displayFilters.layout !== "spreadsheet" && (
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h4 className="text-custom-text-200">Order by</h4>
|
|
||||||
<div className="w-28">
|
|
||||||
<CustomMenu
|
|
||||||
label={
|
|
||||||
ISSUE_ORDER_BY_OPTIONS.find((option) => option.key === displayFilters.order_by)?.title ??
|
|
||||||
"Select"
|
|
||||||
}
|
|
||||||
className="!w-full"
|
|
||||||
buttonClassName="w-full"
|
|
||||||
>
|
|
||||||
{ISSUE_ORDER_BY_OPTIONS.map((option) =>
|
|
||||||
displayFilters.group_by === "priority" && option.key === "priority" ? null : (
|
|
||||||
<CustomMenu.MenuItem
|
|
||||||
key={option.key}
|
|
||||||
onClick={() => {
|
|
||||||
setDisplayFilters({ order_by: option.key });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{option.title}
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</CustomMenu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!isArchivedIssues && (
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h4 className="text-custom-text-200">Issue type</h4>
|
|
||||||
<div className="w-28">
|
|
||||||
<CustomMenu
|
|
||||||
label={
|
|
||||||
ISSUE_FILTER_OPTIONS.find((option) => option.key === displayFilters.type)?.title ??
|
|
||||||
"Select"
|
|
||||||
}
|
|
||||||
className="!w-full"
|
|
||||||
buttonClassName="w-full"
|
|
||||||
>
|
|
||||||
{ISSUE_FILTER_OPTIONS.map((option) => (
|
|
||||||
<CustomMenu.MenuItem
|
|
||||||
key={option.key}
|
|
||||||
onClick={() =>
|
|
||||||
setDisplayFilters({
|
|
||||||
type: option.key,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{option.title}
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
))}
|
|
||||||
</CustomMenu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{displayFilters.layout !== "calendar" && displayFilters.layout !== "spreadsheet" && (
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h4 className="text-custom-text-200">Show sub-issues</h4>
|
|
||||||
<div className="w-28">
|
|
||||||
<ToggleSwitch
|
|
||||||
value={displayFilters.sub_issue ?? true}
|
|
||||||
onChange={() => setDisplayFilters({ sub_issue: !displayFilters.sub_issue })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{displayFilters.layout !== "calendar" &&
|
|
||||||
displayFilters.layout !== "spreadsheet" &&
|
|
||||||
displayFilters.layout !== "gantt_chart" && (
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h4 className="text-custom-text-200">Show empty groups</h4>
|
|
||||||
<div className="w-28">
|
|
||||||
<ToggleSwitch
|
|
||||||
value={displayFilters.show_empty_groups ?? true}
|
|
||||||
onChange={() =>
|
|
||||||
setDisplayFilters({
|
|
||||||
show_empty_groups: !displayFilters.show_empty_groups,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{displayFilters.layout !== "calendar" &&
|
|
||||||
displayFilters.layout !== "spreadsheet" &&
|
|
||||||
displayFilters.layout !== "gantt_chart" && (
|
|
||||||
<div className="relative flex justify-end gap-x-3">
|
|
||||||
<button type="button" onClick={() => resetFilterToDefault()}>
|
|
||||||
Reset to default
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="font-medium text-custom-primary"
|
|
||||||
onClick={() => setNewFilterDefaultView()}
|
|
||||||
>
|
|
||||||
Set as default
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{displayFilters.layout !== "gantt_chart" && (
|
|
||||||
<div className="space-y-2 py-3">
|
|
||||||
<h4 className="text-sm text-custom-text-200">Display Properties</h4>
|
|
||||||
<div className="flex flex-wrap items-center gap-2 text-custom-text-200">
|
|
||||||
{Object.keys(properties).map((key) => {
|
|
||||||
if (key === "estimate" && !isEstimateActive) return null;
|
|
||||||
|
|
||||||
if (
|
|
||||||
displayFilters.layout === "spreadsheet" &&
|
|
||||||
(key === "attachment_count" || key === "link" || key === "sub_issue_count")
|
|
||||||
)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (displayFilters.layout !== "spreadsheet" && (key === "created_on" || key === "updated_on"))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={key}
|
|
||||||
type="button"
|
|
||||||
className={`rounded border px-2 py-1 text-xs capitalize ${
|
|
||||||
properties[key as keyof Properties]
|
|
||||||
? "border-custom-primary bg-custom-primary text-white"
|
|
||||||
: "border-custom-border-200"
|
|
||||||
}`}
|
|
||||||
onClick={() => setProperties(key as keyof Properties)}
|
|
||||||
>
|
|
||||||
{key === "key" ? "ID" : replaceUnderscoreIfSnakeCase(key)}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Popover.Panel>
|
|
||||||
</Transition>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Popover>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,220 +0,0 @@
|
|||||||
// import React, { useCallback, useState } from "react";
|
|
||||||
// import { useRouter } from "next/router";
|
|
||||||
// import useSWR from "swr";
|
|
||||||
// import { DragDropContext, DropResult } from "react-beautiful-dnd";
|
|
||||||
// // services
|
|
||||||
// import { ProjectStateService } from "services/project";
|
|
||||||
// // hooks
|
|
||||||
// import useUser from "hooks/use-user";
|
|
||||||
// import { useProjectMyMembership } from "contexts/project-member.context";
|
|
||||||
// import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view";
|
|
||||||
// // components
|
|
||||||
// import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
|
||||||
// import { AllLists, AllBoards, CalendarView, SpreadsheetView, GanttChartView } from "components/core";
|
|
||||||
// import { EmptyState } from "components/common";
|
|
||||||
// // ui
|
|
||||||
// import { Spinner } from "components/ui";
|
|
||||||
// // icons
|
|
||||||
// import { TrashIcon } from "@heroicons/react/24/outline";
|
|
||||||
// // images
|
|
||||||
// import emptyIssue from "public/empty-state/issue.svg";
|
|
||||||
// import emptyIssueArchive from "public/empty-state/issue-archive.svg";
|
|
||||||
// // helpers
|
|
||||||
// import { getStatesList } from "helpers/state.helper";
|
|
||||||
// // types
|
|
||||||
// import { IIssue, IIssueViewProps } from "types";
|
|
||||||
// // fetch-keys
|
|
||||||
// import { STATES_LIST } from "constants/fetch-keys";
|
|
||||||
|
|
||||||
// type Props = {
|
|
||||||
// addIssueToDate: (date: string) => void;
|
|
||||||
// addIssueToGroup: (groupTitle: string) => void;
|
|
||||||
// disableUserActions: boolean;
|
|
||||||
// dragDisabled?: boolean;
|
|
||||||
// emptyState: {
|
|
||||||
// title: string;
|
|
||||||
// description?: string;
|
|
||||||
// primaryButton?: {
|
|
||||||
// icon: any;
|
|
||||||
// text: string;
|
|
||||||
// onClick: () => void;
|
|
||||||
// };
|
|
||||||
// secondaryButton?: React.ReactNode;
|
|
||||||
// };
|
|
||||||
// handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
|
|
||||||
// handleDraftIssueAction?: (issue: IIssue, action: "edit" | "delete") => void;
|
|
||||||
// handleOnDragEnd: (result: DropResult) => Promise<void>;
|
|
||||||
// openIssuesListModal: (() => void) | null;
|
|
||||||
// removeIssue: ((bridgeId: string, issueId: string) => void) | null;
|
|
||||||
// disableAddIssueOption?: boolean;
|
|
||||||
// trashBox: boolean;
|
|
||||||
// setTrashBox: React.Dispatch<React.SetStateAction<boolean>>;
|
|
||||||
// viewProps: IIssueViewProps;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const projectStateService = new ProjectStateService();
|
|
||||||
|
|
||||||
// export const AllViews: React.FC<Props> = ({
|
|
||||||
// addIssueToDate,
|
|
||||||
// addIssueToGroup,
|
|
||||||
// disableUserActions,
|
|
||||||
// dragDisabled = false,
|
|
||||||
// emptyState,
|
|
||||||
// handleIssueAction,
|
|
||||||
// handleDraftIssueAction,
|
|
||||||
// handleOnDragEnd,
|
|
||||||
// openIssuesListModal,
|
|
||||||
// removeIssue,
|
|
||||||
// disableAddIssueOption = false,
|
|
||||||
// trashBox,
|
|
||||||
// setTrashBox,
|
|
||||||
// viewProps,
|
|
||||||
// }) => {
|
|
||||||
// const router = useRouter();
|
|
||||||
// const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
|
||||||
|
|
||||||
// const [myIssueProjectId, setMyIssueProjectId] = useState<string | null>(null);
|
|
||||||
|
|
||||||
// const { user } = useUser();
|
|
||||||
// const { memberRole } = useProjectMyMembership();
|
|
||||||
|
|
||||||
// const { groupedIssues, isEmpty, displayFilters } = viewProps;
|
|
||||||
|
|
||||||
// const { spreadsheetIssues, mutateIssues } = useSpreadsheetIssuesView();
|
|
||||||
|
|
||||||
// const { data: stateGroups } = useSWR(
|
|
||||||
// workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
|
||||||
// workspaceSlug ? () => projectStateService.getStates(workspaceSlug as string, projectId as string) : null
|
|
||||||
// );
|
|
||||||
// const states = getStatesList(stateGroups);
|
|
||||||
|
|
||||||
// const handleMyIssueOpen = (issue: IIssue) => {
|
|
||||||
// setMyIssueProjectId(issue.project);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const handleTrashBox = useCallback(
|
|
||||||
// (isDragging: boolean) => {
|
|
||||||
// if (isDragging && !trashBox) setTrashBox(true);
|
|
||||||
// },
|
|
||||||
// [trashBox, setTrashBox]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <DragDropContext onDragEnd={handleOnDragEnd}>
|
|
||||||
// <StrictModeDroppable droppableId="trashBox">
|
|
||||||
// {(provided, snapshot) => (
|
|
||||||
// <div
|
|
||||||
// className={`${
|
|
||||||
// trashBox ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
|
|
||||||
// } fixed top-4 left-1/2 -translate-x-1/2 z-40 w-72 flex items-center justify-center gap-2 rounded border-2 border-red-500/20 bg-custom-background-100 px-3 py-5 text-xs font-medium italic text-red-500 ${
|
|
||||||
// snapshot.isDraggingOver ? "bg-red-500 blur-2xl opacity-70" : ""
|
|
||||||
// } transition duration-300`}
|
|
||||||
// ref={provided.innerRef}
|
|
||||||
// {...provided.droppableProps}
|
|
||||||
// >
|
|
||||||
// <TrashIcon className="h-4 w-4" />
|
|
||||||
// Drop here to delete the issue.
|
|
||||||
// </div>
|
|
||||||
// )}
|
|
||||||
// </StrictModeDroppable>
|
|
||||||
// {groupedIssues ? (
|
|
||||||
// !isEmpty ||
|
|
||||||
// displayFilters?.layout === "kanban" ||
|
|
||||||
// displayFilters?.layout === "calendar" ||
|
|
||||||
// displayFilters?.layout === "gantt_chart" ? (
|
|
||||||
// <>
|
|
||||||
// {displayFilters?.layout === "list" ? (
|
|
||||||
// <AllLists
|
|
||||||
// states={states}
|
|
||||||
// addIssueToGroup={addIssueToGroup}
|
|
||||||
// handleIssueAction={handleIssueAction}
|
|
||||||
// handleDraftIssueAction={handleDraftIssueAction}
|
|
||||||
// openIssuesListModal={cycleId || moduleId ? openIssuesListModal : null}
|
|
||||||
// removeIssue={removeIssue}
|
|
||||||
// myIssueProjectId={myIssueProjectId}
|
|
||||||
// handleMyIssueOpen={handleMyIssueOpen}
|
|
||||||
// disableUserActions={disableUserActions}
|
|
||||||
// disableAddIssueOption={disableAddIssueOption}
|
|
||||||
// user={user}
|
|
||||||
// userAuth={memberRole}
|
|
||||||
// viewProps={viewProps}
|
|
||||||
// />
|
|
||||||
// ) : displayFilters?.layout === "kanban" ? (
|
|
||||||
// <AllBoards
|
|
||||||
// addIssueToGroup={addIssueToGroup}
|
|
||||||
// disableUserActions={disableUserActions}
|
|
||||||
// disableAddIssueOption={disableAddIssueOption}
|
|
||||||
// dragDisabled={dragDisabled}
|
|
||||||
// handleIssueAction={handleIssueAction}
|
|
||||||
// handleDraftIssueAction={handleDraftIssueAction}
|
|
||||||
// handleTrashBox={handleTrashBox}
|
|
||||||
// openIssuesListModal={cycleId || moduleId ? openIssuesListModal : null}
|
|
||||||
// myIssueProjectId={myIssueProjectId}
|
|
||||||
// handleMyIssueOpen={handleMyIssueOpen}
|
|
||||||
// removeIssue={removeIssue}
|
|
||||||
// states={states}
|
|
||||||
// user={user}
|
|
||||||
// userAuth={memberRole}
|
|
||||||
// viewProps={viewProps}
|
|
||||||
// />
|
|
||||||
// ) : displayFilters?.layout === "calendar" ? (
|
|
||||||
// <CalendarView
|
|
||||||
// handleIssueAction={handleIssueAction}
|
|
||||||
// addIssueToDate={addIssueToDate}
|
|
||||||
// disableUserActions={disableUserActions}
|
|
||||||
// user={user}
|
|
||||||
// userAuth={memberRole}
|
|
||||||
// />
|
|
||||||
// ) : displayFilters?.layout === "spreadsheet" ? (
|
|
||||||
// <SpreadsheetView
|
|
||||||
// handleIssueAction={handleIssueAction}
|
|
||||||
// spreadsheetIssues={spreadsheetIssues}
|
|
||||||
// mutateIssues={mutateIssues}
|
|
||||||
// openIssuesListModal={cycleId || moduleId ? openIssuesListModal : null}
|
|
||||||
// disableUserActions={disableUserActions}
|
|
||||||
// user={user}
|
|
||||||
// userAuth={memberRole}
|
|
||||||
// />
|
|
||||||
// ) : (
|
|
||||||
// displayFilters?.layout === "gantt_chart" && <GanttChartView disableUserActions={disableUserActions} />
|
|
||||||
// )}
|
|
||||||
// </>
|
|
||||||
// ) : router.pathname.includes("archived-issues") ? (
|
|
||||||
// <EmptyState
|
|
||||||
// title="Archived Issues will be shown here"
|
|
||||||
// description="All the issues that have been in the completed or canceled groups for the configured period of time can be viewed here."
|
|
||||||
// image={emptyIssueArchive}
|
|
||||||
// primaryButton={{
|
|
||||||
// text: "Go to Automation Settings",
|
|
||||||
// onClick: () => {
|
|
||||||
// router.push(`/${workspaceSlug}/projects/${projectId}/settings/automations`);
|
|
||||||
// },
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// ) : (
|
|
||||||
// <EmptyState
|
|
||||||
// title={emptyState.title}
|
|
||||||
// description={emptyState.description}
|
|
||||||
// image={emptyIssue}
|
|
||||||
// primaryButton={
|
|
||||||
// emptyState.primaryButton
|
|
||||||
// ? {
|
|
||||||
// icon: emptyState.primaryButton.icon,
|
|
||||||
// text: emptyState.primaryButton.text,
|
|
||||||
// onClick: emptyState.primaryButton.onClick,
|
|
||||||
// }
|
|
||||||
// : undefined
|
|
||||||
// }
|
|
||||||
// secondaryButton={emptyState.secondaryButton}
|
|
||||||
// />
|
|
||||||
// )
|
|
||||||
// ) : (
|
|
||||||
// <div className="flex h-full w-full items-center justify-center">
|
|
||||||
// <Spinner />
|
|
||||||
// </div>
|
|
||||||
// )}
|
|
||||||
// </DragDropContext>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
export const AllViews = () => <></>;
|
|
@ -1,2 +1 @@
|
|||||||
export * from "./issues-view";
|
|
||||||
export * from "./inline-issue-create-wrapper";
|
export * from "./inline-issue-create-wrapper";
|
||||||
|
@ -1,588 +0,0 @@
|
|||||||
// import { useCallback, useEffect, useState, FC } from "react";
|
|
||||||
// import { useRouter } from "next/router";
|
|
||||||
// import useSWR, { mutate } from "swr";
|
|
||||||
// import { DropResult } from "react-beautiful-dnd";
|
|
||||||
// // services
|
|
||||||
// import { IssueService, IssueLabelService } from "services/issue";
|
|
||||||
// import { ProjectStateService } from "services/project";
|
|
||||||
// import { ModuleService } from "services/module.service";
|
|
||||||
// import { TrackEventService } from "services/track_event.service";
|
|
||||||
// // hooks
|
|
||||||
// import useToast from "hooks/use-toast";
|
|
||||||
// import useIssuesView from "hooks/use-issues-view";
|
|
||||||
// import useUserAuth from "hooks/use-user-auth";
|
|
||||||
// import useIssuesProperties from "hooks/use-issue-properties";
|
|
||||||
// import useProjectMembers from "hooks/use-project-members";
|
|
||||||
// // components
|
|
||||||
// import { FiltersList } from "components/core";
|
|
||||||
// import {
|
|
||||||
// CreateUpdateIssueModal,
|
|
||||||
// DeleteIssueModal,
|
|
||||||
// DeleteDraftIssueModal,
|
|
||||||
// CreateUpdateDraftIssueModal,
|
|
||||||
// } from "components/issues";
|
|
||||||
// import { CreateUpdateViewModal } from "components/views";
|
|
||||||
// // ui
|
|
||||||
// import { Button } from "@plane/ui";
|
|
||||||
// // icons
|
|
||||||
// import { PlusIcon } from "@heroicons/react/24/outline";
|
|
||||||
// // helpers
|
|
||||||
// import { getStatesList } from "helpers/state.helper";
|
|
||||||
// import { orderArrayBy } from "helpers/array.helper";
|
|
||||||
// // types
|
|
||||||
// import { IIssue, IIssueFilterOptions, IState, TIssuePriorities } from "types";
|
|
||||||
// // fetch-keys
|
|
||||||
// import {
|
|
||||||
// CYCLE_DETAILS,
|
|
||||||
// CYCLE_ISSUES_WITH_PARAMS,
|
|
||||||
// MODULE_DETAILS,
|
|
||||||
// MODULE_ISSUES_WITH_PARAMS,
|
|
||||||
// PROJECT_ISSUES_LIST_WITH_PARAMS,
|
|
||||||
// PROJECT_ISSUE_LABELS,
|
|
||||||
// STATES_LIST,
|
|
||||||
// } from "constants/fetch-keys";
|
|
||||||
|
|
||||||
// type Props = {
|
|
||||||
// openIssuesListModal?: () => void;
|
|
||||||
// disableUserActions?: boolean;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const issueService = new IssueService();
|
|
||||||
// const issueLabelService = new IssueLabelService();
|
|
||||||
// const projectStateService = new ProjectStateService();
|
|
||||||
// const moduleService = new ModuleService();
|
|
||||||
// const trackEventService = new TrackEventService();
|
|
||||||
|
|
||||||
// export const IssuesView: FC<Props> = () => {
|
|
||||||
// // const { openIssuesListModal, disableUserActions = false } = props;
|
|
||||||
// // create issue modal
|
|
||||||
// const [createIssueModal, setCreateIssueModal] = useState(false);
|
|
||||||
// const [createViewModal, setCreateViewModal] = useState<any>(null);
|
|
||||||
// const [preloadedData, setPreloadedData] = useState<
|
|
||||||
// (Partial<IIssue> & { actionType: "createIssue" | "edit" | "delete" }) | undefined
|
|
||||||
// >(undefined);
|
|
||||||
|
|
||||||
// // update issue modal
|
|
||||||
// const [editIssueModal, setEditIssueModal] = useState(false);
|
|
||||||
// const [issueToEdit, setIssueToEdit] = useState<(IIssue & { actionType: "edit" | "delete" }) | undefined>(undefined);
|
|
||||||
|
|
||||||
// // delete issue modal
|
|
||||||
// const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
|
||||||
// const [issueToDelete, setIssueToDelete] = useState<IIssue | null>(null);
|
|
||||||
|
|
||||||
// // trash box
|
|
||||||
// // const [trashBox, setTrashBox] = useState(false);
|
|
||||||
|
|
||||||
// // selected draft issue
|
|
||||||
// const [selectedDraftIssue, setSelectedDraftIssue] = useState<IIssue | null>(null);
|
|
||||||
// const [selectedDraftForDelete, setSelectDraftForDelete] = useState<IIssue | null>(null);
|
|
||||||
|
|
||||||
// const router = useRouter();
|
|
||||||
// const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
|
||||||
|
|
||||||
// const isDraftIssues = router.pathname?.split("/")?.[4] === "draft-issues";
|
|
||||||
// // const isArchivedIssues = router.pathname?.split("/")?.[4] === "archived-issues";
|
|
||||||
|
|
||||||
// const { user } = useUserAuth();
|
|
||||||
|
|
||||||
// const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
// const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params, setDisplayFilters } =
|
|
||||||
// useIssuesView();
|
|
||||||
// const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
|
||||||
|
|
||||||
// const { data: stateGroups } = useSWR(
|
|
||||||
// workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
|
||||||
// workspaceSlug ? () => projectStateService.getStates(workspaceSlug as string, projectId as string) : null
|
|
||||||
// );
|
|
||||||
// const states = getStatesList(stateGroups);
|
|
||||||
|
|
||||||
// const { data: labels } = useSWR(
|
|
||||||
// workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null,
|
|
||||||
// workspaceSlug && projectId
|
|
||||||
// ? () => issueLabelService.getProjectIssueLabels(workspaceSlug.toString(), projectId.toString())
|
|
||||||
// : null
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString());
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (!isDraftIssues) return;
|
|
||||||
|
|
||||||
// if (
|
|
||||||
// displayFilters.layout === "calendar" ||
|
|
||||||
// displayFilters.layout === "gantt_chart" ||
|
|
||||||
// displayFilters.layout === "spreadsheet"
|
|
||||||
// )
|
|
||||||
// setDisplayFilters({ layout: "list" });
|
|
||||||
// }, [isDraftIssues, displayFilters, setDisplayFilters]);
|
|
||||||
|
|
||||||
// const handleDeleteIssue = useCallback(
|
|
||||||
// (issue: IIssue) => {
|
|
||||||
// setDeleteIssueModal(true);
|
|
||||||
// setIssueToDelete(issue);
|
|
||||||
// },
|
|
||||||
// [setDeleteIssueModal, setIssueToDelete]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const handleDraftIssueClick = useCallback((issue: any) => setSelectedDraftIssue(issue), []);
|
|
||||||
// const handleDraftIssueDelete = useCallback((issue: any) => setSelectDraftForDelete(issue), []);
|
|
||||||
|
|
||||||
// const handleOnDragEnd = useCallback(
|
|
||||||
// async (result: DropResult) => {
|
|
||||||
// setTrashBox(false);
|
|
||||||
|
|
||||||
// if (!result.destination || !workspaceSlug || !projectId || !groupedByIssues) return;
|
|
||||||
|
|
||||||
// const { source, destination } = result;
|
|
||||||
|
|
||||||
// const draggedItem = groupedByIssues[source.droppableId][source.index];
|
|
||||||
|
|
||||||
// if (destination.droppableId === "trashBox") {
|
|
||||||
// handleDeleteIssue(draggedItem);
|
|
||||||
// } else {
|
|
||||||
// if (displayFilters.order_by === "sort_order") {
|
|
||||||
// let newSortOrder = draggedItem.sort_order;
|
|
||||||
|
|
||||||
// const destinationGroupArray = groupedByIssues[destination.droppableId];
|
|
||||||
|
|
||||||
// if (destinationGroupArray.length !== 0) {
|
|
||||||
// // check if dropping in the same group
|
|
||||||
// if (source.droppableId === destination.droppableId) {
|
|
||||||
// // check if dropping at beginning
|
|
||||||
// if (destination.index === 0) newSortOrder = destinationGroupArray[0].sort_order - 10000;
|
|
||||||
// // check if dropping at last
|
|
||||||
// else if (destination.index === destinationGroupArray.length - 1)
|
|
||||||
// newSortOrder = destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000;
|
|
||||||
// else {
|
|
||||||
// if (destination.index > source.index)
|
|
||||||
// newSortOrder =
|
|
||||||
// (destinationGroupArray[source.index + 1].sort_order +
|
|
||||||
// destinationGroupArray[source.index + 2].sort_order) /
|
|
||||||
// 2;
|
|
||||||
// else if (destination.index < source.index)
|
|
||||||
// newSortOrder =
|
|
||||||
// (destinationGroupArray[source.index - 1].sort_order +
|
|
||||||
// destinationGroupArray[source.index - 2].sort_order) /
|
|
||||||
// 2;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // check if dropping at beginning
|
|
||||||
// if (destination.index === 0) newSortOrder = destinationGroupArray[0].sort_order - 10000;
|
|
||||||
// // check if dropping at last
|
|
||||||
// else if (destination.index === destinationGroupArray.length)
|
|
||||||
// newSortOrder = destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000;
|
|
||||||
// else
|
|
||||||
// newSortOrder =
|
|
||||||
// (destinationGroupArray[destination.index - 1].sort_order +
|
|
||||||
// destinationGroupArray[destination.index].sort_order) /
|
|
||||||
// 2;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// draggedItem.sort_order = newSortOrder;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const destinationGroup = destination.droppableId; // destination group id
|
|
||||||
|
|
||||||
// if (displayFilters.order_by === "sort_order" || source.droppableId !== destination.droppableId) {
|
|
||||||
// // different group/column;
|
|
||||||
|
|
||||||
// // source.droppableId !== destination.droppableId -> even if order by is not sort_order,
|
|
||||||
// // if the issue is moved to a different group, then we will change the group of the
|
|
||||||
// // dragged item(or issue)
|
|
||||||
|
|
||||||
// if (displayFilters.group_by === "priority") draggedItem.priority = destinationGroup as TIssuePriorities;
|
|
||||||
// else if (displayFilters.group_by === "state") {
|
|
||||||
// draggedItem.state = destinationGroup;
|
|
||||||
// draggedItem.state_detail = states?.find((s) => s.id === destinationGroup) as IState;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const sourceGroup = source.droppableId; // source group id
|
|
||||||
|
|
||||||
// mutate<{
|
|
||||||
// [key: string]: IIssue[];
|
|
||||||
// }>(
|
|
||||||
// cycleId
|
|
||||||
// ? CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)
|
|
||||||
// : moduleId
|
|
||||||
// ? MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)
|
|
||||||
// : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params),
|
|
||||||
// (prevData) => {
|
|
||||||
// if (!prevData) return prevData;
|
|
||||||
|
|
||||||
// const sourceGroupArray = [...groupedByIssues[sourceGroup]];
|
|
||||||
// const destinationGroupArray = [...groupedByIssues[destinationGroup]];
|
|
||||||
|
|
||||||
// sourceGroupArray.splice(source.index, 1);
|
|
||||||
// destinationGroupArray.splice(destination.index, 0, draggedItem);
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// ...prevData,
|
|
||||||
// [sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"),
|
|
||||||
// [destinationGroup]: orderArrayBy(destinationGroupArray, displayFilters.order_by ?? "-created_at"),
|
|
||||||
// };
|
|
||||||
// },
|
|
||||||
// false
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // patch request
|
|
||||||
// issueService
|
|
||||||
// .patchIssue(
|
|
||||||
// workspaceSlug as string,
|
|
||||||
// projectId as string,
|
|
||||||
// draggedItem.id,
|
|
||||||
// {
|
|
||||||
// priority: draggedItem.priority,
|
|
||||||
// state: draggedItem.state,
|
|
||||||
// sort_order: draggedItem.sort_order,
|
|
||||||
// },
|
|
||||||
// user
|
|
||||||
// )
|
|
||||||
// .then((response) => {
|
|
||||||
// const sourceStateBeforeDrag = states?.find((state) => state.name === source.droppableId);
|
|
||||||
|
|
||||||
// if (sourceStateBeforeDrag?.group !== "completed" && response?.state_detail?.group === "completed")
|
|
||||||
// trackEventService.trackIssueMarkedAsDoneEvent(
|
|
||||||
// {
|
|
||||||
// workspaceSlug,
|
|
||||||
// workspaceId: draggedItem.workspace,
|
|
||||||
// projectName: draggedItem.project_detail.name,
|
|
||||||
// projectIdentifier: draggedItem.project_detail.identifier,
|
|
||||||
// projectId,
|
|
||||||
// issueId: draggedItem.id,
|
|
||||||
// },
|
|
||||||
// user
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (cycleId) {
|
|
||||||
// mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params));
|
|
||||||
// mutate(CYCLE_DETAILS(cycleId as string));
|
|
||||||
// }
|
|
||||||
// if (moduleId) {
|
|
||||||
// mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
|
|
||||||
// mutate(MODULE_DETAILS(moduleId as string));
|
|
||||||
// }
|
|
||||||
// mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// [
|
|
||||||
// displayFilters.group_by,
|
|
||||||
// displayFilters.order_by,
|
|
||||||
// workspaceSlug,
|
|
||||||
// cycleId,
|
|
||||||
// moduleId,
|
|
||||||
// groupedByIssues,
|
|
||||||
// projectId,
|
|
||||||
// handleDeleteIssue,
|
|
||||||
// params,
|
|
||||||
// states,
|
|
||||||
// user,
|
|
||||||
// ]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const addIssueToGroup = useCallback(
|
|
||||||
// (groupTitle: string) => {
|
|
||||||
// setCreateIssueModal(true);
|
|
||||||
|
|
||||||
// let preloadedValue: string | string[] = groupTitle;
|
|
||||||
|
|
||||||
// if (displayFilters.group_by === "labels") {
|
|
||||||
// if (groupTitle === "None") preloadedValue = [];
|
|
||||||
// else preloadedValue = [groupTitle];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (displayFilters.group_by)
|
|
||||||
// setPreloadedData({
|
|
||||||
// [displayFilters.group_by]: preloadedValue,
|
|
||||||
// actionType: "createIssue",
|
|
||||||
// });
|
|
||||||
// else setPreloadedData({ actionType: "createIssue" });
|
|
||||||
// },
|
|
||||||
// [displayFilters.group_by, setCreateIssueModal, setPreloadedData]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const addIssueToDate = useCallback(
|
|
||||||
// (date: string) => {
|
|
||||||
// setCreateIssueModal(true);
|
|
||||||
// setPreloadedData({
|
|
||||||
// target_date: date,
|
|
||||||
// actionType: "createIssue",
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// [setCreateIssueModal, setPreloadedData]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const makeIssueCopy = useCallback(
|
|
||||||
// (issue: IIssue) => {
|
|
||||||
// setCreateIssueModal(true);
|
|
||||||
|
|
||||||
// setPreloadedData({ ...issue, name: `${issue.name} (Copy)`, actionType: "createIssue" });
|
|
||||||
// },
|
|
||||||
// [setCreateIssueModal, setPreloadedData]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const handleEditIssue = useCallback(
|
|
||||||
// (issue: IIssue) => {
|
|
||||||
// setEditIssueModal(true);
|
|
||||||
// setIssueToEdit({
|
|
||||||
// ...issue,
|
|
||||||
// actionType: "edit",
|
|
||||||
// cycle: issue.issue_cycle ? issue.issue_cycle.cycle : null,
|
|
||||||
// module: issue.issue_module ? issue.issue_module.module : null,
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// [setEditIssueModal, setIssueToEdit]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const handleIssueAction = useCallback(
|
|
||||||
// (issue: IIssue, action: "copy" | "edit" | "delete") => {
|
|
||||||
// if (action === "copy") makeIssueCopy(issue);
|
|
||||||
// else if (action === "edit") handleEditIssue(issue);
|
|
||||||
// else if (action === "delete") handleDeleteIssue(issue);
|
|
||||||
// },
|
|
||||||
// [makeIssueCopy, handleEditIssue, handleDeleteIssue]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const handleDraftIssueAction = useCallback(
|
|
||||||
// (issue: IIssue, action: "edit" | "delete") => {
|
|
||||||
// if (action === "edit") handleDraftIssueClick(issue);
|
|
||||||
// else if (action === "delete") handleDraftIssueDelete(issue);
|
|
||||||
// },
|
|
||||||
// [handleDraftIssueClick, handleDraftIssueDelete]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const removeIssueFromCycle = useCallback(
|
|
||||||
// (bridgeId: string, issueId: string) => {
|
|
||||||
// if (!workspaceSlug || !projectId || !cycleId) return;
|
|
||||||
|
|
||||||
// mutate(
|
|
||||||
// CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
|
|
||||||
// (prevData: any) => {
|
|
||||||
// if (!prevData) return prevData;
|
|
||||||
// if (displayFilters.group_by) {
|
|
||||||
// const filteredData: any = {};
|
|
||||||
// for (const key in prevData) {
|
|
||||||
// filteredData[key] = prevData[key].filter((item: any) => item.id !== issueId);
|
|
||||||
// }
|
|
||||||
// return filteredData;
|
|
||||||
// } else {
|
|
||||||
// const filteredData = prevData.filter((i: any) => i.id !== issueId);
|
|
||||||
// return filteredData;
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// false
|
|
||||||
// );
|
|
||||||
|
|
||||||
// issueService
|
|
||||||
// .removeIssueFromCycle(workspaceSlug as string, projectId as string, cycleId as string, bridgeId)
|
|
||||||
// .then(() => {
|
|
||||||
// setToastAlert({
|
|
||||||
// title: "Success",
|
|
||||||
// message: "Issue removed successfully.",
|
|
||||||
// type: "success",
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch((e) => {
|
|
||||||
// console.log(e);
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// [displayFilters.group_by, workspaceSlug, projectId, cycleId, params, setToastAlert]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const removeIssueFromModule = useCallback(
|
|
||||||
// (bridgeId: string, issueId: string) => {
|
|
||||||
// if (!workspaceSlug || !projectId || !moduleId) return;
|
|
||||||
|
|
||||||
// mutate(
|
|
||||||
// MODULE_ISSUES_WITH_PARAMS(moduleId as string, params),
|
|
||||||
// (prevData: any) => {
|
|
||||||
// if (!prevData) return prevData;
|
|
||||||
// if (displayFilters.group_by) {
|
|
||||||
// const filteredData: any = {};
|
|
||||||
// for (const key in prevData) {
|
|
||||||
// filteredData[key] = prevData[key].filter((item: any) => item.id !== issueId);
|
|
||||||
// }
|
|
||||||
// return filteredData;
|
|
||||||
// } else {
|
|
||||||
// const filteredData = prevData.filter((item: any) => item.id !== issueId);
|
|
||||||
// return filteredData;
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// false
|
|
||||||
// );
|
|
||||||
|
|
||||||
// moduleService
|
|
||||||
// .removeIssueFromModule(workspaceSlug as string, projectId as string, moduleId as string, bridgeId)
|
|
||||||
// .then(() => {
|
|
||||||
// setToastAlert({
|
|
||||||
// title: "Success",
|
|
||||||
// message: "Issue removed successfully.",
|
|
||||||
// type: "success",
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .catch((e) => {
|
|
||||||
// console.log(e);
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// [displayFilters.group_by, workspaceSlug, projectId, moduleId, params, setToastAlert]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const nullFilters = Object.keys(filters).filter((key) => filters[key as keyof IIssueFilterOptions] === null);
|
|
||||||
|
|
||||||
// const areFiltersApplied = Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length;
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <>
|
|
||||||
// <CreateUpdateViewModal
|
|
||||||
// isOpen={createViewModal !== null}
|
|
||||||
// handleClose={() => setCreateViewModal(null)}
|
|
||||||
// preLoadedData={createViewModal}
|
|
||||||
// user={user}
|
|
||||||
// />
|
|
||||||
// <CreateUpdateIssueModal
|
|
||||||
// isOpen={createIssueModal && preloadedData?.actionType === "createIssue"}
|
|
||||||
// handleClose={() => setCreateIssueModal(false)}
|
|
||||||
// prePopulateData={{
|
|
||||||
// ...preloadedData,
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// <CreateUpdateDraftIssueModal
|
|
||||||
// isOpen={selectedDraftIssue !== null}
|
|
||||||
// handleClose={() => setSelectedDraftIssue(null)}
|
|
||||||
// data={
|
|
||||||
// selectedDraftIssue
|
|
||||||
// ? {
|
|
||||||
// ...selectedDraftIssue,
|
|
||||||
// is_draft: true,
|
|
||||||
// }
|
|
||||||
// : null
|
|
||||||
// }
|
|
||||||
// fieldsToShow={["all"]}
|
|
||||||
// />
|
|
||||||
// <CreateUpdateIssueModal
|
|
||||||
// isOpen={editIssueModal && issueToEdit?.actionType !== "delete"}
|
|
||||||
// handleClose={() => setEditIssueModal(false)}
|
|
||||||
// data={issueToEdit}
|
|
||||||
// />
|
|
||||||
// <DeleteIssueModal
|
|
||||||
// handleClose={() => setDeleteIssueModal(false)}
|
|
||||||
// isOpen={deleteIssueModal}
|
|
||||||
// data={issueToDelete}
|
|
||||||
// user={user}
|
|
||||||
// />
|
|
||||||
// <DeleteDraftIssueModal
|
|
||||||
// data={selectedDraftForDelete}
|
|
||||||
// isOpen={selectedDraftForDelete !== null}
|
|
||||||
// handleClose={() => setSelectDraftForDelete(null)}
|
|
||||||
// />
|
|
||||||
|
|
||||||
// {areFiltersApplied && (
|
|
||||||
// <>
|
|
||||||
// <div className="flex items-center justify-between gap-2 px-5 pt-3 pb-0">
|
|
||||||
// <FiltersList
|
|
||||||
// filters={filters}
|
|
||||||
// setFilters={(updatedFilter) => setFilters(updatedFilter, !Boolean(viewId))}
|
|
||||||
// labels={labels}
|
|
||||||
// members={members?.map((m: any) => m.member)}
|
|
||||||
// states={states}
|
|
||||||
// clearAllFilters={() =>
|
|
||||||
// setFilters({
|
|
||||||
// assignees: null,
|
|
||||||
// created_by: null,
|
|
||||||
// labels: null,
|
|
||||||
// priority: null,
|
|
||||||
// state: null,
|
|
||||||
// state_group: null,
|
|
||||||
// start_date: null,
|
|
||||||
// target_date: null,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// />
|
|
||||||
// <Button
|
|
||||||
// variant="primary"
|
|
||||||
// prependIcon={!viewId && <PlusIcon />}
|
|
||||||
// onClick={() => {
|
|
||||||
// if (viewId) {
|
|
||||||
// setFilters({}, true);
|
|
||||||
// setToastAlert({
|
|
||||||
// title: "View updated",
|
|
||||||
// message: "Your view has been updated",
|
|
||||||
// type: "success",
|
|
||||||
// });
|
|
||||||
// } else
|
|
||||||
// setCreateViewModal({
|
|
||||||
// query: filters,
|
|
||||||
// });
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// {viewId ? "Update" : "Save"} view
|
|
||||||
// </Button>
|
|
||||||
// </div>
|
|
||||||
// {<div className="mt-3 border-t border-custom-border-200" />}
|
|
||||||
// </>
|
|
||||||
// )}
|
|
||||||
// {/* <AllViews
|
|
||||||
// addIssueToDate={addIssueToDate}
|
|
||||||
// addIssueToGroup={addIssueToGroup}
|
|
||||||
// disableUserActions={disableUserActions}
|
|
||||||
// dragDisabled={
|
|
||||||
// displayFilters.group_by === "created_by" ||
|
|
||||||
// displayFilters.group_by === "labels" ||
|
|
||||||
// displayFilters.group_by === "state_detail.group" ||
|
|
||||||
// displayFilters.group_by === "assignees"
|
|
||||||
// }
|
|
||||||
// emptyState={{
|
|
||||||
// title: isDraftIssues
|
|
||||||
// ? "Draft issues will appear here"
|
|
||||||
// : cycleId
|
|
||||||
// ? "Cycle issues will appear here"
|
|
||||||
// : moduleId
|
|
||||||
// ? "Module issues will appear here"
|
|
||||||
// : "Project issues will appear here",
|
|
||||||
// description: isDraftIssues
|
|
||||||
// ? "Draft issues are issues that are not yet created."
|
|
||||||
// : "Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done.",
|
|
||||||
// primaryButton: !isDraftIssues
|
|
||||||
// ? {
|
|
||||||
// icon: <PlusIcon className="h-4 w-4" />,
|
|
||||||
// text: "New Issue",
|
|
||||||
// onClick: () => {
|
|
||||||
// const e = new KeyboardEvent("keydown", {
|
|
||||||
// key: "c",
|
|
||||||
// });
|
|
||||||
// document.dispatchEvent(e);
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// : undefined,
|
|
||||||
// secondaryButton:
|
|
||||||
// cycleId || moduleId ? (
|
|
||||||
// <Button variant="neutral-primary" prependIcon={<PlusIcon />} onClick={openIssuesListModal ?? (() => {})}>
|
|
||||||
// Add an existing issue
|
|
||||||
// </Button>
|
|
||||||
// ) : null,
|
|
||||||
// }}
|
|
||||||
// handleOnDragEnd={handleOnDragEnd}
|
|
||||||
// handleIssueAction={handleIssueAction}
|
|
||||||
// handleDraftIssueAction={handleDraftIssueAction}
|
|
||||||
// openIssuesListModal={openIssuesListModal ?? null}
|
|
||||||
// removeIssue={cycleId ? removeIssueFromCycle : moduleId ? removeIssueFromModule : null}
|
|
||||||
// trashBox={trashBox}
|
|
||||||
// setTrashBox={setTrashBox}
|
|
||||||
// viewProps={{
|
|
||||||
// groupedIssues: groupedByIssues,
|
|
||||||
// displayFilters,
|
|
||||||
// isEmpty,
|
|
||||||
// mutateIssues,
|
|
||||||
// params,
|
|
||||||
// properties,
|
|
||||||
// }}
|
|
||||||
// disableAddIssueOption={isArchivedIssues}
|
|
||||||
// /> */}
|
|
||||||
// </>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
export const IssuesView = () => <></>;
|
|
@ -7,14 +7,14 @@ import useToast from "hooks/use-toast";
|
|||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssue, Properties } from "types";
|
import { IIssue, IIssueDisplayProperties } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
handleToggleExpand: (issueId: string) => void;
|
handleToggleExpand: (issueId: string) => void;
|
||||||
properties: Properties;
|
properties: IIssueDisplayProperties;
|
||||||
handleEditIssue: (issue: IIssue) => void;
|
handleEditIssue: (issue: IIssue) => void;
|
||||||
handleDeleteIssue: (issue: IIssue) => void;
|
handleDeleteIssue: (issue: IIssue) => void;
|
||||||
disableUserActions: boolean;
|
disableUserActions: boolean;
|
||||||
|
@ -5,14 +5,14 @@ import { IssueColumn } from "components/issues";
|
|||||||
// hooks
|
// hooks
|
||||||
import useSubIssue from "hooks/use-sub-issue";
|
import useSubIssue from "hooks/use-sub-issue";
|
||||||
// types
|
// types
|
||||||
import { IIssue, Properties } from "types";
|
import { IIssue, IIssueDisplayProperties } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
expandedIssues: string[];
|
expandedIssues: string[];
|
||||||
setExpandedIssues: React.Dispatch<React.SetStateAction<string[]>>;
|
setExpandedIssues: React.Dispatch<React.SetStateAction<string[]>>;
|
||||||
properties: Properties;
|
properties: IIssueDisplayProperties;
|
||||||
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
|
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
|
||||||
disableUserActions: boolean;
|
disableUserActions: boolean;
|
||||||
nestingLevel?: number;
|
nestingLevel?: number;
|
||||||
|
@ -110,7 +110,6 @@ export const SubIssues: React.FC<ISubIssues> = ({
|
|||||||
<div className="flex-shrink-0 text-sm">
|
<div className="flex-shrink-0 text-sm">
|
||||||
<IssueProperty
|
<IssueProperty
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
projectId={projectId}
|
|
||||||
parentIssue={parentIssue}
|
parentIssue={parentIssue}
|
||||||
issue={issue}
|
issue={issue}
|
||||||
user={user}
|
user={user}
|
||||||
|
@ -10,8 +10,6 @@ import { TrackEventService } from "services/track_event.service";
|
|||||||
import { ViewDueDateSelect, ViewStartDateSelect } from "components/issues";
|
import { ViewDueDateSelect, ViewStartDateSelect } from "components/issues";
|
||||||
import { MembersSelect, PrioritySelect } from "components/project";
|
import { MembersSelect, PrioritySelect } from "components/project";
|
||||||
import { StateSelect } from "components/states";
|
import { StateSelect } from "components/states";
|
||||||
// hooks
|
|
||||||
import useIssuesProperties from "hooks/use-issue-properties";
|
|
||||||
// types
|
// types
|
||||||
import { IUser, IIssue, IState } from "types";
|
import { IUser, IIssue, IState } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
@ -19,7 +17,6 @@ import { SUB_ISSUES } from "constants/fetch-keys";
|
|||||||
|
|
||||||
export interface IIssueProperty {
|
export interface IIssueProperty {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
|
||||||
parentIssue: IIssue;
|
parentIssue: IIssue;
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
user: IUser | undefined;
|
user: IUser | undefined;
|
||||||
@ -30,11 +27,12 @@ export interface IIssueProperty {
|
|||||||
const issueService = new IssueService();
|
const issueService = new IssueService();
|
||||||
const trackEventService = new TrackEventService();
|
const trackEventService = new TrackEventService();
|
||||||
|
|
||||||
export const IssueProperty: React.FC<IIssueProperty> = observer(
|
export const IssueProperty: React.FC<IIssueProperty> = observer((props) => {
|
||||||
({ workspaceSlug, projectId, parentIssue, issue, user, editable }) => {
|
const { workspaceSlug, parentIssue, issue, user, editable } = props;
|
||||||
const [properties] = useIssuesProperties(workspaceSlug, projectId);
|
|
||||||
|
|
||||||
const { project: projectStore } = useMobxStore();
|
const { project: projectStore, issueFilter: issueFilterStore } = useMobxStore();
|
||||||
|
|
||||||
|
const displayProperties = issueFilterStore.userDisplayProperties ?? {};
|
||||||
|
|
||||||
const handlePriorityChange = (data: any) => {
|
const handlePriorityChange = (data: any) => {
|
||||||
partialUpdateIssue({ priority: data });
|
partialUpdateIssue({ priority: data });
|
||||||
@ -119,7 +117,7 @@ export const IssueProperty: React.FC<IIssueProperty> = observer(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex items-center gap-1">
|
<div className="relative flex items-center gap-1">
|
||||||
{properties.priority && (
|
{displayProperties.priority && (
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<PrioritySelect
|
<PrioritySelect
|
||||||
value={issue.priority}
|
value={issue.priority}
|
||||||
@ -130,7 +128,7 @@ export const IssueProperty: React.FC<IIssueProperty> = observer(
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{properties.state && (
|
{displayProperties.state && (
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<StateSelect
|
<StateSelect
|
||||||
value={issue.state_detail}
|
value={issue.state_detail}
|
||||||
@ -142,7 +140,7 @@ export const IssueProperty: React.FC<IIssueProperty> = observer(
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{properties.start_date && issue.start_date && (
|
{displayProperties.start_date && issue.start_date && (
|
||||||
<div className="flex-shrink-0 w-[104px]">
|
<div className="flex-shrink-0 w-[104px]">
|
||||||
<ViewStartDateSelect
|
<ViewStartDateSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
@ -152,7 +150,7 @@ export const IssueProperty: React.FC<IIssueProperty> = observer(
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{properties.due_date && issue.target_date && (
|
{displayProperties.due_date && issue.target_date && (
|
||||||
<div className="flex-shrink-0 w-[104px]">
|
<div className="flex-shrink-0 w-[104px]">
|
||||||
{user && (
|
{user && (
|
||||||
<ViewDueDateSelect
|
<ViewDueDateSelect
|
||||||
@ -164,7 +162,7 @@ export const IssueProperty: React.FC<IIssueProperty> = observer(
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{properties.assignee && (
|
{displayProperties.assignee && (
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<MembersSelect
|
<MembersSelect
|
||||||
value={issue.assignees}
|
value={issue.assignees}
|
||||||
@ -178,5 +176,4 @@ export const IssueProperty: React.FC<IIssueProperty> = observer(
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
import { useState, useEffect, useCallback } from "react";
|
|
||||||
import useSWR from "swr";
|
|
||||||
// services
|
|
||||||
import { IssueService } from "services/issue";
|
|
||||||
// hooks
|
|
||||||
import useUser from "hooks/use-user";
|
|
||||||
// types
|
|
||||||
import { IssuePriorities, Properties } from "types";
|
|
||||||
|
|
||||||
const issueService = new IssueService();
|
|
||||||
|
|
||||||
const initialValues: Properties = {
|
|
||||||
assignee: true,
|
|
||||||
start_date: true,
|
|
||||||
due_date: true,
|
|
||||||
key: true,
|
|
||||||
labels: true,
|
|
||||||
priority: true,
|
|
||||||
state: true,
|
|
||||||
sub_issue_count: true,
|
|
||||||
attachment_count: true,
|
|
||||||
link: true,
|
|
||||||
estimate: true,
|
|
||||||
created_on: true,
|
|
||||||
updated_on: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const useIssuesProperties = (workspaceSlug?: string, projectId?: string) => {
|
|
||||||
const [properties, setProperties] = useState<Properties>(initialValues);
|
|
||||||
|
|
||||||
const { user } = useUser();
|
|
||||||
|
|
||||||
const { data: issueProperties, mutate: mutateIssueProperties } = useSWR<IssuePriorities>(
|
|
||||||
workspaceSlug && projectId ? `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/` : null,
|
|
||||||
workspaceSlug && projectId ? () => issueService.getIssueProperties(workspaceSlug, projectId) : null
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!issueProperties || !workspaceSlug || !projectId || !user) return;
|
|
||||||
|
|
||||||
setProperties({ ...initialValues, ...issueProperties.properties });
|
|
||||||
|
|
||||||
if (Object.keys(issueProperties).length === 0)
|
|
||||||
issueService.createIssueProperties(workspaceSlug, projectId, {
|
|
||||||
properties: { ...initialValues },
|
|
||||||
user: user.id,
|
|
||||||
});
|
|
||||||
else if (Object.keys(issueProperties?.properties).length === 0)
|
|
||||||
issueService.patchIssueProperties(workspaceSlug, projectId, issueProperties.id, {
|
|
||||||
properties: { ...initialValues },
|
|
||||||
user: user.id,
|
|
||||||
});
|
|
||||||
}, [issueProperties, workspaceSlug, projectId, user]);
|
|
||||||
|
|
||||||
const updateIssueProperties = useCallback(
|
|
||||||
(key: keyof Properties) => {
|
|
||||||
if (!workspaceSlug || !user) return;
|
|
||||||
|
|
||||||
setProperties((prev) => ({ ...prev, [key]: !prev[key] }));
|
|
||||||
|
|
||||||
if (issueProperties && projectId) {
|
|
||||||
mutateIssueProperties(
|
|
||||||
(prev: any) =>
|
|
||||||
({
|
|
||||||
...prev,
|
|
||||||
properties: { ...prev?.properties, [key]: !prev?.properties?.[key] },
|
|
||||||
} as IssuePriorities),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
if (Object.keys(issueProperties).length > 0) {
|
|
||||||
issueService.patchIssueProperties(workspaceSlug, projectId, issueProperties.id, {
|
|
||||||
properties: {
|
|
||||||
...issueProperties.properties,
|
|
||||||
[key]: !issueProperties.properties[key],
|
|
||||||
},
|
|
||||||
user: user.id,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
issueService.createIssueProperties(workspaceSlug, projectId, {
|
|
||||||
properties: { ...initialValues },
|
|
||||||
user: user.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[workspaceSlug, projectId, issueProperties, user, mutateIssueProperties]
|
|
||||||
);
|
|
||||||
|
|
||||||
const newProperties: Properties = {
|
|
||||||
assignee: properties.assignee,
|
|
||||||
start_date: properties.start_date,
|
|
||||||
due_date: properties.due_date,
|
|
||||||
key: properties.key,
|
|
||||||
labels: properties.labels,
|
|
||||||
priority: properties.priority,
|
|
||||||
state: properties.state,
|
|
||||||
sub_issue_count: properties.sub_issue_count,
|
|
||||||
attachment_count: properties.attachment_count,
|
|
||||||
link: properties.link,
|
|
||||||
estimate: properties.estimate,
|
|
||||||
created_on: properties.created_on,
|
|
||||||
updated_on: properties.updated_on,
|
|
||||||
};
|
|
||||||
|
|
||||||
return [newProperties, updateIssueProperties] as const;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useIssuesProperties;
|
|
@ -11,8 +11,6 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
|||||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||||
// helper
|
// helper
|
||||||
import { truncateText } from "helpers/string.helper";
|
import { truncateText } from "helpers/string.helper";
|
||||||
// components
|
|
||||||
import { IssuesFilterView, IssuesView } from "components/core";
|
|
||||||
// ui
|
// ui
|
||||||
import { ArchiveIcon, BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
import { ArchiveIcon, BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
@ -51,11 +49,11 @@ const ProjectArchivedIssues: NextPage = () => {
|
|||||||
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Archived Issues`} />
|
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Archived Issues`} />
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
}
|
}
|
||||||
right={
|
// right={
|
||||||
<div className="flex items-center gap-2">
|
// <div className="flex items-center gap-2">
|
||||||
<IssuesFilterView />
|
// <IssuesFilterView />
|
||||||
</div>
|
// </div>
|
||||||
}
|
// }
|
||||||
>
|
>
|
||||||
<div className="h-full w-full flex flex-col">
|
<div className="h-full w-full flex flex-col">
|
||||||
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
|
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
|
||||||
@ -70,7 +68,7 @@ const ProjectArchivedIssues: NextPage = () => {
|
|||||||
<X className="h-3 w-3" />
|
<X className="h-3 w-3" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<IssuesView />
|
{/* <IssuesView /> */}
|
||||||
</div>
|
</div>
|
||||||
</ProjectAuthorizationWrapper>
|
</ProjectAuthorizationWrapper>
|
||||||
</IssueViewContextProvider>
|
</IssueViewContextProvider>
|
||||||
|
@ -11,8 +11,6 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
|||||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||||
// helper
|
// helper
|
||||||
import { truncateText } from "helpers/string.helper";
|
import { truncateText } from "helpers/string.helper";
|
||||||
// components
|
|
||||||
import { IssuesFilterView, IssuesView } from "components/core";
|
|
||||||
// ui
|
// ui
|
||||||
import { BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
import { BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
@ -51,11 +49,11 @@ const ProjectDraftIssues: NextPage = () => {
|
|||||||
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Draft Issues`} />
|
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Draft Issues`} />
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
}
|
}
|
||||||
right={
|
// right={
|
||||||
<div className="flex items-center gap-2">
|
// <div className="flex items-center gap-2">
|
||||||
<IssuesFilterView />
|
// <IssuesFilterView />
|
||||||
</div>
|
// </div>
|
||||||
}
|
// }
|
||||||
>
|
>
|
||||||
<div className="h-full w-full flex flex-col">
|
<div className="h-full w-full flex flex-col">
|
||||||
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
|
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
|
||||||
@ -70,7 +68,6 @@ const ProjectDraftIssues: NextPage = () => {
|
|||||||
<X className="h-3 w-3" />
|
<X className="h-3 w-3" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<IssuesView />
|
|
||||||
</div>
|
</div>
|
||||||
</ProjectAuthorizationWrapper>
|
</ProjectAuthorizationWrapper>
|
||||||
</IssueViewContextProvider>
|
</IssueViewContextProvider>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
import { TrackEventService } from "services/track_event.service";
|
import { TrackEventService } from "services/track_event.service";
|
||||||
// type
|
// type
|
||||||
import type { IUser, IIssue, IIssueActivity, ISubIssueResponse } from "types";
|
import type { IUser, IIssue, IIssueActivity, ISubIssueResponse, IIssueDisplayProperties } from "types";
|
||||||
// helper
|
// helper
|
||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
|
|
||||||
@ -62,14 +62,6 @@ export class IssueService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getIssueProperties(workspaceSlug: string, projectId: string): Promise<any> {
|
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/`)
|
|
||||||
.then((response) => response?.data)
|
|
||||||
.catch((error) => {
|
|
||||||
throw error?.response?.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async addIssueToCycle(
|
async addIssueToCycle(
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
@ -153,24 +145,20 @@ export class IssueService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async createIssueProperties(workspaceSlug: string, projectId: string, data: any): Promise<any> {
|
async getIssueDisplayProperties(workspaceSlug: string, projectId: string): Promise<any> {
|
||||||
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/`, data)
|
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-display-properties/`)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
throw error?.response?.data;
|
throw error?.response?.data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async patchIssueProperties(
|
async patchIssueDisplayProperties(
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
issuePropertyId: string,
|
data: IIssueDisplayProperties
|
||||||
data: any
|
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
return this.patch(
|
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-display-properties/`, data)
|
||||||
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/` + `${issuePropertyId}/`,
|
|
||||||
data
|
|
||||||
)
|
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
throw error?.response?.data;
|
throw error?.response?.data;
|
||||||
|
@ -136,14 +136,6 @@ export class ProjectService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async joinProjects(data: any): Promise<any> {
|
|
||||||
return this.post("/api/users/me/invitations/projects/", data)
|
|
||||||
.then((response) => response?.data)
|
|
||||||
.catch((error) => {
|
|
||||||
throw error?.response?.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async projectMembers(workspaceSlug: string, projectId: string): Promise<IProjectMember[]> {
|
async projectMembers(workspaceSlug: string, projectId: string): Promise<IProjectMember[]> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-members/`)
|
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-members/`)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
|
@ -45,7 +45,7 @@ export class IssueFilterStore implements IIssueFilterStore {
|
|||||||
error: any | null = null;
|
error: any | null = null;
|
||||||
|
|
||||||
// observables
|
// observables
|
||||||
userDisplayProperties: any = {};
|
userDisplayProperties: IIssueDisplayProperties = {};
|
||||||
userDisplayFilters: IIssueDisplayFilterOptions = {};
|
userDisplayFilters: IIssueDisplayFilterOptions = {};
|
||||||
userFilters: IIssueFilterOptions = {};
|
userFilters: IIssueFilterOptions = {};
|
||||||
defaultDisplayFilters: IIssueDisplayFilterOptions = {};
|
defaultDisplayFilters: IIssueDisplayFilterOptions = {};
|
||||||
@ -144,7 +144,7 @@ export class IssueFilterStore implements IIssueFilterStore {
|
|||||||
fetchUserProjectFilters = async (workspaceSlug: string, projectId: string) => {
|
fetchUserProjectFilters = async (workspaceSlug: string, projectId: string) => {
|
||||||
try {
|
try {
|
||||||
const memberResponse = await this.projectService.projectMemberMe(workspaceSlug, projectId);
|
const memberResponse = await this.projectService.projectMemberMe(workspaceSlug, projectId);
|
||||||
const issueProperties = await this.issueService.getIssueProperties(workspaceSlug, projectId);
|
const issueProperties = await this.issueService.getIssueDisplayProperties(workspaceSlug, projectId);
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.userFilters = memberResponse?.view_props?.filters;
|
this.userFilters = memberResponse?.view_props?.filters;
|
||||||
@ -207,7 +207,7 @@ export class IssueFilterStore implements IIssueFilterStore {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
properties: Partial<IIssueDisplayProperties>
|
properties: Partial<IIssueDisplayProperties>
|
||||||
) => {
|
) => {
|
||||||
const newProperties = {
|
const newProperties: IIssueDisplayProperties = {
|
||||||
...this.userDisplayProperties,
|
...this.userDisplayProperties,
|
||||||
...properties,
|
...properties,
|
||||||
};
|
};
|
||||||
@ -217,7 +217,7 @@ export class IssueFilterStore implements IIssueFilterStore {
|
|||||||
this.userDisplayProperties = newProperties;
|
this.userDisplayProperties = newProperties;
|
||||||
});
|
});
|
||||||
|
|
||||||
// await this.issueService.patchIssueProperties(workspaceSlug, projectId, newProperties);
|
await this.issueService.patchIssueDisplayProperties(workspaceSlug, projectId, newProperties);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.fetchUserProjectFilters(workspaceSlug, projectId);
|
this.fetchUserProjectFilters(workspaceSlug, projectId);
|
||||||
|
|
||||||
|
30
web/types/view-props.d.ts
vendored
30
web/types/view-props.d.ts
vendored
@ -84,19 +84,19 @@ export interface IIssueDisplayFilterOptions {
|
|||||||
type?: TIssueTypeFilters;
|
type?: TIssueTypeFilters;
|
||||||
}
|
}
|
||||||
export interface IIssueDisplayProperties {
|
export interface IIssueDisplayProperties {
|
||||||
assignee: boolean;
|
assignee?: boolean;
|
||||||
start_date: boolean;
|
start_date?: boolean;
|
||||||
due_date: boolean;
|
due_date?: boolean;
|
||||||
labels: boolean;
|
labels?: boolean;
|
||||||
key: boolean;
|
key?: boolean;
|
||||||
priority: boolean;
|
priority?: boolean;
|
||||||
state: boolean;
|
state?: boolean;
|
||||||
sub_issue_count: boolean;
|
sub_issue_count?: boolean;
|
||||||
link: boolean;
|
link?: boolean;
|
||||||
attachment_count: boolean;
|
attachment_count?: boolean;
|
||||||
estimate: boolean;
|
estimate?: boolean;
|
||||||
created_on: boolean;
|
created_on?: boolean;
|
||||||
updated_on: boolean;
|
updated_on?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWorkspaceIssueFilterOptions {
|
export interface IWorkspaceIssueFilterOptions {
|
||||||
@ -142,10 +142,10 @@ export interface IProjectViewProps {
|
|||||||
export interface IWorkspaceViewProps {
|
export interface IWorkspaceViewProps {
|
||||||
filters: IIssueFilterOptions;
|
filters: IIssueFilterOptions;
|
||||||
display_filters: IIssueDisplayFilterOptions | undefined;
|
display_filters: IIssueDisplayFilterOptions | undefined;
|
||||||
display_properties: Properties;
|
display_properties: IIssueDisplayProperties;
|
||||||
}
|
}
|
||||||
export interface IWorkspaceGlobalViewProps {
|
export interface IWorkspaceGlobalViewProps {
|
||||||
filters: IWorkspaceIssueFilterOptions;
|
filters: IWorkspaceIssueFilterOptions;
|
||||||
display_filters: IWorkspaceIssueDisplayFilterOptions | undefined;
|
display_filters: IWorkspaceIssueDisplayFilterOptions | undefined;
|
||||||
display_properties: Properties;
|
display_properties: IIssueDisplayProperties;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user