[WEB-1616] chore: improving the graphs ui and label in analytics (#4872)

* chore: improving the graphs ui and label in analytics

* chore: automatic width in tabel
This commit is contained in:
guru_sainath 2024-06-19 16:38:44 +05:30 committed by GitHub
parent 9b79a66a90
commit 67ad958998
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 115 additions and 96 deletions

View file

@ -8,7 +8,7 @@ import { Tooltip } from "@plane/ui";
// ui
import { BarGraph } from "@/components/ui";
// helpers
import { generateBarColor, generateDisplayName } from "@/helpers/analytics.helper";
import { generateBarColor, generateDisplayName, renderChartDynamicLabel } from "@/helpers/analytics.helper";
import { findStringWithMostCharacters } from "@/helpers/array.helper";
// types
import { CustomTooltip } from "./custom-tooltip";
@ -66,7 +66,7 @@ export const AnalyticsGraph: React.FC<Props> = ({ analytics, barGraphData, param
height={fullScreen ? "400px" : "300px"}
margin={{
right: 20,
bottom: params.x_axis === "assignees__id" ? 50 : longestXAxisLabel.length * 5 + 20,
bottom: params.x_axis === "assignees__id" ? 50 : renderChartDynamicLabel(longestXAxisLabel)?.length * 5 + 20,
}}
axisBottom={{
tickSize: 0,
@ -111,18 +111,20 @@ export const AnalyticsGraph: React.FC<Props> = ({ analytics, barGraphData, param
);
}
: (datum) => (
<g transform={`translate(${datum.x},${datum.y + 10})`}>
<text
x={0}
y={datum.y}
textAnchor={`${barGraphData.data.length > 7 ? "end" : "middle"}`}
fontSize={10}
fill="rgb(var(--color-text-200))"
className={`${barGraphData.data.length > 7 ? "-rotate-45" : ""}`}
>
{generateDisplayName(datum.value, analytics, params, "x_axis")}
</text>
</g>
<Tooltip tooltipContent={generateDisplayName(datum.value, analytics, params, "x_axis")}>
<g transform={`translate(${datum.x},${datum.y + 20})`}>
<text
x={0}
y={datum.y}
textAnchor={`${barGraphData.data.length > 7 ? "end" : "middle"}`}
fontSize={10}
fill="rgb(var(--color-text-200))"
className={`${barGraphData.data.length > 7 ? "-rotate-45" : ""}`}
>
{renderChartDynamicLabel(generateDisplayName(datum.value, analytics, params, "x_axis"))?.label}
</text>
</g>
</Tooltip>
),
}}
theme={{

View file

@ -1,14 +1,12 @@
"use client";
import { BarDatum } from "@nivo/bar";
// icons
import { IAnalyticsParams, IAnalyticsResponse, TIssuePriorities } from "@plane/types";
import { PriorityIcon } from "@plane/ui";
import { PriorityIcon, Tooltip } from "@plane/ui";
// helpers
import { ANALYTICS_X_AXIS_VALUES, ANALYTICS_Y_AXIS_VALUES } from "@/constants/analytics";
import { generateBarColor, generateDisplayName } from "@/helpers/analytics.helper";
// types
// constants
import { generateBarColor, generateDisplayName, renderChartDynamicLabel } from "@/helpers/analytics.helper";
import { cn } from "@/helpers/common.helper";
type Props = {
analytics: IAnalyticsResponse;
@ -21,80 +19,87 @@ type Props = {
};
export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, params, yAxisKey }) => (
<div className="flow-root">
<div className="overflow-x-auto">
<div className="inline-block min-w-full align-middle">
<table className="min-w-full divide-y divide-custom-border-200 whitespace-nowrap border-y border-custom-border-200">
<thead className="bg-custom-background-80">
<tr className="divide-x divide-custom-border-200 text-sm text-custom-text-100">
<th scope="col" className="px-2.5 py-3 text-left font-medium">
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === params.x_axis)?.label}
</th>
{params.segment ? (
barGraphData.xAxisKeys.map((key) => (
<th
key={`segment-${key}`}
scope="col"
className={`px-2.5 py-3 text-left font-medium ${
params.segment === "priority" || params.segment === "state__group" ? "capitalize" : ""
}`}
>
<div className="flex items-center gap-2">
{params.segment === "priority" ? (
<PriorityIcon priority={key as TIssuePriorities} />
) : (
<span
className="h-3 w-3 flex-shrink-0 rounded"
style={{
backgroundColor: generateBarColor(key, analytics, params, "segment"),
}}
/>
)}
{generateDisplayName(key, analytics, params, "segment")}
</div>
</th>
))
) : (
<th scope="col" className="px-2.5 py-3 text-left font-medium sm:pr-0">
{ANALYTICS_Y_AXIS_VALUES.find((v) => v.value === params.y_axis)?.label}
</th>
)}
</tr>
</thead>
<tbody className="divide-y divide-custom-border-200">
{barGraphData.data.map((item, index) => (
<tr key={`table-row-${index}`} className="divide-x divide-custom-border-200 text-xs text-custom-text-200">
<td
className={`flex items-center gap-2 whitespace-nowrap px-2.5 py-2 font-medium ${
params.x_axis === "priority" || params.x_axis === "state__group" ? "capitalize" : ""
}`}
>
{params.x_axis === "priority" ? (
<PriorityIcon priority={item.name as TIssuePriorities} />
<div className="w-full overflow-hidden overflow-x-auto">
<table className="w-full overflow-hidden divide-y divide-custom-border-200 whitespace-nowrap border-y border-custom-border-200">
<thead className="bg-custom-background-80">
<tr className="divide-x divide-custom-border-200 text-sm text-custom-text-100">
<th scope="col" className="px-2.5 py-3 text-left font-medium">
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === params.x_axis)?.label}
</th>
{params.segment ? (
barGraphData.xAxisKeys.map((key) => (
<th
key={`segment-${key}`}
scope="col"
className={`px-2.5 py-3 text-left font-medium ${
params.segment === "priority" || params.segment === "state__group" ? "capitalize" : ""
}`}
>
<div className="flex items-center gap-2">
{params.segment === "priority" ? (
<PriorityIcon priority={key as TIssuePriorities} />
) : (
<span
className="h-3 w-3 rounded"
className="h-3 w-3 flex-shrink-0 rounded"
style={{
backgroundColor: generateBarColor(key, analytics, params, "segment"),
}}
/>
)}
{renderChartDynamicLabel(generateDisplayName(key, analytics, params, "segment"))?.label}
</div>
</th>
))
) : (
<th scope="col" className="px-2.5 py-3 text-left font-medium sm:pr-0">
{ANALYTICS_Y_AXIS_VALUES.find((v) => v.value === params.y_axis)?.label}
</th>
)}
</tr>
</thead>
<tbody className="divide-y divide-custom-border-200">
{barGraphData.data.map((item, index) => (
<tr key={`table-row-${index}`} className="divide-x divide-custom-border-200 text-xs text-custom-text-200">
<td className="px-2.5 py-2">
<div className="relative flex items-center gap-2 w-full overflow-hidden">
<div className="flex-shrink-0 h-3 w-3 rounded overflow-hidden">
{params.x_axis === "priority" ? (
<PriorityIcon priority={(item.name as string).toLowerCase() as TIssuePriorities} />
) : (
<div
className="w-full h-full"
style={{
backgroundColor: generateBarColor(`${item.name}`, analytics, params, "x_axis"),
}}
/>
)}
{generateDisplayName(`${item.name}`, analytics, params, "x_axis")}
</div>
<div
className={cn(
"font-medium",
["priority", "state__group"].includes(params.x_axis) ? `capitalize` : ``
)}
>
<Tooltip tooltipContent={generateDisplayName(`${item.name}`, analytics, params, "x_axis")}>
<div className="overflow-hidden w-full whitespace-normal break-words truncate line-clamp-1">
{generateDisplayName(`${item.name}`, analytics, params, "x_axis")}
</div>
</Tooltip>
</div>
</div>
</td>
{params.segment ? (
barGraphData.xAxisKeys.map((key, index) => (
<td key={`segment-value-${index}`} className="whitespace-nowrap px-2.5 py-2 sm:pr-0">
{item[key] ?? 0}
</td>
{params.segment ? (
barGraphData.xAxisKeys.map((key, index) => (
<td key={`segment-value-${index}`} className="whitespace-nowrap px-2.5 py-2 sm:pr-0">
{item[key] ?? 0}
</td>
))
) : (
<td className="whitespace-nowrap px-2.5 py-2 sm:pr-0">{item[yAxisKey]}</td>
)}
</tr>
))}
</tbody>
</table>
</div>
</div>
))
) : (
<td className="whitespace-nowrap px-2.5 py-2 sm:pr-0">{item[yAxisKey]}</td>
)}
</tr>
))}
</tbody>
</table>
</div>
);

View file

@ -36,8 +36,8 @@ export const convertResponseToBarGraphData = (
name: DATE_KEYS.includes(params.x_axis)
? renderMonthAndYear(key)
: params.x_axis === "priority" || params.x_axis === "state__group"
? capitalizeFirstLetter(key)
: key,
? capitalizeFirstLetter(key)
: key,
...segments,
});
} else {
@ -49,8 +49,8 @@ export const convertResponseToBarGraphData = (
name: DATE_KEYS.includes(params.x_axis)
? renderMonthAndYear(item.dimension)
: params.x_axis === "priority" || params.x_axis === "state__group"
? capitalizeFirstLetter(item.dimension ?? "None")
: item.dimension ?? "None",
? capitalizeFirstLetter(item.dimension ?? "None")
: item.dimension ?? "None",
[yAxisKey]: item[yAxisKey] ?? 0,
});
}
@ -84,12 +84,12 @@ export const generateBarColor = (
priority === "urgent"
? "#ef4444"
: priority === "high"
? "#f97316"
: priority === "medium"
? "#eab308"
: priority === "low"
? "#22c55e"
: "#ced4da";
? "#f97316"
: priority === "medium"
? "#eab308"
: priority === "low"
? "#22c55e"
: "#ced4da";
}
return color ?? generateRandomColor(value);
@ -139,3 +139,15 @@ export const renderMonthAndYear = (date: string | number | null): string => {
return (MONTHS_LIST[monthNumber]?.shortTitle ?? "None") + ` ${year}` ?? "";
};
export const MAX_CHART_LABEL_LENGTH = 15;
export const renderChartDynamicLabel = (
label: string,
length: number = MAX_CHART_LABEL_LENGTH
): { label: string; length: number } => {
const currentLabel = label.substring(0, length);
return {
label: `${label.length > MAX_CHART_LABEL_LENGTH ? `${currentLabel.substring(0, MAX_CHART_LABEL_LENGTH - 3)}...` : currentLabel}`,
length: currentLabel.length,
};
};