chore: updated display properties endpoint (#2486)

This commit is contained in:
Aaryan Khandelwal 2023-10-19 14:53:01 +05:30 committed by GitHub
parent 3a44d4bf35
commit 861ff4ae94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 186 additions and 1494 deletions

View File

@ -2,4 +2,3 @@ export * from "./date-filter-modal";
export * from "./date-filter-select";
export * from "./filters-list";
export * from "./workspace-filters-list";
export * from "./issues-view-filter";

View File

@ -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>
);
};

View File

@ -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 = () => <></>;

View File

@ -1,2 +1 @@
export * from "./issues-view";
export * from "./inline-issue-create-wrapper";

View File

@ -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 = () => <></>;

View File

@ -7,14 +7,14 @@ import useToast from "hooks/use-toast";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
// types
import { IIssue, Properties } from "types";
import { IIssue, IIssueDisplayProperties } from "types";
type Props = {
issue: IIssue;
projectId: string;
expanded: boolean;
handleToggleExpand: (issueId: string) => void;
properties: Properties;
properties: IIssueDisplayProperties;
handleEditIssue: (issue: IIssue) => void;
handleDeleteIssue: (issue: IIssue) => void;
disableUserActions: boolean;

View File

@ -5,14 +5,14 @@ import { IssueColumn } from "components/issues";
// hooks
import useSubIssue from "hooks/use-sub-issue";
// types
import { IIssue, Properties } from "types";
import { IIssue, IIssueDisplayProperties } from "types";
type Props = {
issue: IIssue;
projectId: string;
expandedIssues: string[];
setExpandedIssues: React.Dispatch<React.SetStateAction<string[]>>;
properties: Properties;
properties: IIssueDisplayProperties;
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
disableUserActions: boolean;
nestingLevel?: number;

View File

@ -110,7 +110,6 @@ export const SubIssues: React.FC<ISubIssues> = ({
<div className="flex-shrink-0 text-sm">
<IssueProperty
workspaceSlug={workspaceSlug}
projectId={projectId}
parentIssue={parentIssue}
issue={issue}
user={user}

View File

@ -10,8 +10,6 @@ import { TrackEventService } from "services/track_event.service";
import { ViewDueDateSelect, ViewStartDateSelect } from "components/issues";
import { MembersSelect, PrioritySelect } from "components/project";
import { StateSelect } from "components/states";
// hooks
import useIssuesProperties from "hooks/use-issue-properties";
// types
import { IUser, IIssue, IState } from "types";
// fetch-keys
@ -19,7 +17,6 @@ import { SUB_ISSUES } from "constants/fetch-keys";
export interface IIssueProperty {
workspaceSlug: string;
projectId: string;
parentIssue: IIssue;
issue: IIssue;
user: IUser | undefined;
@ -30,153 +27,153 @@ export interface IIssueProperty {
const issueService = new IssueService();
const trackEventService = new TrackEventService();
export const IssueProperty: React.FC<IIssueProperty> = observer(
({ workspaceSlug, projectId, parentIssue, issue, user, editable }) => {
const [properties] = useIssuesProperties(workspaceSlug, projectId);
export const IssueProperty: React.FC<IIssueProperty> = observer((props) => {
const { workspaceSlug, parentIssue, issue, user, editable } = props;
const { project: projectStore } = useMobxStore();
const { project: projectStore, issueFilter: issueFilterStore } = useMobxStore();
const handlePriorityChange = (data: any) => {
partialUpdateIssue({ priority: data });
trackEventService.trackIssuePartialPropertyUpdateEvent(
{
workspaceSlug,
workspaceId: issue.workspace,
projectId: issue.project_detail.id,
projectIdentifier: issue.project_detail.identifier,
projectName: issue.project_detail.name,
issueId: issue.id,
},
"ISSUE_PROPERTY_UPDATE_PRIORITY",
user as IUser
);
};
const displayProperties = issueFilterStore.userDisplayProperties ?? {};
const handleStateChange = (data: IState) => {
partialUpdateIssue({
state: data.id,
state_detail: data,
});
trackEventService.trackIssuePartialPropertyUpdateEvent(
{
workspaceSlug,
workspaceId: issue.workspace,
projectId: issue.project_detail.id,
projectIdentifier: issue.project_detail.identifier,
projectName: issue.project_detail.name,
issueId: issue.id,
},
"ISSUE_PROPERTY_UPDATE_STATE",
user as IUser
);
};
const handleAssigneeChange = (data: string[]) => {
partialUpdateIssue({ assignees_list: data, assignees: data });
trackEventService.trackIssuePartialPropertyUpdateEvent(
{
workspaceSlug,
workspaceId: issue.workspace,
projectId: issue.project_detail.id,
projectIdentifier: issue.project_detail.identifier,
projectName: issue.project_detail.name,
issueId: issue.id,
},
"ISSUE_PROPERTY_UPDATE_ASSIGNEE",
user as IUser
);
};
const partialUpdateIssue = async (data: Partial<IIssue>) => {
mutate(
workspaceSlug && parentIssue ? SUB_ISSUES(parentIssue.id) : null,
(elements: any) => {
const _elements = { ...elements };
const _issues = _elements.sub_issues.map((element: IIssue) =>
element.id === issue.id ? { ...element, ...data } : element
);
_elements["sub_issues"] = [..._issues];
return _elements;
},
false
);
const issueResponse = await issueService.patchIssue(workspaceSlug as string, issue.project, issue.id, data, user);
mutate(
SUB_ISSUES(parentIssue.id),
(elements: any) => {
const _elements = elements.sub_issues.map((element: IIssue) =>
element.id === issue.id ? issueResponse : element
);
elements["sub_issues"] = _elements;
return elements;
},
true
);
};
return (
<div className="relative flex items-center gap-1">
{properties.priority && (
<div className="flex-shrink-0">
<PrioritySelect
value={issue.priority}
onChange={handlePriorityChange}
hideDropdownArrow
disabled={!editable}
/>
</div>
)}
{properties.state && (
<div className="flex-shrink-0">
<StateSelect
value={issue.state_detail}
stateGroups={projectStore.states ? projectStore.states[issue.project] : undefined}
onChange={(data) => handleStateChange(data)}
hideDropdownArrow
disabled={!editable}
/>
</div>
)}
{properties.start_date && issue.start_date && (
<div className="flex-shrink-0 w-[104px]">
<ViewStartDateSelect
issue={issue}
onChange={(val) => partialUpdateIssue({ start_date: val })}
disabled={!editable}
/>
</div>
)}
{properties.due_date && issue.target_date && (
<div className="flex-shrink-0 w-[104px]">
{user && (
<ViewDueDateSelect
issue={issue}
onChange={(val) => partialUpdateIssue({ target_date: val })}
disabled={!editable}
/>
)}
</div>
)}
{properties.assignee && (
<div className="flex-shrink-0">
<MembersSelect
value={issue.assignees}
onChange={(val) => handleAssigneeChange(val)}
members={projectStore.members ? (projectStore.members[issue.project] ?? []).map((m) => m.member) : []}
hideDropdownArrow
disabled={!editable}
multiple
/>
</div>
)}
</div>
const handlePriorityChange = (data: any) => {
partialUpdateIssue({ priority: data });
trackEventService.trackIssuePartialPropertyUpdateEvent(
{
workspaceSlug,
workspaceId: issue.workspace,
projectId: issue.project_detail.id,
projectIdentifier: issue.project_detail.identifier,
projectName: issue.project_detail.name,
issueId: issue.id,
},
"ISSUE_PROPERTY_UPDATE_PRIORITY",
user as IUser
);
}
);
};
const handleStateChange = (data: IState) => {
partialUpdateIssue({
state: data.id,
state_detail: data,
});
trackEventService.trackIssuePartialPropertyUpdateEvent(
{
workspaceSlug,
workspaceId: issue.workspace,
projectId: issue.project_detail.id,
projectIdentifier: issue.project_detail.identifier,
projectName: issue.project_detail.name,
issueId: issue.id,
},
"ISSUE_PROPERTY_UPDATE_STATE",
user as IUser
);
};
const handleAssigneeChange = (data: string[]) => {
partialUpdateIssue({ assignees_list: data, assignees: data });
trackEventService.trackIssuePartialPropertyUpdateEvent(
{
workspaceSlug,
workspaceId: issue.workspace,
projectId: issue.project_detail.id,
projectIdentifier: issue.project_detail.identifier,
projectName: issue.project_detail.name,
issueId: issue.id,
},
"ISSUE_PROPERTY_UPDATE_ASSIGNEE",
user as IUser
);
};
const partialUpdateIssue = async (data: Partial<IIssue>) => {
mutate(
workspaceSlug && parentIssue ? SUB_ISSUES(parentIssue.id) : null,
(elements: any) => {
const _elements = { ...elements };
const _issues = _elements.sub_issues.map((element: IIssue) =>
element.id === issue.id ? { ...element, ...data } : element
);
_elements["sub_issues"] = [..._issues];
return _elements;
},
false
);
const issueResponse = await issueService.patchIssue(workspaceSlug as string, issue.project, issue.id, data, user);
mutate(
SUB_ISSUES(parentIssue.id),
(elements: any) => {
const _elements = elements.sub_issues.map((element: IIssue) =>
element.id === issue.id ? issueResponse : element
);
elements["sub_issues"] = _elements;
return elements;
},
true
);
};
return (
<div className="relative flex items-center gap-1">
{displayProperties.priority && (
<div className="flex-shrink-0">
<PrioritySelect
value={issue.priority}
onChange={handlePriorityChange}
hideDropdownArrow
disabled={!editable}
/>
</div>
)}
{displayProperties.state && (
<div className="flex-shrink-0">
<StateSelect
value={issue.state_detail}
stateGroups={projectStore.states ? projectStore.states[issue.project] : undefined}
onChange={(data) => handleStateChange(data)}
hideDropdownArrow
disabled={!editable}
/>
</div>
)}
{displayProperties.start_date && issue.start_date && (
<div className="flex-shrink-0 w-[104px]">
<ViewStartDateSelect
issue={issue}
onChange={(val) => partialUpdateIssue({ start_date: val })}
disabled={!editable}
/>
</div>
)}
{displayProperties.due_date && issue.target_date && (
<div className="flex-shrink-0 w-[104px]">
{user && (
<ViewDueDateSelect
issue={issue}
onChange={(val) => partialUpdateIssue({ target_date: val })}
disabled={!editable}
/>
)}
</div>
)}
{displayProperties.assignee && (
<div className="flex-shrink-0">
<MembersSelect
value={issue.assignees}
onChange={(val) => handleAssigneeChange(val)}
members={projectStore.members ? (projectStore.members[issue.project] ?? []).map((m) => m.member) : []}
hideDropdownArrow
disabled={!editable}
multiple
/>
</div>
)}
</div>
);
});

View File

@ -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;

View File

@ -11,8 +11,6 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
import { IssueViewContextProvider } from "contexts/issue-view.context";
// helper
import { truncateText } from "helpers/string.helper";
// components
import { IssuesFilterView, IssuesView } from "components/core";
// ui
import { ArchiveIcon, BreadcrumbItem, Breadcrumbs } from "@plane/ui";
// icons
@ -51,11 +49,11 @@ const ProjectArchivedIssues: NextPage = () => {
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Archived Issues`} />
</Breadcrumbs>
}
right={
<div className="flex items-center gap-2">
<IssuesFilterView />
</div>
}
// right={
// <div className="flex items-center gap-2">
// <IssuesFilterView />
// </div>
// }
>
<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">
@ -70,7 +68,7 @@ const ProjectArchivedIssues: NextPage = () => {
<X className="h-3 w-3" />
</button>
</div>
<IssuesView />
{/* <IssuesView /> */}
</div>
</ProjectAuthorizationWrapper>
</IssueViewContextProvider>

View File

@ -11,8 +11,6 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
import { IssueViewContextProvider } from "contexts/issue-view.context";
// helper
import { truncateText } from "helpers/string.helper";
// components
import { IssuesFilterView, IssuesView } from "components/core";
// ui
import { BreadcrumbItem, Breadcrumbs } from "@plane/ui";
// icons
@ -51,11 +49,11 @@ const ProjectDraftIssues: NextPage = () => {
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Draft Issues`} />
</Breadcrumbs>
}
right={
<div className="flex items-center gap-2">
<IssuesFilterView />
</div>
}
// right={
// <div className="flex items-center gap-2">
// <IssuesFilterView />
// </div>
// }
>
<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">
@ -70,7 +68,6 @@ const ProjectDraftIssues: NextPage = () => {
<X className="h-3 w-3" />
</button>
</div>
<IssuesView />
</div>
</ProjectAuthorizationWrapper>
</IssueViewContextProvider>

View File

@ -2,7 +2,7 @@
import { APIService } from "services/api.service";
import { TrackEventService } from "services/track_event.service";
// type
import type { IUser, IIssue, IIssueActivity, ISubIssueResponse } from "types";
import type { IUser, IIssue, IIssueActivity, ISubIssueResponse, IIssueDisplayProperties } from "types";
// 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(
workspaceSlug: string,
projectId: string,
@ -153,24 +145,20 @@ export class IssueService extends APIService {
});
}
async createIssueProperties(workspaceSlug: string, projectId: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/`, data)
async getIssueDisplayProperties(workspaceSlug: string, projectId: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-display-properties/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchIssueProperties(
async patchIssueDisplayProperties(
workspaceSlug: string,
projectId: string,
issuePropertyId: string,
data: any
data: IIssueDisplayProperties
): Promise<any> {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/` + `${issuePropertyId}/`,
data
)
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-display-properties/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;

View File

@ -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[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-members/`)
.then((response) => response?.data)

View File

@ -45,7 +45,7 @@ export class IssueFilterStore implements IIssueFilterStore {
error: any | null = null;
// observables
userDisplayProperties: any = {};
userDisplayProperties: IIssueDisplayProperties = {};
userDisplayFilters: IIssueDisplayFilterOptions = {};
userFilters: IIssueFilterOptions = {};
defaultDisplayFilters: IIssueDisplayFilterOptions = {};
@ -144,7 +144,7 @@ export class IssueFilterStore implements IIssueFilterStore {
fetchUserProjectFilters = async (workspaceSlug: string, projectId: string) => {
try {
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(() => {
this.userFilters = memberResponse?.view_props?.filters;
@ -207,7 +207,7 @@ export class IssueFilterStore implements IIssueFilterStore {
projectId: string,
properties: Partial<IIssueDisplayProperties>
) => {
const newProperties = {
const newProperties: IIssueDisplayProperties = {
...this.userDisplayProperties,
...properties,
};
@ -217,7 +217,7 @@ export class IssueFilterStore implements IIssueFilterStore {
this.userDisplayProperties = newProperties;
});
// await this.issueService.patchIssueProperties(workspaceSlug, projectId, newProperties);
await this.issueService.patchIssueDisplayProperties(workspaceSlug, projectId, newProperties);
} catch (error) {
this.fetchUserProjectFilters(workspaceSlug, projectId);

View File

@ -84,19 +84,19 @@ export interface IIssueDisplayFilterOptions {
type?: TIssueTypeFilters;
}
export interface IIssueDisplayProperties {
assignee: boolean;
start_date: boolean;
due_date: boolean;
labels: boolean;
key: boolean;
priority: boolean;
state: boolean;
sub_issue_count: boolean;
link: boolean;
attachment_count: boolean;
estimate: boolean;
created_on: boolean;
updated_on: boolean;
assignee?: boolean;
start_date?: boolean;
due_date?: boolean;
labels?: boolean;
key?: boolean;
priority?: boolean;
state?: boolean;
sub_issue_count?: boolean;
link?: boolean;
attachment_count?: boolean;
estimate?: boolean;
created_on?: boolean;
updated_on?: boolean;
}
export interface IWorkspaceIssueFilterOptions {
@ -142,10 +142,10 @@ export interface IProjectViewProps {
export interface IWorkspaceViewProps {
filters: IIssueFilterOptions;
display_filters: IIssueDisplayFilterOptions | undefined;
display_properties: Properties;
display_properties: IIssueDisplayProperties;
}
export interface IWorkspaceGlobalViewProps {
filters: IWorkspaceIssueFilterOptions;
display_filters: IWorkspaceIssueDisplayFilterOptions | undefined;
display_properties: Properties;
display_properties: IIssueDisplayProperties;
}