chore: code refactor and build fix (#6285)

* chore: code refactor and build fix

* chore: code refactor

* chore: code refactor
This commit is contained in:
Anmol Singh Bhatia 2024-12-27 18:18:45 +05:30 committed by GitHub
parent 3c6bbaef3c
commit 211d5e1cd0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 292 additions and 101 deletions

View file

@ -11,7 +11,6 @@ import { PROJECT_ERROR_MESSAGES } from "@/constants/project";
import { useIssues, useProject, useUser, useUserPermissions } from "@/hooks/store";
// plane-web
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
type Props = {
isOpen: boolean;
handleClose: () => void;
@ -19,10 +18,11 @@ type Props = {
data?: TIssue | TDeDupeIssue;
isSubIssue?: boolean;
onSubmit?: () => Promise<void>;
isEpic?: boolean;
};
export const DeleteIssueModal: React.FC<Props> = (props) => {
const { dataId, data, isOpen, handleClose, isSubIssue = false, onSubmit } = props;
const { dataId, data, isOpen, handleClose, isSubIssue = false, onSubmit, isEpic = false } = props;
// states
const [isDeleting, setIsDeleting] = useState(false);
// store hooks
@ -70,12 +70,14 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: `${isSubIssue ? "Sub-issue" : "Issue"} deleted successfully`,
message: `${isSubIssue ? "Sub-issue" : isEpic ? "Epic" : "Issue"} deleted successfully`,
});
onClose();
})
.catch((errors) => {
const isPermissionError = errors?.error === "Only admin or creator can delete the issue";
const isPermissionError =
errors?.error ===
`Only admin or creator can delete the ${isSubIssue ? "sub-issue" : isEpic ? "epic" : "issue"}`;
const currentError = isPermissionError
? PROJECT_ERROR_MESSAGES.permissionError
: PROJECT_ERROR_MESSAGES.issueDeleteError;
@ -94,14 +96,14 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
handleSubmit={handleIssueDelete}
isSubmitting={isDeleting}
isOpen={isOpen}
title="Delete issue"
title={`Delete ${isEpic ? "epic" : "issue"}`}
content={
<>
Are you sure you want to delete issue{" "}
{`Are you sure you want to delete ${isEpic ? "epic" : "issue"} `}
<span className="break-words font-medium text-custom-text-100">
{projectDetails?.identifier}-{issue?.sequence_id}
</span>
{""}? All of the data related to the issue will be permanently removed. This action cannot be undone.
{` ? All of the data related to the ${isEpic ? "epic" : "issue"} will be permanently removed. This action cannot be undone.`}
</>
}
/>

View file

@ -123,6 +123,7 @@ const HeaderFilters = observer((props: Props) => {
states={projectStates}
cycleViewDisabled={!currentProjectDetails?.cycle_view}
moduleViewDisabled={!currentProjectDetails?.module_view}
isEpic={storeType === EIssuesStoreType.EPIC}
/>
</FiltersDropdown>
<FiltersDropdown title="Display" placement="bottom-end">
@ -134,6 +135,7 @@ const HeaderFilters = observer((props: Props) => {
handleDisplayPropertiesUpdate={handleDisplayProperties}
cycleViewDisabled={!currentProjectDetails?.cycle_view}
moduleViewDisabled={!currentProjectDetails?.module_view}
isEpic={storeType === EIssuesStoreType.EPIC}
/>
</FiltersDropdown>
{canUserCreateIssue ? (

View file

@ -53,11 +53,10 @@ export const SubIssuesCollapsibleContent: FC<Props> = observer((props) => {
},
});
// store hooks
const { toggleCreateIssueModal, toggleDeleteIssueModal } = useIssueDetail();
const {
subIssues: { subIssueHelpersByIssueId, setSubIssueHelpers },
toggleCreateIssueModal,
toggleDeleteIssueModal,
} = useIssueDetail();
} = useIssueDetail(issueServiceType);
// helpers
const subIssueOperations = useSubIssueOperations(issueServiceType);

View file

@ -38,7 +38,7 @@ export const SubIssuesCollapsibleTitle: FC<Props> = observer((props) => {
return (
<CollapsibleButton
isOpen={isOpen}
title="Sub-issues"
title={`${issueServiceType === EIssueServiceType.EPICS ? "Issues" : "Sub-issues"}`}
indicatorElement={
<div className="flex items-center gap-1.5 text-custom-text-300 text-sm">
<CircularProgressIndicator size={18} percentage={percentage} strokeWidth={3} />

View file

@ -9,18 +9,24 @@ import { cn } from "@/helpers/common.helper";
export type TActivitySortRoot = {
sortOrder: "asc" | "desc";
toggleSort: () => void;
className?: string;
iconClassName?: string;
};
export const ActivitySortRoot: FC<TActivitySortRoot> = memo((props) => (
<div
className={cn(getButtonStyling("neutral-primary", "sm"), "px-2 text-custom-text-300 cursor-pointer")}
className={cn(
getButtonStyling("neutral-primary", "sm"),
"px-2 text-custom-text-300 cursor-pointer",
props.className
)}
onClick={() => {
props.toggleSort();
}}
>
{props.sortOrder === "asc" ? (
<ArrowUpWideNarrow className="size-4 " />
<ArrowUpWideNarrow className={cn("size-4", props.iconClassName)} />
) : (
<ArrowDownWideNarrow className="size-4 " />
<ArrowDownWideNarrow className={cn("size-4", props.iconClassName)} />
)}
</div>
));

View file

@ -50,7 +50,7 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
const { workspaceSlug } = useParams();
// hooks
const storeType = useIssueStoreType() as CalendarStoreType;
const storeType = isEpic ? EIssuesStoreType.EPIC : (useIssueStoreType() as CalendarStoreType);
const { allowPermissions } = useUserPermissions();
const { issues, issuesFilter, issueMap } = useIssues(storeType);
const {

View file

@ -87,6 +87,7 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
}}
quickAddCallback={quickAddCallback}
addIssuesToView={addIssuesToView}
isEpic={isEpic}
/>
</div>
)}

View file

@ -25,6 +25,7 @@ type Props = {
ignoreGroupedFilters?: Partial<TIssueGroupByOptions>[];
cycleViewDisabled?: boolean;
moduleViewDisabled?: boolean;
isEpic?: boolean;
};
export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
@ -37,6 +38,7 @@ export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
ignoreGroupedFilters = [],
cycleViewDisabled = false,
moduleViewDisabled = false,
isEpic = false,
} = props;
const isDisplayFilterEnabled = (displayFilter: keyof IIssueDisplayFilterOptions) =>
@ -61,6 +63,7 @@ export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
handleUpdate={handleDisplayPropertiesUpdate}
cycleViewDisabled={cycleViewDisabled}
moduleViewDisabled={moduleViewDisabled}
isEpic={isEpic}
/>
</div>
)}

View file

@ -16,6 +16,7 @@ type Props = {
handleUpdate: (updatedDisplayProperties: Partial<IIssueDisplayProperties>) => void;
cycleViewDisabled?: boolean;
moduleViewDisabled?: boolean;
isEpic?: boolean;
};
export const FilterDisplayProperties: React.FC<Props> = observer((props) => {
@ -25,6 +26,7 @@ export const FilterDisplayProperties: React.FC<Props> = observer((props) => {
handleUpdate,
cycleViewDisabled = false,
moduleViewDisabled = false,
isEpic = false,
} = props;
// router
const { workspaceSlug, projectId: routerProjectId } = useParams();
@ -45,6 +47,11 @@ export const FilterDisplayProperties: React.FC<Props> = observer((props) => {
default:
return shouldRenderDisplayProperty({ workspaceSlug: workspaceSlug?.toString(), projectId, key: property.key });
}
}).map((property) => {
if (isEpic && property.key === "sub_issue_count") {
return { ...property, title: "Issue count" };
}
return property;
});
return (

View file

@ -11,10 +11,11 @@ import { ISSUE_FILTER_OPTIONS } from "@/constants/issue";
type Props = {
selectedIssueType: TIssueGroupingFilters | undefined;
handleUpdate: (val: TIssueGroupingFilters) => void;
isEpic?: boolean;
};
export const FilterIssueGrouping: React.FC<Props> = observer((props) => {
const { selectedIssueType, handleUpdate } = props;
const { selectedIssueType, handleUpdate, isEpic = false } = props;
const [previewEnabled, setPreviewEnabled] = React.useState(true);
@ -23,7 +24,7 @@ export const FilterIssueGrouping: React.FC<Props> = observer((props) => {
return (
<>
<FilterHeader
title="Issue Grouping"
title={`${isEpic ? "Epic" : "Issue"} Grouping`}
isPreviewEnabled={previewEnabled}
handleIsPreviewEnabled={() => setPreviewEnabled(!previewEnabled)}
/>
@ -34,7 +35,7 @@ export const FilterIssueGrouping: React.FC<Props> = observer((props) => {
key={issueType?.key}
isChecked={activeIssueType === issueType?.key ? true : false}
onClick={() => handleUpdate(issueType?.key)}
title={issueType.title}
title={`${issueType.title} ${isEpic ? "Epics" : "Issues"}`}
multiple={false}
/>
))}

View file

@ -42,6 +42,7 @@ type Props = {
states?: IState[] | undefined;
cycleViewDisabled?: boolean;
moduleViewDisabled?: boolean;
isEpic?: boolean;
};
export const FilterSelection: React.FC<Props> = observer((props) => {
@ -56,6 +57,7 @@ export const FilterSelection: React.FC<Props> = observer((props) => {
states,
cycleViewDisabled = false,
moduleViewDisabled = false,
isEpic = false,
} = props;
// hooks
const { isMobile } = usePlatformOS();
@ -234,6 +236,7 @@ export const FilterSelection: React.FC<Props> = observer((props) => {
type: val,
})
}
isEpic={isEpic}
/>
</div>
)}

View file

@ -111,6 +111,7 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
target_date: renderFormattedPayloadDate(targetDate),
}}
quickAddCallback={quickAddIssue}
isEpic={isEpic}
/>
) : undefined;
@ -120,8 +121,8 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
<div className="h-full w-full">
<GanttChartRoot
border={false}
title="Issues"
loaderTitle="Issues"
title={isEpic ? "Epics" : "Issues"}
loaderTitle={isEpic ? "Epics" : "Issues"}
blockIds={issuesIds}
blockUpdateHandler={updateIssueBlockStructure}
blockToRender={(data: TIssue) => <IssueGanttBlock issueId={data.id} isEpic={isEpic} />}

View file

@ -16,6 +16,7 @@ type Props = {
dropErrorMessage?: string;
orderBy: TIssueOrderByOptions | undefined;
isDraggingOverColumn: boolean;
isEpic?: boolean;
};
export const GroupDragOverlay = (props: Props) => {
@ -27,6 +28,7 @@ export const GroupDragOverlay = (props: Props) => {
dropErrorMessage,
orderBy,
isDraggingOverColumn,
isEpic = false,
} = props;
const shouldOverlayBeVisible = isDraggingOverColumn && canOverlayBeVisible;
@ -68,7 +70,7 @@ export const GroupDragOverlay = (props: Props) => {
The layout is ordered by <span className="font-semibold">{readableOrderBy}</span>.
</span>
)}
<span>Drop here to move the issue.</span>
<span>{`Drop here to move the ${isEpic ? "epic" : "issue"}.`}</span>
</>
)}
</div>

View file

@ -284,6 +284,7 @@ export const ListGroup = observer((props: Props) => {
dropErrorMessage={group.dropErrorMessage}
orderBy={orderBy}
isDraggingOverColumn={isDraggingOverColumn}
isEpic={isEpic}
/>
{groupIssueIds && (
<IssueBlocksList
@ -312,6 +313,7 @@ export const ListGroup = observer((props: Props) => {
prePopulatedData={prePopulateQuickAddData(group_by, group.id)}
containerClassName="border-b border-t border-custom-border-200 bg-custom-background-100 "
quickAddCallback={quickAddCallback}
isEpic={isEpic}
/>
</div>
)}

View file

@ -1,6 +1,6 @@
"use client";
import { useCallback, useMemo } from "react";
import { useCallback, useMemo, SyntheticEvent } from "react";
import xor from "lodash/xor";
import { observer } from "mobx-react";
import { useParams, usePathname } from "next/navigation";
@ -245,7 +245,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
const redirectToIssueDetail = () => {
router.push(
`/${workspaceSlug}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${issue.id}#sub-issues`
`/${workspaceSlug}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}${isEpic ? "epics" : "issues"}/${issue.id}#sub-issues`
);
// router.push({
// pathname: `/${workspaceSlug}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${
@ -265,7 +265,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
const maxDate = getDate(issue.target_date);
maxDate?.setDate(maxDate.getDate());
const handleEventPropagation = (e: React.MouseEvent) => {
const handleEventPropagation = (e: SyntheticEvent<HTMLDivElement>) => {
e.stopPropagation();
e.preventDefault();
};
@ -275,7 +275,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
{/* basic properties */}
{/* state */}
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="state">
<div className="h-5" onClick={handleEventPropagation}>
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
<StateDropdown
buttonContainerClassName="truncate max-w-40"
value={issue.state_id}
@ -291,7 +291,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
{/* priority */}
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="priority">
<div className="h-5" onClick={handleEventPropagation}>
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
<PriorityDropdown
value={issue?.priority}
onChange={handlePriority}
@ -306,7 +306,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
{/* start date */}
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="start_date">
<div className="h-5" onClick={handleEventPropagation}>
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
<DateDropdown
value={issue.start_date ?? null}
onChange={handleStartDate}
@ -324,7 +324,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
{/* target/due date */}
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="due_date">
<div className="h-5" onClick={handleEventPropagation}>
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
<DateDropdown
value={issue?.target_date ?? null}
onChange={handleTargetDate}
@ -344,7 +344,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
{/* assignee */}
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="assignee">
<div className="h-5" onClick={handleEventPropagation}>
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
<MemberDropdown
projectId={issue?.project_id}
value={issue?.assignee_ids}
@ -362,52 +362,54 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
</div>
</WithDisplayPropertiesHOC>
{!isEpic && (
<>
{/* modules */}
{projectDetails?.module_view && (
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="modules">
<div className="h-5" onClick={handleEventPropagation}>
<ModuleDropdown
buttonContainerClassName="truncate max-w-40"
projectId={issue?.project_id}
value={issue?.module_ids ?? []}
onChange={handleModule}
disabled={isReadOnly}
renderByDefault={isMobile}
multiple
buttonVariant="border-with-text"
showCount
showTooltip
/>
</div>
</WithDisplayPropertiesHOC>
)}
<>
{!isEpic && (
<>
{/* modules */}
{projectDetails?.module_view && (
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="modules">
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
<ModuleDropdown
buttonContainerClassName="truncate max-w-40"
projectId={issue?.project_id}
value={issue?.module_ids ?? []}
onChange={handleModule}
disabled={isReadOnly}
renderByDefault={isMobile}
multiple
buttonVariant="border-with-text"
showCount
showTooltip
/>
</div>
</WithDisplayPropertiesHOC>
)}
{/* cycles */}
{projectDetails?.cycle_view && (
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="cycle">
<div className="h-5" onClick={handleEventPropagation}>
<CycleDropdown
buttonContainerClassName="truncate max-w-40"
projectId={issue?.project_id}
value={issue?.cycle_id}
onChange={handleCycle}
disabled={isReadOnly}
buttonVariant="border-with-text"
renderByDefault={isMobile}
showTooltip
/>
</div>
</WithDisplayPropertiesHOC>
)}
</>
)}
{/* cycles */}
{projectDetails?.cycle_view && (
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="cycle">
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
<CycleDropdown
buttonContainerClassName="truncate max-w-40"
projectId={issue?.project_id}
value={issue?.cycle_id}
onChange={handleCycle}
disabled={isReadOnly}
buttonVariant="border-with-text"
renderByDefault={isMobile}
showTooltip
/>
</div>
</WithDisplayPropertiesHOC>
)}
</>
)}
</>
{/* estimates */}
{projectId && areEstimateEnabledByProjectId(projectId?.toString()) && (
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="estimate">
<div className="h-5" onClick={handleEventPropagation}>
<div className="h-5" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
<EstimateDropdown
value={issue.estimate_point ?? undefined}
onChange={handleEstimate}
@ -429,12 +431,13 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
shouldRenderProperty={(properties) => !!properties.sub_issue_count && !!subIssueCount}
>
<Tooltip
tooltipHeading="Sub-issues"
tooltipHeading={isEpic ? "Issues" : "Sub-issues"}
tooltipContent={`${subIssueCount}`}
isMobile={isMobile}
renderByDefault={false}
>
<div
onFocus={handleEventPropagation}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
@ -467,6 +470,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
>
<div
className="flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1"
onFocus={handleEventPropagation}
onClick={handleEventPropagation}
>
<Paperclip className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
@ -489,6 +493,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
>
<div
className="flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1"
onFocus={handleEventPropagation}
onClick={handleEventPropagation}
>
<Link className="h-3 w-3 flex-shrink-0" strokeWidth={2} />

View file

@ -5,7 +5,7 @@ import { Row } from "@plane/ui";
import { TQuickAddIssueButton } from "../root";
export const GanttQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((props) => {
const { onClick } = props;
const { onClick, isEpic = false } = props;
return (
<button
@ -15,7 +15,7 @@ export const GanttQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((prop
>
<Row className="flex py-2 gap-2">
<PlusIcon className="h-3.5 w-3.5 stroke-2 my-auto" />
<span className="text-sm font-medium">New Issue</span>
<span className="text-sm font-medium">{`New ${isEpic ? "Epic" : "Issue"}`}</span>
</Row>
</button>
);

View file

@ -4,7 +4,7 @@ import { PlusIcon } from "lucide-react";
import { TQuickAddIssueButton } from "../root";
export const KanbanQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((props) => {
const { onClick } = props;
const { onClick, isEpic = false } = props;
return (
<div
@ -12,7 +12,7 @@ export const KanbanQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((pro
onClick={onClick}
>
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
<span className="text-sm font-medium">New Issue</span>
<span className="text-sm font-medium">{`New ${isEpic ? "Epic" : "Issue"}`}</span>
</div>
);
});

View file

@ -5,7 +5,7 @@ import { Row } from "@plane/ui";
import { TQuickAddIssueButton } from "../root";
export const ListQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((props) => {
const { onClick } = props;
const { onClick, isEpic = false } = props;
return (
<Row
@ -13,7 +13,7 @@ export const ListQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((props
onClick={onClick}
>
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
<span className="text-sm font-medium">New Issue</span>
<span className="text-sm font-medium">{`New ${isEpic ? "Epic" : "Issue"}`}</span>
</Row>
);
});

View file

@ -4,7 +4,7 @@ import { PlusIcon } from "lucide-react";
import { TQuickAddIssueButton } from "../root";
export const SpreadsheetAddIssueButton: FC<TQuickAddIssueButton> = observer((props) => {
const { onClick } = props;
const { onClick, isEpic = false } = props;
return (
<div className="flex items-center">
@ -14,7 +14,7 @@ export const SpreadsheetAddIssueButton: FC<TQuickAddIssueButton> = observer((pro
onClick={onClick}
>
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
<span className="text-sm font-medium">New Issue</span>
<span className="text-sm font-medium">{`New ${isEpic ? "Epic" : "Issue"}`}</span>
</button>
</div>
);

View file

@ -15,10 +15,11 @@ interface Props {
displayFilters: IIssueDisplayFilterOptions;
handleDisplayFilterUpdate: (data: Partial<IIssueDisplayFilterOptions>) => void;
onClose: () => void;
isEpic?: boolean;
}
export const HeaderColumn = (props: Props) => {
const { displayFilters, handleDisplayFilterUpdate, property, onClose } = props;
const { displayFilters, handleDisplayFilterUpdate, property, onClose, isEpic = false } = props;
const { storedValue: selectedMenuItem, setValue: setSelectedMenuItem } = useLocalStorage(
"spreadsheetViewSorting",
@ -46,7 +47,7 @@ export const HeaderColumn = (props: Props) => {
<Row className="flex w-full cursor-pointer items-center justify-between gap-1.5 py-2 text-sm text-custom-text-200 hover:text-custom-text-100">
<div className="flex items-center gap-1.5">
{<propertyDetails.icon className="h-4 w-4 text-custom-text-400" />}
{propertyDetails.title}
{propertyDetails.title === "Sub-issue" && isEpic ? "Issues" : propertyDetails.title}
</div>
<div className="ml-3 flex">
{activeSortingProperty === property && (

View file

@ -18,16 +18,19 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
// router
const router = useAppRouter();
// hooks
const { workspaceSlug } = useParams();
const { workspaceSlug, epicId } = useParams();
// derived values
const subIssueCount = issue?.sub_issues_count ?? 0;
const redirectToIssueDetail = () => {
router.push(
`/${workspaceSlug?.toString()}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${issue.id}#sub-issues`
`/${workspaceSlug?.toString()}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}${epicId ? "epics" : "issues"}/${issue.id}#sub-issues`
);
};
const issueLabel = epicId ? "issue" : "sub-issue";
const label = `${subIssueCount} ${issueLabel}${subIssueCount !== 1 ? "s" : ""}`;
return (
<Row
onClick={subIssueCount ? redirectToIssueDetail : () => {}}
@ -38,7 +41,7 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
}
)}
>
{subIssueCount} {subIssueCount === 1 ? "sub-issue" : "sub-issues"}
{label}
</Row>
);
});

View file

@ -12,9 +12,17 @@ interface Props {
isEstimateEnabled: boolean;
displayFilters: IIssueDisplayFilterOptions;
handleDisplayFilterUpdate: (data: Partial<IIssueDisplayFilterOptions>) => void;
isEpic?: boolean;
}
export const SpreadsheetHeaderColumn = observer((props: Props) => {
const { displayProperties, displayFilters, property, isEstimateEnabled, handleDisplayFilterUpdate } = props;
const {
displayProperties,
displayFilters,
property,
isEstimateEnabled,
handleDisplayFilterUpdate,
isEpic = false,
} = props;
//hooks
const tableHeaderCellRef = useRef<HTMLTableCellElement | null>(null);
@ -39,6 +47,7 @@ export const SpreadsheetHeaderColumn = observer((props: Props) => {
onClose={() => {
tableHeaderCellRef?.current?.focus();
}}
isEpic={isEpic}
/>
</th>
</WithDisplayPropertiesHOC>

View file

@ -21,6 +21,7 @@ interface Props {
isEstimateEnabled: boolean;
spreadsheetColumnsList: (keyof IIssueDisplayProperties)[];
selectionHelpers: TSelectionHelper;
isEpic?: boolean;
}
export const SpreadsheetHeader = observer((props: Props) => {
@ -32,6 +33,7 @@ export const SpreadsheetHeader = observer((props: Props) => {
isEstimateEnabled,
spreadsheetColumnsList,
selectionHelpers,
isEpic = false,
} = props;
// router
const { projectId } = useParams();
@ -62,7 +64,7 @@ export const SpreadsheetHeader = observer((props: Props) => {
/>
</div>
)}
<span className="flex h-full w-full flex-grow items-center py-2.5">Issues</span>
<span className="flex h-full w-full flex-grow items-center py-2.5">{`${isEpic ? "Epics" : "Issues"}`}</span>
</Row>
</th>
@ -74,6 +76,7 @@ export const SpreadsheetHeader = observer((props: Props) => {
displayFilters={displayFilters}
handleDisplayFilterUpdate={handleDisplayFilterUpdate}
isEstimateEnabled={isEstimateEnabled}
isEpic={isEpic}
/>
))}
</tr>

View file

@ -112,6 +112,7 @@ export const SpreadsheetTable = observer((props: Props) => {
isEstimateEnabled={isEstimateEnabled}
spreadsheetColumnsList={spreadsheetColumnsList}
selectionHelpers={selectionHelpers}
isEpic={isEpic}
/>
<tbody>
{issueIds.map((id) => (

View file

@ -117,6 +117,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
layout={EIssueLayoutTypes.SPREADSHEET}
QuickAddButton={SpreadsheetAddIssueButton}
quickAddCallback={quickAddCallback}
isEpic={isEpic}
/>
)}
</div>

View file

@ -69,7 +69,7 @@ export const ParentIssuesListModal: React.FC<Props> = ({
projectService
.projectIssuesSearch(workspaceSlug as string, projectId as string, {
search: debouncedSearchTerm,
parent: true,
parent: searchEpic ? undefined : true,
issue_id: issueId,
workspace_search: false,
epic: searchEpic ? true : undefined,

View file

@ -60,6 +60,7 @@ export const IssueList: FC<IIssueList> = observer((props) => {
disabled={disabled}
handleIssueCrudState={handleIssueCrudState}
subIssueOperations={subIssueOperations}
issueServiceType={issueServiceType}
/>
</Fragment>
))}