fix: issue stats refactor (#6705)

* fix: issue stats refactor

* fix: refactor

* fix: ui color

* fix: translation key
This commit is contained in:
Akshita Goyal 2025-03-06 13:44:37 +05:30 committed by GitHub
parent f01d82ad1e
commit 44af90dc6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 98 additions and 53 deletions

View file

@ -814,7 +814,8 @@
"sub_issue_count": "Sub-work item count",
"attachment_count": "Attachment count",
"created_on": "Created on",
"sub_issue": "Sub-work item"
"sub_issue": "Sub-work item",
"work_item_count": "Work item count"
},
"extra": {
"show_sub_issues": "Show sub-work items",

View file

@ -985,7 +985,8 @@
"sub_issue_count": "Cantidad de sub-elementos",
"attachment_count": "Cantidad de archivos adjuntos",
"created_on": "Creado el",
"sub_issue": "Sub-elemento de trabajo"
"sub_issue": "Sub-elemento de trabajo",
"work_item_count": "Recuento de elementos de trabajo"
},
"extra": {
"show_sub_issues": "Mostrar sub-elementos",

View file

@ -983,7 +983,8 @@
"sub_issue_count": "Nombre de sous-éléments",
"attachment_count": "Nombre de pièces jointes",
"created_on": "Créé le",
"sub_issue": "Sous-élément de travail"
"sub_issue": "Sous-élément de travail",
"work_item_count": "Nombre d'éléments de travail"
},
"extra": {
"show_sub_issues": "Afficher les sous-éléments",

View file

@ -980,8 +980,9 @@
"sub_issue_count": "Numero di sotto-elementi di lavoro",
"attachment_count": "Numero di allegati",
"created_on": "Creato il",
"sub_issue": "Sotto-elemento di lavoro"
},
"sub_issue": "Sotto-elemento di lavoro",
"work_item_count": "Conteggio degli elementi di lavoro"
},
"extra": {
"show_sub_issues": "Mostra sotto-elementi di lavoro",
"show_empty_groups": "Mostra gruppi vuoti"

View file

@ -983,8 +983,9 @@
"sub_issue_count": "サブ作業項目数",
"attachment_count": "添付ファイル数",
"created_on": "作成日",
"sub_issue": "サブ作業項目"
},
"sub_issue": "サブ作業項目",
"work_item_count": "作業項目数"
},
"extra": {
"show_sub_issues": "サブ作業項目を表示",
"show_empty_groups": "空のグループを表示"

View file

@ -982,7 +982,8 @@
"sub_issue_count": "Количество подэлементов",
"attachment_count": "Количество вложений",
"created_on": "Дата создания",
"sub_issue": "Подэлемент"
"sub_issue": "Подэлемент",
"work_item_count": "Количество рабочих элементов"
},
"extra": {
"show_sub_issues": "Показывать подэлементы",

View file

@ -983,7 +983,8 @@
"sub_issue_count": "子工作项数量",
"attachment_count": "附件数量",
"created_on": "创建于",
"sub_issue": "子工作项"
"sub_issue": "子工作项",
"work_item_count": "工作项数量"
},
"extra": {
"show_sub_issues": "显示子工作项",

View file

@ -4,9 +4,10 @@ import React, { FC } from "react";
type Props = {
issueId: string;
className?: string;
size?: number;
showProgressText?: boolean;
showLabel?: boolean;
};
export const IssueStats: FC<Props> = (props) => {
const { issueId } = props;
return <></>;
};
export const IssueStats: FC<Props> = (props) => <></>;

View file

@ -53,7 +53,7 @@ export const FilterDisplayProperties: React.FC<Props> = observer((props) => {
}
}).map((property) => {
if (isEpic && property.key === "sub_issue_count") {
return { ...property, title: "Work item count" };
return { ...property, titleTranslationKey: "issue.display.properties.work_item_count" };
}
return property;
});

View file

@ -5,9 +5,9 @@ import { useParams } from "next/navigation";
// ui
import { Tooltip, ControlLink } from "@plane/ui";
// components
import { findTotalDaysInRange } from "@plane/utils";
import { SIDEBAR_WIDTH } from "@/components/gantt-chart/constants";
// helpers
import { renderFormattedDate } from "@/helpers/date-time.helper";
import { generateWorkItemLink } from "@/helpers/issue.helper";
// hooks
import { useIssueDetail, useIssues, useProject, useProjectState } from "@/hooks/store";
@ -17,6 +17,7 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
//
import { IssueStats } from "@/plane-web/components/issues/issue-layouts/issue-stats";
import { getBlockViewDetails } from "../utils";
import { GanttStoreType } from "./base-gantt-root";
@ -48,6 +49,8 @@ export const IssueGanttBlock: React.FC<Props> = observer((props) => {
const handleIssuePeekOverview = () => handleRedirection(workspaceSlug, issueDetails, isMobile);
const duration = findTotalDaysInRange(issueDetails?.start_date, issueDetails?.target_date) || 0;
return (
<Tooltip
isMobile={isMobile}
@ -62,17 +65,24 @@ export const IssueGanttBlock: React.FC<Props> = observer((props) => {
>
<div
id={`issue-${issueId}`}
className="relative flex h-full w-full cursor-pointer items-center rounded"
className="relative flex h-full w-full cursor-pointer items-center rounded space-between"
style={blockStyle}
onClick={handleIssuePeekOverview}
>
<div className="absolute left-0 top-0 h-full w-full bg-custom-background-100/50" />
<div className="absolute left-0 top-0 h-full w-full bg-custom-background-100/50 " />
<div
className="sticky w-auto overflow-hidden truncate px-2.5 py-1 text-sm text-custom-text-100"
className="sticky w-auto overflow-hidden truncate px-2.5 py-1 text-sm text-custom-text-100 flex-1"
style={{ left: `${SIDEBAR_WIDTH}px` }}
>
{issueDetails?.name}
</div>
{isEpic && (
<IssueStats
issueId={issueId}
className="sticky mx-2 font-medium text-custom-text-100 overflow-hidden truncate w-auto justify-end flex-shrink-0"
showProgressText={duration >= 2}
/>
)}
</div>
</Tooltip>
);

View file

@ -25,8 +25,10 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// local components
import { IssueStats } from "@/plane-web/components/issues/issue-layouts/issue-stats";
import { TRenderQuickActions } from "../list/list-view-types";
import { IssueProperties } from "../properties/all-properties";
import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC";
import { getIssueBlockId } from "../utils";
interface IssueBlockProps {
@ -61,6 +63,9 @@ const KanbanIssueDetailsBlock: React.FC<IssueDetailsBlockProps> = observer((prop
// hooks
const { isMobile } = usePlatformOS();
// derived values
const subIssueCount = issue?.sub_issues_count ?? 0;
const handleEventPropagation = (e: React.MouseEvent) => {
e.stopPropagation();
e.preventDefault();
@ -105,6 +110,16 @@ const KanbanIssueDetailsBlock: React.FC<IssueDetailsBlockProps> = observer((prop
isReadOnly={isReadOnly}
isEpic={isEpic}
/>
{isEpic && displayProperties && (
<WithDisplayPropertiesHOC
displayProperties={displayProperties}
displayPropertyKey="sub_issue_count"
shouldRenderProperty={(properties) => !!properties.sub_issue_count && !!subIssueCount}
>
<IssueStats issueId={issue.id} className="mt-2 font-medium text-custom-text-350" />
</WithDisplayPropertiesHOC>
)}
</>
);
});

View file

@ -25,6 +25,7 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
import { IssueIdentifier } from "@/plane-web/components/issues";
import { IssueStats } from "@/plane-web/components/issues/issue-layouts/issue-stats";
// types
import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC";
import { TRenderQuickActions } from "./list-view-types";
interface IssueBlockProps {
@ -269,7 +270,15 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
>
<p className="truncate cursor-pointer text-sm text-custom-text-100">{issue.name}</p>
</Tooltip>
{isEpic && <IssueStats issueId={issue.id} />}
{isEpic && displayProperties && (
<WithDisplayPropertiesHOC
displayProperties={displayProperties}
displayPropertyKey="sub_issue_count"
shouldRenderProperty={(properties) => !!properties.sub_issue_count}
>
<IssueStats issueId={issue.id} className="ml-2 font-medium text-custom-text-350" />
</WithDisplayPropertiesHOC>
)}
</div>
{!issue?.tempId && (
<div

View file

@ -429,36 +429,38 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
{/* extra render properties */}
{/* sub-issues */}
<WithDisplayPropertiesHOC
displayProperties={displayProperties}
displayPropertyKey="sub_issue_count"
shouldRenderProperty={(properties) => !!properties.sub_issue_count && !!subIssueCount}
>
<Tooltip
tooltipHeading={isEpic ? t("issues.label", { count: 2 }) : t("common.sub_work_items")}
tooltipContent={`${subIssueCount}`}
isMobile={isMobile}
renderByDefault={false}
{!isEpic && (
<WithDisplayPropertiesHOC
displayProperties={displayProperties}
displayPropertyKey="sub_issue_count"
shouldRenderProperty={(properties) => !!properties.sub_issue_count && !!subIssueCount}
>
<div
onFocus={handleEventPropagation}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
if (subIssueCount) redirectToIssueDetail();
}}
className={cn(
"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",
{
"hover:bg-custom-background-80 cursor-pointer": subIssueCount,
}
)}
<Tooltip
tooltipHeading={t("common.sub_work_items")}
tooltipContent={`${subIssueCount}`}
isMobile={isMobile}
renderByDefault={false}
>
<Layers className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
<div className="text-xs">{subIssueCount}</div>
</div>
</Tooltip>
</WithDisplayPropertiesHOC>
<div
onFocus={handleEventPropagation}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
if (subIssueCount) redirectToIssueDetail();
}}
className={cn(
"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",
{
"hover:bg-custom-background-80 cursor-pointer": subIssueCount,
}
)}
>
<Layers className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
<div className="text-xs">{subIssueCount}</div>
</div>
</Tooltip>
</WithDisplayPropertiesHOC>
)}
{/* attachments */}
<WithDisplayPropertiesHOC

View file

@ -8,6 +8,7 @@ import { Row } from "@plane/ui";
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppRouter } from "@/hooks/use-app-router";
import { IssueStats } from "@/plane-web/components/issues/issue-layouts/issue-stats";
type Props = {
issue: TIssue;
@ -18,30 +19,30 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
// router
const router = useAppRouter();
// hooks
const { workspaceSlug, epicId } = useParams();
const { workspaceSlug } = useParams();
// derived values
const isEpic = issue?.is_epic;
const subIssueCount = issue?.sub_issues_count ?? 0;
const redirectToIssueDetail = () => {
router.push(
`/${workspaceSlug?.toString()}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}${epicId ? "epics" : "issues"}/${issue.id}#sub-issues`
`/${workspaceSlug?.toString()}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}${isEpic ? "epics" : "issues"}/${issue.id}#sub-issues`
);
};
const issueLabel = epicId ? "work item" : "sub-work item";
const label = `${subIssueCount} ${issueLabel}${subIssueCount !== 1 ? "s" : ""}`;
const label = `${subIssueCount} sub-work item${subIssueCount !== 1 ? "s" : ""}`;
return (
<Row
onClick={subIssueCount ? redirectToIssueDetail : () => {}}
className={cn(
"flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10",
"flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 py-1 text-xs hover:bg-custom-background-90 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-90",
{
"cursor-pointer": subIssueCount,
}
)}
>
{label}
{isEpic ? <IssueStats issueId={issue.id} /> : label}
</Row>
);
});