[WEB-6579] feat: dashboard table widget (#6250)

* feat: add table chart functionality to dashboards

- Introduced new table chart type with corresponding components and configurations.
- Updated widget configuration to handle table chart properties.
- Enhanced translations and constants to support the new chart type.
- Refactored existing components to accommodate the new table chart integration.

* fix:format

* feat: enhance table chart functionality in dashboards

- Added support for x_axis_property in table chart configuration.
- Updated validation to ensure x_axis_property is set for table charts.
- Enhanced translations to include error messages for missing x_axis_property.
- Updated constants to define default metrics for table charts.

* chore: added table chart enum

* chore: added serializer level validation

* feat: add new table chart SVG assets for dashboards

- Introduced dark and light mode SVG assets for the table chart.
- Updated the helper file to include the new SVG assets in the chart asset map.

* Update packages/constants/src/dashboards/dashboards.ts

Co-authored-by: Copilot <[email protected]>

* Update apps/web/core/store/dashboards/widget.ts

Co-authored-by: Copilot <[email protected]>

* Update apps/web/core/components/dashboards/widgets/chart-types/table-chart.tsx

Co-authored-by: Copilot <[email protected]>

* chore: refactor table chart component and update translations

- Updated the placeholder text for the X-axis configuration in the widget sidebar.
- Refactored the payload handling in the basic config component to use Object.entries for better readability.
- Enhanced the table chart component layout for improved responsiveness and added truncation for long text.
- Added new translation keys for row placeholders and configuration hints in the i18n files.

* added translations

---------

Co-authored-by: NarayanBavisetti <[email protected]>
Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Jayash Tripathy
2026-03-17 21:25:58 +05:30
committed by GitHub
co-authored by NarayanBavisetti Copilot
parent c9b045fcb9
commit 3bc942c8d7
37 changed files with 725 additions and 61 deletions
+1
View File
@@ -90,6 +90,7 @@ class Widget(BaseModel):
PIE_CHART = "PIE_CHART", "Pie Chart"
DONUT_CHART = "DONUT_CHART", "Donut Chart"
NUMBER = "NUMBER", "Number Chart"
TABLE_CHART = "TABLE_CHART", "Table Chart"
class ChartModelEnum(models.TextChoices):
BASIC = "BASIC", "Basic"
@@ -104,6 +104,14 @@ class WidgetSerializer(BaseSerializer):
height = serializers.IntegerField(required=False)
width = serializers.IntegerField(required=False)
filters = serializers.JSONField(required=False)
chart_type = serializers.ChoiceField(choices=Widget.ChartTypeEnum.values)
chart_model = serializers.ChoiceField(choices=Widget.ChartModelEnum.values)
x_axis_property = serializers.ChoiceField(choices=Widget.PropertyEnum.values, allow_null=True, required=False)
y_axis_metric = serializers.ChoiceField(choices=Widget.YAxisMetricEnum.values, allow_null=True, required=False)
x_axis_date_grouping = serializers.ChoiceField(
choices=Widget.XAxisDateGroupingEnum.values, allow_null=True, required=False
)
group_by = serializers.ChoiceField(choices=Widget.PropertyEnum.values, allow_null=True, required=False)
def create(self, validated_data):
workspace_id = self.context["workspace_id"]
@@ -0,0 +1,4 @@
<svg width="94" height="94" viewBox="0 0 94 94" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="46.7188" cy="47.2188" r="46.7188" fill="#1F1F1F"/>
<path d="M63.125 42.875H42.875V63.125H55.3994C57.1102 63.125 58.2811 63.1228 59.1875 63.0488C60.071 62.9766 60.5387 62.8464 60.8721 62.6768C61.6482 62.2813 62.2813 61.6482 62.6768 60.8721C62.8464 60.5387 62.9766 60.071 63.0488 59.1875C63.1228 58.2811 63.125 57.1102 63.125 55.3994V42.875ZM30.875 55.3994C30.875 57.1102 30.8772 58.2811 30.9512 59.1875C31.0234 60.071 31.1536 60.5387 31.3232 60.8721C31.7187 61.6482 32.3518 62.2813 33.1279 62.6768C33.4612 62.8464 33.9289 62.9766 34.8125 63.0488C35.7189 63.1228 36.8898 63.125 38.6006 63.125H39.125V42.875H30.875V55.3994ZM63.125 38.6006C63.125 36.8898 63.1228 35.7189 63.0488 34.8125C62.9766 33.9289 62.8464 33.4612 62.6768 33.1279C62.2813 32.3518 61.6482 31.7187 60.8721 31.3232C60.5387 31.1536 60.071 31.0234 59.1875 30.9512C58.2811 30.8772 57.1102 30.875 55.3994 30.875H38.6006C36.8898 30.875 35.7189 30.8772 34.8125 30.9512C33.9289 31.0234 33.4612 31.1536 33.1279 31.3232C32.3518 31.7187 31.7187 32.3518 31.3232 33.1279C31.1536 33.4612 31.0234 33.9289 30.9512 34.8125C30.8772 35.7189 30.875 36.8898 30.875 38.6006V39.125H63.125V38.6006ZM66.875 55.3994C66.875 57.048 66.8764 58.3979 66.7871 59.4922C66.6959 60.6084 66.5004 61.6243 66.0166 62.5742C65.2616 64.0561 64.0561 65.2616 62.5742 66.0166C61.6243 66.5004 60.6084 66.6959 59.4922 66.7871C58.3979 66.8764 57.048 66.875 55.3994 66.875H38.6006C36.952 66.875 35.6022 66.8764 34.5078 66.7871C33.3917 66.6959 32.3757 66.5005 31.4258 66.0166C29.944 65.2617 28.7384 64.0561 27.9834 62.5742C27.4996 61.6243 27.3041 60.6084 27.2129 59.4922C27.1236 58.3979 27.125 57.048 27.125 55.3994V38.6006C27.125 36.952 27.1236 35.6022 27.2129 34.5078C27.3041 33.3916 27.4996 32.3757 27.9834 31.4258C28.7384 29.944 29.944 28.7384 31.4258 27.9834C32.3757 27.4996 33.3916 27.3041 34.5078 27.2129C35.6022 27.1236 36.952 27.125 38.6006 27.125H55.3994C57.048 27.125 58.3979 27.1236 59.4922 27.2129C60.6084 27.3041 61.6243 27.4996 62.5742 27.9834C64.0561 28.7384 65.2617 29.944 66.0166 31.4258C66.5005 32.3757 66.6959 33.3917 66.7871 34.5078C66.8764 35.6022 66.875 36.952 66.875 38.6006V55.3994Z" fill="#4F4E53"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -0,0 +1,4 @@
<svg width="94" height="94" viewBox="0 0 94 94" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="46.7188" cy="47.2188" r="46.7188" fill="#F4F5F9"/>
<path d="M63.125 42.875H42.875V63.125H55.3994C57.1102 63.125 58.2811 63.1228 59.1875 63.0488C60.071 62.9766 60.5387 62.8464 60.8721 62.6768C61.6482 62.2813 62.2813 61.6482 62.6768 60.8721C62.8464 60.5387 62.9766 60.071 63.0488 59.1875C63.1228 58.2811 63.125 57.1102 63.125 55.3994V42.875ZM30.875 55.3994C30.875 57.1102 30.8772 58.2811 30.9512 59.1875C31.0234 60.071 31.1536 60.5387 31.3232 60.8721C31.7187 61.6482 32.3518 62.2813 33.1279 62.6768C33.4612 62.8464 33.9289 62.9766 34.8125 63.0488C35.7189 63.1228 36.8898 63.125 38.6006 63.125H39.125V42.875H30.875V55.3994ZM63.125 38.6006C63.125 36.8898 63.1228 35.7189 63.0488 34.8125C62.9766 33.9289 62.8464 33.4612 62.6768 33.1279C62.2813 32.3518 61.6482 31.7187 60.8721 31.3232C60.5387 31.1536 60.071 31.0234 59.1875 30.9512C58.2811 30.8772 57.1102 30.875 55.3994 30.875H38.6006C36.8898 30.875 35.7189 30.8772 34.8125 30.9512C33.9289 31.0234 33.4612 31.1536 33.1279 31.3232C32.3518 31.7187 31.7187 32.3518 31.3232 33.1279C31.1536 33.4612 31.0234 33.9289 30.9512 34.8125C30.8772 35.7189 30.875 36.8898 30.875 38.6006V39.125H63.125V38.6006ZM66.875 55.3994C66.875 57.048 66.8764 58.3979 66.7871 59.4922C66.6959 60.6084 66.5004 61.6243 66.0166 62.5742C65.2616 64.0561 64.0561 65.2616 62.5742 66.0166C61.6243 66.5004 60.6084 66.6959 59.4922 66.7871C58.3979 66.8764 57.048 66.875 55.3994 66.875H38.6006C36.952 66.875 35.6022 66.8764 34.5078 66.7871C33.3917 66.6959 32.3757 66.5005 31.4258 66.0166C29.944 65.2617 28.7384 64.0561 27.9834 62.5742C27.4996 61.6243 27.3041 60.6084 27.2129 59.4922C27.1236 58.3979 27.125 57.048 27.125 55.3994V38.6006C27.125 36.952 27.1236 35.6022 27.2129 34.5078C27.3041 33.3916 27.4996 32.3757 27.9834 31.4258C28.7384 29.944 29.944 28.7384 31.4258 27.9834C32.3757 27.4996 33.3916 27.3041 34.5078 27.2129C35.6022 27.1236 36.952 27.125 38.6006 27.125H55.3994C57.048 27.125 58.3979 27.1236 59.4922 27.2129C60.6084 27.3041 61.6243 27.4996 62.5742 27.9834C64.0561 28.7384 65.2617 29.944 66.0166 31.4258C66.5005 32.3757 66.6959 33.3917 66.7871 34.5078C66.8764 35.6022 66.875 36.952 66.875 38.6006V55.3994Z" fill="#9DA3BC"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -11,11 +11,13 @@
* NOTICE: Proprietary and confidential. Unauthorized use or distribution is prohibited.
*/
import { useCallback } from "react";
import { Controller, useFormContext } from "react-hook-form";
// plane ui
import { WIDGET_X_AXIS_DATE_PROPERTIES } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import type { TDashboardWidget } from "@plane/types";
import type { EWidgetXAxisProperty, TDashboardWidget } from "@plane/types";
import { EWidgetChartTypes } from "@plane/types";
// local components
import { WidgetDateGroupSelect } from "./date-group-select";
import { WidgetPropertySelect } from "./property-select";
@@ -24,17 +26,61 @@ type Props = {
handleSubmit: (data: Partial<TDashboardWidget>) => Promise<void>;
};
/** When updating one axis property, avoid duplicate with the other; returns payload and whether to clear the other field. */
function getAxisMutualExclusionPayload(
field: "x_axis_property" | "group_by",
newValue: EWidgetXAxisProperty | null,
otherFieldValue: EWidgetXAxisProperty | null
): { payload: Partial<TDashboardWidget>; clearOther: boolean } {
const clearOther = newValue != null && newValue === otherFieldValue;
if (field === "x_axis_property") {
return {
payload: { x_axis_property: newValue, ...(clearOther && { group_by: null }) },
clearOther,
};
}
return {
payload: { group_by: newValue, ...(clearOther && { x_axis_property: null }) },
clearOther,
};
}
export function WidgetConfigSidebarXAxisConfig(props: Props) {
const { handleSubmit } = props;
// translation
const { t } = useTranslation();
// form info
const { control, watch, setValue } = useFormContext<TDashboardWidget>();
// derived values
const selectedChartType = watch("chart_type");
const selectedXAxisProperty = watch("x_axis_property");
const selectedGroupByProperty = watch("group_by");
const isTableChart = selectedChartType === EWidgetChartTypes.TABLE_CHART;
const isDateGroupingEnabled =
!!selectedXAxisProperty && WIDGET_X_AXIS_DATE_PROPERTIES.includes(selectedXAxisProperty);
selectedXAxisProperty != null && WIDGET_X_AXIS_DATE_PROPERTIES.includes(selectedXAxisProperty);
const handleXAxisPropertyChange = useCallback(
(val: EWidgetXAxisProperty | null, onChange: (val: EWidgetXAxisProperty | null) => void) => {
const { payload, clearOther } = getAxisMutualExclusionPayload(
"x_axis_property",
val,
selectedGroupByProperty ?? null
);
onChange(val);
if (clearOther) setValue("group_by", null);
void handleSubmit(payload);
},
[selectedGroupByProperty, setValue, handleSubmit]
);
const handleGroupByChange = useCallback(
(val: EWidgetXAxisProperty | null, onChange: (val: EWidgetXAxisProperty | null) => void) => {
const { payload, clearOther } = getAxisMutualExclusionPayload("group_by", val, selectedXAxisProperty ?? null);
onChange(val);
if (clearOther) setValue("x_axis_property", null);
void handleSubmit(payload);
},
[selectedXAxisProperty, setValue, handleSubmit]
);
return (
<div className="flex-shrink-0 space-y-1 text-13">
@@ -43,16 +89,9 @@ export function WidgetConfigSidebarXAxisConfig(props: Props) {
name="x_axis_property"
render={({ field: { value, onChange } }) => (
<WidgetPropertySelect
onChange={(val) => {
const isGroupBySame = selectedGroupByProperty === val;
onChange(val);
if (isGroupBySame) {
setValue("group_by", null);
}
handleSubmit({ x_axis_property: val, ...(isGroupBySame ? { group_by: null } : {}) });
}}
onChange={(val) => handleXAxisPropertyChange(val, onChange)}
placeholder={t("dashboards.widget.common.add_property")}
title={t("chart.x_axis")}
title={isTableChart ? t("dashboards.widget.chart_types.table_chart.columns") : t("chart.x_axis")}
value={value}
/>
)}
@@ -65,7 +104,7 @@ export function WidgetConfigSidebarXAxisConfig(props: Props) {
<WidgetDateGroupSelect
onChange={(val) => {
onChange(val);
handleSubmit({ x_axis_date_grouping: val });
void handleSubmit({ x_axis_date_grouping: val });
}}
placeholder={t("dashboards.widget.common.date_group.placeholder")}
title={t("dashboards.widget.common.date_group.label")}
@@ -74,6 +113,20 @@ export function WidgetConfigSidebarXAxisConfig(props: Props) {
)}
/>
)}
{isTableChart && (
<Controller
control={control}
name="group_by"
render={({ field: { value, onChange } }) => (
<WidgetPropertySelect
onChange={(val) => handleGroupByChange(val, onChange)}
placeholder={t("dashboards.widget.chart_types.table_chart.rows_placeholder")}
title={t("dashboards.widget.chart_types.table_chart.rows")}
value={value}
/>
)}
/>
)}
</div>
);
}
@@ -16,6 +16,7 @@ import { Controller, useFormContext } from "react-hook-form";
import { CHART_WIDGETS_Y_AXIS_METRICS_LIST } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import type { EWidgetYAxisMetric, TDashboardWidget } from "@plane/types";
import { EWidgetChartTypes } from "@plane/types";
// local components
import { WidgetMetricSelect } from "./metric-select";
@@ -28,7 +29,11 @@ export function WidgetConfigSidebarYAxisConfig(props: Props) {
// translation
const { t } = useTranslation();
// form info
const { control } = useFormContext<TDashboardWidget>();
const { control, watch } = useFormContext<TDashboardWidget>();
// derived values
const selectedChartType = watch("chart_type");
if (selectedChartType === EWidgetChartTypes.TABLE_CHART) return null;
return (
<div className="flex-shrink-0 space-y-1 text-13">
@@ -22,7 +22,7 @@ import {
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import type { TDashboardWidget, TDashboardWidgetConfig } from "@plane/types";
import { EWidgetChartModels, EWidgetChartTypes, EWidgetXAxisProperty } from "@plane/types";
import { EWidgetChartModels, EWidgetChartTypes, EWidgetXAxisProperty, EWidgetYAxisMetric } from "@plane/types";
// local components
import { WidgetChartTypeIcon } from "../../widgets";
import { DashboardWidgetChartTypesDropdown } from "../../widgets/dropdown";
@@ -72,38 +72,46 @@ export function WidgetConfigSidebarBasicConfig(props: Props) {
[getValues]
);
const getYAxisMetricForChartType = useCallback(
(chartType: EWidgetChartTypes): EWidgetYAxisMetric | undefined => {
if (chartType === EWidgetChartTypes.TABLE_CHART) {
return EWidgetYAxisMetric.WORK_ITEM_COUNT;
}
const current = getValues("y_axis_metric");
if (current == null) return undefined;
if (chartType === EWidgetChartTypes.NUMBER) {
return NUMBER_WIDGET_Y_AXIS_METRICS_LIST.includes(current) ? current : NUMBER_WIDGET_Y_AXIS_METRICS_LIST[0];
}
return CHART_WIDGETS_Y_AXIS_METRICS_LIST.includes(current) ? current : CHART_WIDGETS_Y_AXIS_METRICS_LIST[0];
},
[getValues]
);
const handleChartTypeChange = useCallback(
async (chartType: EWidgetChartTypes, chartModel: EWidgetChartModels) => {
const updatedConfig = getUpdatedConfig(chartType, chartModel);
// update form values
const payload: Partial<TDashboardWidget> = {
chart_type: chartType,
chart_model: chartModel,
config: updatedConfig,
};
// update y-axis metric
const yAxisMetric = getValues("y_axis_metric");
let newYAxisMetric = yAxisMetric;
if (yAxisMetric) {
if (chartType === EWidgetChartTypes.NUMBER && !NUMBER_WIDGET_Y_AXIS_METRICS_LIST.includes(yAxisMetric)) {
newYAxisMetric = NUMBER_WIDGET_Y_AXIS_METRICS_LIST[0];
}
if (chartType !== EWidgetChartTypes.NUMBER && !CHART_WIDGETS_Y_AXIS_METRICS_LIST.includes(yAxisMetric)) {
newYAxisMetric = CHART_WIDGETS_Y_AXIS_METRICS_LIST[0];
}
payload.y_axis_metric = newYAxisMetric;
}
if (chartModel === EWidgetChartModels.BASIC) {
const yAxisMetric = getYAxisMetricForChartType(chartType);
if (yAxisMetric != null) payload.y_axis_metric = yAxisMetric;
if (chartModel === EWidgetChartModels.BASIC && chartType !== EWidgetChartTypes.TABLE_CHART) {
payload.group_by = null;
}
if (chartType === EWidgetChartTypes.DONUT_CHART && chartModel === EWidgetChartModels.PROGRESS) {
payload.x_axis_property = EWidgetXAxisProperty.STATE_GROUPS;
}
Object.keys(payload).forEach((key) => {
const payloadKey = key as keyof typeof payload;
setValue(payloadKey, payloadKey);
});
// make api call
if (chartType === EWidgetChartTypes.TABLE_CHART && !getValues("x_axis_property")) {
payload.x_axis_property = EWidgetXAxisProperty.STATES;
}
for (const [key, value] of Object.entries(payload)) {
if (value !== undefined) setValue(key as keyof TDashboardWidget, value);
}
await handleSubmit(payload);
},
[getUpdatedConfig, handleSubmit]
@@ -178,7 +178,6 @@ export const DashboardsWidgetConfigSidebarRoot = observer(function DashboardsWid
<WidgetConfigSidebarBasicConfig handleSubmit={handleFormSubmit} />
<div className="flex-shrink-0 h-px border-t border-subtle" />
<WidgetConfigSidebarAxisConfig handleSubmit={handleFormSubmit} />
<div className="flex-shrink-0 h-px border-t border-subtle" />
<WidgetConfigSidebarStyleConfig handleSubmit={handleFormSubmit} />
<div className="flex-shrink-0 h-px border-t border-subtle" />
<WidgetConfigSidebarFilters
@@ -55,30 +55,35 @@ export const WidgetConfigSidebarStyleConfig = observer(function WidgetConfigSide
[handleSubmit]
);
if (selectedChartType === EWidgetChartTypes.TABLE_CHART) return null;
return (
<div className="flex-shrink-0 space-y-3 text-13">
<Collapsible open={isCollapsibleIcon} onOpenChange={setIsCollapsibleIcon}>
<CollapsibleTrigger>
<div className="flex items-center gap-0.5 p-1 -ml-1 hover:bg-layer-1 rounded-sm transition-colors">
<h6 className="font-semibold text-secondary">{t("dashboards.widget.common.style")}</h6>
<div className="flex-shrink-0 size-4 grid place-items-center">
<ChevronRightIcon
className={cn("size-2.5 transition-all", {
"rotate-90": isCollapsibleIcon,
})}
/>
<>
<div className="flex-shrink-0 h-px border-t border-subtle" />
<div className="flex-shrink-0 space-y-3 text-13">
<Collapsible open={isCollapsibleIcon} onOpenChange={setIsCollapsibleIcon}>
<CollapsibleTrigger>
<div className="flex items-center gap-0.5 p-1 -ml-1 hover:bg-layer-1 rounded-sm transition-colors">
<h6 className="font-semibold text-secondary">{t("dashboards.widget.common.style")}</h6>
<div className="flex-shrink-0 size-4 grid place-items-center">
<ChevronRightIcon
className={cn("size-2.5 transition-all", {
"rotate-90": isCollapsibleIcon,
})}
/>
</div>
</div>
</div>
</CollapsibleTrigger>
<CollapsibleContent>
<div className="mt-3 flex flex-col gap-y-4">
<WidgetConfigSidebarAppearanceConfig handleConfigUpdate={handleConfigUpdate} />
{selectedChartType !== EWidgetChartTypes.NUMBER && (
<WidgetConfigSidebarGuidesConfig handleConfigUpdate={handleConfigUpdate} />
)}
</div>
</CollapsibleContent>
</Collapsible>
</div>
</CollapsibleTrigger>
<CollapsibleContent>
<div className="mt-3 flex flex-col gap-y-4">
<WidgetConfigSidebarAppearanceConfig handleConfigUpdate={handleConfigUpdate} />
{selectedChartType !== EWidgetChartTypes.NUMBER && (
<WidgetConfigSidebarGuidesConfig handleConfigUpdate={handleConfigUpdate} />
)}
</div>
</CollapsibleContent>
</Collapsible>
</div>
</>
);
});
@@ -30,6 +30,7 @@ import { DashboardWidgetHeader } from "./header";
import { DashboardLineChartWidget } from "./line-chart";
import { DashboardNumberWidget } from "./number";
import { DashboardPieChartWidget } from "./pie-chart";
import { DashboardTableChartWidget } from "./table-chart";
import type { TWidgetComponentProps } from "./";
import { commonWidgetClassName, parseWidgetData } from "./";
@@ -94,6 +95,9 @@ export const DashboardWidgetRoot = observer(function DashboardWidgetRoot(props:
case EWidgetChartTypes.PIE_CHART:
WidgetComponent = DashboardPieChartWidget;
break;
case EWidgetChartTypes.TABLE_CHART:
WidgetComponent = DashboardTableChartWidget;
break;
default:
WidgetComponent = null;
}
@@ -0,0 +1,99 @@
/**
* SPDX-FileCopyrightText: 2023-present Plane Software, Inc.
* SPDX-License-Identifier: LicenseRef-Plane-Commercial
*
* Licensed under the Plane Commercial License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://plane.so/legals/eula
*
* DO NOT remove or modify this notice.
* NOTICE: Proprietary and confidential. Unauthorized use or distribution is prohibited.
*/
import { observer } from "mobx-react";
// plane imports
import { WIDGET_X_AXIS_PROPERTIES_LIST } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
// local imports
import type { TWidgetComponentProps } from ".";
export const DashboardTableChartWidget = observer(function DashboardTableChartWidget(props: TWidgetComponentProps) {
const { parsedData, widget } = props;
// translation
const { t } = useTranslation();
// derived values
const { group_by } = widget ?? {};
// columns = x-axis items (each datum)
const columns = parsedData.data;
// rows = schema keys (group values)
const groupKeys = Object.keys(parsedData.schema);
const hasGroupKeys = groupKeys.length > 0;
// first column header label — the group_by property name
const groupByLabel = group_by ? t(WIDGET_X_AXIS_PROPERTIES_LIST[group_by].i18n_label) : "";
// If there are no columns at all, there is nothing to render.
if (!columns.length) return null;
return (
<div className="flex size-full flex-col overflow-hidden px-4">
{hasGroupKeys ? (
<>
<table className="w-full shrink-0 border-collapse text-xs" style={{ tableLayout: "fixed" }}>
<thead>
<tr className="border-b border-subtle-1">
<th className="min-w-0 pr-3 py-3 text-left text-tertiary text-11 truncate" title={groupByLabel}>
{groupByLabel}
</th>
{columns.map((col) => (
<th
key={col.key}
className="min-w-0 pr-3 py-3 text-left font-medium text-tertiary text-11 truncate"
title={col.name}
>
{col.name}
</th>
))}
</tr>
</thead>
</table>
<div className="min-h-0 flex-1 overflow-auto vertical-scrollbar scrollbar-xs">
<table className="w-full border-collapse text-xs" style={{ tableLayout: "fixed" }}>
<tbody>
{groupKeys.map((groupKey) => {
const groupLabel = parsedData.schema[groupKey];
return (
<tr key={groupKey} className="transition-colors">
<td
className="sticky left-0 z-10 min-w-0 bg-surface-1 pr-3 py-3 text-secondary truncate"
title={groupLabel}
>
{groupLabel}
</td>
{columns.map((col) => {
const cellValue = col[groupKey] ?? 0;
return (
<td
key={col.key}
className="min-w-0 pr-3 py-3 text-primary tabular-nums truncate"
title={String(cellValue)}
>
{cellValue}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
</>
) : (
<div className="flex h-full items-center justify-center text-xs text-tertiary">
<span>{t("dashboards.widget.chart_types.table_chart.configure_rows_hint")}</span>
</div>
)}
</div>
);
});
@@ -26,6 +26,8 @@ import numberDark from "@/app/assets/empty-state/dashboards/widgets/charts/numbe
import numberLight from "@/app/assets/empty-state/dashboards/widgets/charts/number-light.webp?url";
import pieChartDark from "@/app/assets/empty-state/dashboards/widgets/charts/pie_chart-dark.webp?url";
import pieChartLight from "@/app/assets/empty-state/dashboards/widgets/charts/pie_chart-light.webp?url";
import tableChartDark from "@/app/assets/empty-state/dashboards/widgets/charts/table_chart-dark.svg?url";
import tableChartLight from "@/app/assets/empty-state/dashboards/widgets/charts/table_chart-light.svg?url";
export const CHART_ASSET_MAP: Record<EWidgetChartTypes, { dark: string; light: string }> = {
AREA_CHART: { dark: areaChartDark, light: areaChartLight },
@@ -34,4 +36,5 @@ export const CHART_ASSET_MAP: Record<EWidgetChartTypes, { dark: string; light: s
LINE_CHART: { dark: lineChartDark, light: lineChartLight },
NUMBER: { dark: numberDark, light: numberLight },
PIE_CHART: { dark: pieChartDark, light: pieChartLight },
TABLE_CHART: { dark: tableChartDark, light: tableChartLight },
};
@@ -20,6 +20,7 @@ import {
BasicLineChartIcon,
BasicNumberIcon,
BasicPieChartIcon,
BasicTableChartIcon,
ComparisonAreaChartIcon,
GroupedBarChartIcon,
MultiLineLineChartIcon,
@@ -72,6 +73,8 @@ export function WidgetChartTypeIcon(props: Props) {
Icon = BasicPieChartIcon;
} else if (chartType === EWidgetChartTypes.NUMBER) {
Icon = BasicNumberIcon;
} else if (chartType === EWidgetChartTypes.TABLE_CHART) {
Icon = BasicTableChartIcon;
}
return Icon ? <Icon className={className} /> : null;
+5
View File
@@ -193,6 +193,11 @@ export class DashboardWidgetInstance implements IDashboardWidgetInstance {
if (chartType === EWidgetChartTypes.NUMBER) {
if (!this.y_axis_metric) return "y_axis_metric";
}
if (chartType === EWidgetChartTypes.TABLE_CHART) {
if (!this.x_axis_property) return "x_axis_property";
if (!this.y_axis_metric) return "y_axis_metric";
if (!this.group_by) return "group_by";
}
return null;
}
@@ -69,6 +69,11 @@ export const WIDGET_CHART_TYPES_LIST: {
i18n_short_label: "dashboards.widget.chart_types.number.short_label",
i18n_long_label: "dashboards.widget.chart_types.number.long_label",
},
{
key: EWidgetChartTypes.TABLE_CHART,
i18n_short_label: "dashboards.widget.chart_types.table_chart.short_label",
i18n_long_label: "dashboards.widget.chart_types.table_chart.long_label",
},
];
export const DEFAULT_WIDGET_CHART_TYPE_PAYLOAD: {
@@ -184,6 +189,21 @@ export const DEFAULT_WIDGET_CHART_TYPE_PAYLOAD: {
},
},
},
[EWidgetChartTypes.TABLE_CHART]: {
// For table charts, y_axis_metric is static because it cannot be changed.
y_axis_metric: EWidgetYAxisMetric.WORK_ITEM_COUNT,
config: {
orientation: "vertical",
show_legends: true,
show_tooltip: true,
},
[EWidgetChartModels.BASIC]: {
y_axis_metric: EWidgetYAxisMetric.WORK_ITEM_COUNT,
config: {
bar_color: DEFAULT_WIDGET_COLOR,
},
},
},
};
export const WIDGET_CHART_MODELS_LIST: Record<
@@ -279,6 +299,14 @@ export const WIDGET_CHART_MODELS_LIST: Record<
flags: [E_FEATURE_FLAGS.DASHBOARDS, E_FEATURE_FLAGS.DASHBOARDS_ADVANCED],
},
],
[EWidgetChartTypes.TABLE_CHART]: [
{
value: EWidgetChartModels.BASIC,
i18n_short_label: "dashboards.widget.chart_types.table_chart.chart_models.basic.short_label",
i18n_long_label: "dashboards.widget.chart_types.table_chart.chart_models.basic.long_label",
flags: [E_FEATURE_FLAGS.DASHBOARDS, E_FEATURE_FLAGS.DASHBOARDS_ADVANCED],
},
],
};
export const WIDGET_X_AXIS_PROPERTIES_LIST: Record<
@@ -470,6 +498,11 @@ export const WIDGET_DROPDOWN_SECTIONS: {
i18n_label: "dashboards.widget.chart_types.number.short_label",
models: WIDGET_CHART_MODELS_LIST[EWidgetChartTypes.NUMBER],
},
{
key: EWidgetChartTypes.TABLE_CHART,
i18n_label: "dashboards.widget.chart_types.table_chart.short_label",
models: WIDGET_CHART_MODELS_LIST[EWidgetChartTypes.TABLE_CHART],
},
],
},
];
@@ -4844,6 +4844,20 @@ Vytvořte nový.`,
},
text_color: "Barva textu",
},
table_chart: {
short_label: "Tabulka",
long_label: "Tabulkový graf",
chart_models: {
basic: {
short_label: "Základní",
long_label: "Tabulka",
},
},
columns: "Sloupce",
rows: "Řádky",
rows_placeholder: "Přidat řádky",
configure_rows_hint: "Vyberte vlastnost pro řádky pro zobrazení této tabulky.",
},
},
color_palettes: {
modern_tech: "Moderní technologie",
@@ -4964,6 +4978,12 @@ Vytvořte nový.`,
y_axis_metric: "Metrika chybí.",
},
},
table_chart: {
basic: {
x_axis_property: "Sloupcům chybí hodnota.",
group_by: "Řádkům chybí hodnota.",
},
},
ask_admin: "Požádejte svého správce, aby konfiguroval tento widget.",
},
},
@@ -4907,6 +4907,20 @@ Erstellen Sie ein neues.`,
},
text_color: "Textfarbe",
},
table_chart: {
short_label: "Tabelle",
long_label: "Tabellendiagramm",
chart_models: {
basic: {
short_label: "Standard",
long_label: "Tabelle",
},
},
columns: "Spalten",
rows: "Zeilen",
rows_placeholder: "Zeilen hinzufügen",
configure_rows_hint: "Wählen Sie eine Eigenschaft für Zeilen aus, um diese Tabelle anzuzeigen.",
},
},
color_palettes: {
modern: "Modern",
@@ -5027,6 +5041,12 @@ Erstellen Sie ein neues.`,
y_axis_metric: "Der Metrik fehlt ein Wert.",
},
},
table_chart: {
basic: {
x_axis_property: "Spalten fehlt ein Wert.",
group_by: "Zeilen fehlt ein Wert.",
},
},
ask_admin: "Bitten Sie Ihren Administrator, dieses Widget zu konfigurieren.",
},
},
@@ -5369,6 +5369,20 @@ if you are sure your search is right. `,
},
text_color: "Text color",
},
table_chart: {
short_label: "Table",
long_label: "Table chart",
chart_models: {
basic: {
short_label: "Basic",
long_label: "Table",
},
},
columns: "Columns",
rows: "Rows",
rows_placeholder: "Add rows",
configure_rows_hint: "Select a property for rows to view this table.",
},
},
sections: {
charts: "Charts",
@@ -5489,6 +5503,12 @@ if you are sure your search is right. `,
y_axis_metric: "Metric is missing a value.",
},
},
table_chart: {
basic: {
x_axis_property: "Columns is missing a value.",
group_by: "Rows is missing a value.",
},
},
ask_admin: "Ask your admin to configure this widget.",
},
upgrade_required: {
@@ -4945,6 +4945,20 @@ si estás seguro de que tu búsqueda es correcta.`,
},
text_color: "Color de texto",
},
table_chart: {
short_label: "Tabla",
long_label: "Gráfico de tabla",
chart_models: {
basic: {
short_label: "Básico",
long_label: "Tabla",
},
},
columns: "Columnas",
rows: "Filas",
rows_placeholder: "Añadir filas",
configure_rows_hint: "Seleccione una propiedad para las filas para ver esta tabla.",
},
},
color_palettes: {
modern: "Moderno",
@@ -5065,6 +5079,12 @@ si estás seguro de que tu búsqueda es correcta.`,
y_axis_metric: "A la métrica le falta un valor.",
},
},
table_chart: {
basic: {
x_axis_property: "A las columnas les falta un valor.",
group_by: "A las filas les falta un valor.",
},
},
ask_admin: "Solicite a su administrador que configure este widget.",
},
},
@@ -4951,6 +4951,20 @@ si vous êtes sûr que votre recherche est correcte.`,
},
text_color: "Couleur du texte",
},
table_chart: {
short_label: "Tableau",
long_label: "Graphique en tableau",
chart_models: {
basic: {
short_label: "Basique",
long_label: "Tableau",
},
},
columns: "Colonnes",
rows: "Lignes",
rows_placeholder: "Ajouter des lignes",
configure_rows_hint: "Sélectionnez une propriété pour les lignes pour afficher ce tableau.",
},
},
color_palettes: {
modern: "Moderne",
@@ -5071,6 +5085,12 @@ si vous êtes sûr que votre recherche est correcte.`,
y_axis_metric: "La métrique manque d'une valeur.",
},
},
table_chart: {
basic: {
x_axis_property: "Il manque une valeur aux colonnes.",
group_by: "Il manque une valeur aux lignes.",
},
},
ask_admin: "Demandez à votre administrateur de configurer ce widget.",
},
},
@@ -4885,6 +4885,20 @@ jika Anda yakin pencarian Anda benar. `,
},
text_color: "Warna teks",
},
table_chart: {
short_label: "Tabel",
long_label: "Grafik tabel",
chart_models: {
basic: {
short_label: "Dasar",
long_label: "Tabel",
},
},
columns: "Kolom",
rows: "Baris",
rows_placeholder: "Tambah baris",
configure_rows_hint: "Pilih properti untuk baris untuk melihat tabel ini.",
},
},
color_palettes: {
modern: "Modern",
@@ -5005,6 +5019,12 @@ jika Anda yakin pencarian Anda benar. `,
y_axis_metric: "Metrik tidak memiliki nilai.",
},
},
table_chart: {
basic: {
x_axis_property: "Kolom tidak memiliki nilai.",
group_by: "Baris tidak memiliki nilai.",
},
},
ask_admin: "Tanyakan admin Anda untuk mengonfigurasi widget ini.",
},
},
@@ -4911,6 +4911,20 @@ Crea un nuovo progetto invece`,
},
text_color: "Colore testo",
},
table_chart: {
short_label: "Tabella",
long_label: "Grafico a tabella",
chart_models: {
basic: {
short_label: "Base",
long_label: "Tabella",
},
},
columns: "Colonne",
rows: "Righe",
rows_placeholder: "Aggiungi righe",
configure_rows_hint: "Seleziona una proprietà per le righe per visualizzare questa tabella.",
},
},
color_palettes: {
modern: "Moderno",
@@ -5031,6 +5045,12 @@ Crea un nuovo progetto invece`,
y_axis_metric: "La metrica manca di un valore.",
},
},
table_chart: {
basic: {
x_axis_property: "Alle colonne manca un valore.",
group_by: "Alle righe manca un valore.",
},
},
ask_admin: "Chiedi al tuo amministratore di configurare questo widget.",
},
},
@@ -4865,6 +4865,20 @@ export default {
},
text_color: "テキスト カラー",
},
table_chart: {
short_label: "表",
long_label: "表グラフ",
chart_models: {
basic: {
short_label: "基本",
long_label: "表",
},
},
columns: "列",
rows: "行",
rows_placeholder: "行を追加",
configure_rows_hint: "この表を表示するには行のプロパティを選択してください。",
},
},
color_palettes: {
modern: "モダン",
@@ -4985,6 +4999,12 @@ export default {
y_axis_metric: "メトリック イズ ミッシング ア バリュー",
},
},
table_chart: {
basic: {
x_axis_property: "列に値がありません。",
group_by: "行に値がありません。",
},
},
ask_admin: "アスク ユア アドミン トゥ コンフィギュア ディス ウィジェット",
},
},
@@ -4824,6 +4824,20 @@ export default {
},
text_color: "텍스트 컬러",
},
table_chart: {
short_label: "테이블",
long_label: "테이블 차트",
chart_models: {
basic: {
short_label: "기본",
long_label: "테이블",
},
},
columns: "열",
rows: "행",
rows_placeholder: "행 추가",
configure_rows_hint: "이 테이블을 보려면 행에 대한 속성을 선택하세요.",
},
},
color_palettes: {
modern: "모던",
@@ -4944,6 +4958,12 @@ export default {
y_axis_metric: "메트릭에 값이 없습니다.",
},
},
table_chart: {
basic: {
x_axis_property: "열에 값이 없습니다.",
group_by: "행에 값이 없습니다.",
},
},
ask_admin: "이 위젯을 구성하려면 관리자에게 문의하세요.",
},
},
@@ -4853,6 +4853,20 @@ Utwórz nowy.`,
},
text_color: "Kolor tekstu",
},
table_chart: {
short_label: "Tabela",
long_label: "Wykres tabelaryczny",
chart_models: {
basic: {
short_label: "Podstawowy",
long_label: "Tabela",
},
},
columns: "Kolumny",
rows: "Wiersze",
rows_placeholder: "Dodaj wiersze",
configure_rows_hint: "Wybierz właściwość dla wierszy, aby wyświetlić tę tabelę.",
},
},
color_palettes: {
modern: "Nowoczesna",
@@ -4973,6 +4987,12 @@ Utwórz nowy.`,
y_axis_metric: "Metryka nie ma wartości.",
},
},
table_chart: {
basic: {
x_axis_property: "Kolumny nie mają wartości.",
group_by: "Wiersze nie mają wartości.",
},
},
ask_admin: "Poproś swojego administratora o skonfigurowanie tego widżetu.",
},
},
@@ -4924,6 +4924,20 @@ se você tem certeza de que sua pesquisa está correta.`,
},
text_color: "Cor do texto",
},
table_chart: {
short_label: "Tabela",
long_label: "Gráfico de tabela",
chart_models: {
basic: {
short_label: "Básico",
long_label: "Tabela",
},
},
columns: "Colunas",
rows: "Linhas",
rows_placeholder: "Adicionar linhas",
configure_rows_hint: "Selecione uma propriedade para as linhas para visualizar esta tabela.",
},
},
color_palettes: {
modern: "Moderno",
@@ -5046,6 +5060,12 @@ se você tem certeza de que sua pesquisa está correta.`,
y_axis_metric: "A métrica está sem um valor.",
},
},
table_chart: {
basic: {
x_axis_property: "As colunas estão sem um valor.",
group_by: "As linhas estão sem um valor.",
},
},
ask_admin: "Peça ao seu administrador para configurar este widget.",
},
},
@@ -4917,6 +4917,20 @@ văzute aici`,
},
text_color: "Culoare text",
},
table_chart: {
short_label: "Tabel",
long_label: "Grafic tabel",
chart_models: {
basic: {
short_label: "De bază",
long_label: "Tabel",
},
},
columns: "Coloane",
rows: "Rânduri",
rows_placeholder: "Adaugă rânduri",
configure_rows_hint: "Selectați o proprietate pentru rânduri pentru a vizualiza acest tabel.",
},
},
color_palettes: {
modern: "Modern",
@@ -5037,6 +5051,12 @@ văzute aici`,
y_axis_metric: "Metrica lipsește o valoare.",
},
},
table_chart: {
basic: {
x_axis_property: "Coloanelor lipsește o valoare.",
group_by: "Rândurilor lipsește o valoare.",
},
},
ask_admin: "Întreabă administratorul tău pentru a configura acest widget.",
},
},
@@ -4918,6 +4918,20 @@ export default {
},
text_color: "Цвет текста",
},
table_chart: {
short_label: "Таблица",
long_label: "Табличная диаграмма",
chart_models: {
basic: {
short_label: "Основная",
long_label: "Таблица",
},
},
columns: "Столбцы",
rows: "Строки",
rows_placeholder: "Добавить строки",
configure_rows_hint: "Выберите свойство для строк, чтобы просмотреть эту таблицу.",
},
},
color_palettes: {
modern: "Современная",
@@ -5038,6 +5052,12 @@ export default {
y_axis_metric: "Отсутствует значение для метрики.",
},
},
table_chart: {
basic: {
x_axis_property: "Столбцам не хватает значения.",
group_by: "Строкам не хватает значения.",
},
},
ask_admin: "Попросите администратора настроить этот виджет.",
},
},
@@ -4760,6 +4760,20 @@ Vytvorte nový.`,
},
text_color: "Farba textu",
},
table_chart: {
short_label: "Tabuľka",
long_label: "Tabuľkový graf",
chart_models: {
basic: {
short_label: "Základný",
long_label: "Tabuľka",
},
},
columns: "Stĺpce",
rows: "Riadky",
rows_placeholder: "Pridať riadky",
configure_rows_hint: "Vyberte vlastnosť pre riadky na zobrazenie tejto tabuľky.",
},
},
color_palettes: {
modern: "Moderná",
@@ -4880,6 +4894,12 @@ Vytvorte nový.`,
y_axis_metric: "Metrike chýba hodnota.",
},
},
table_chart: {
basic: {
x_axis_property: "Stĺpcom chýba hodnota.",
group_by: "Riadkom chýba hodnota.",
},
},
ask_admin: "Požiadajte svojho administrátora o konfiguráciu tohto vidžetu.",
},
},
@@ -4906,6 +4906,20 @@ modüller arşivlenebilir.`,
},
text_color: "Tekst rengi",
},
table_chart: {
short_label: "Tablo",
long_label: "Tablo grafiği",
chart_models: {
basic: {
short_label: "Temel",
long_label: "Tablo",
},
},
columns: "Sütunlar",
rows: "Satırlar",
rows_placeholder: "Satır ekle",
configure_rows_hint: "Bu tabloyu görüntülemek için satırlar için bir özellik seçin.",
},
},
sections: {
charts: "Çarts",
@@ -5026,6 +5040,12 @@ modüller arşivlenebilir.`,
y_axis_metric: "Metrik için değer eksik.",
},
},
table_chart: {
basic: {
x_axis_property: "Sütunlar için değer eksik.",
group_by: "Satırlar için değer eksik.",
},
},
ask_admin: "Bu vicıtı konfigüre etmesi için admininize sorun.",
},
upgrade_required: {
@@ -4852,6 +4852,20 @@ export default {
},
text_color: "Колір тексту",
},
table_chart: {
short_label: "Таблиця",
long_label: "Таблична діаграма",
chart_models: {
basic: {
short_label: "Базова",
long_label: "Таблиця",
},
},
columns: "Стовпці",
rows: "Рядки",
rows_placeholder: "Додати рядки",
configure_rows_hint: "Виберіть властивість для рядків, щоб переглянути цю таблицю.",
},
},
color_palettes: {
modern: "Модерн",
@@ -4972,6 +4986,12 @@ export default {
y_axis_metric: "Відсутнє значення метрики.",
},
},
table_chart: {
basic: {
x_axis_property: "Стовпцям не вистачає значення.",
group_by: "Рядкам не вистачає значення.",
},
},
ask_admin: "Попросіть адміністратора налаштувати цей віджет.",
},
},
@@ -4861,6 +4861,20 @@ tìm kiếm là chính xác, hãy cho chúng tôi biết.`,
},
text_color: "Màu văn bản",
},
table_chart: {
short_label: "Bảng",
long_label: "Biểu đồ bảng",
chart_models: {
basic: {
short_label: "Cơ bản",
long_label: "Bảng",
},
},
columns: "Cột",
rows: "Hàng",
rows_placeholder: "Thêm hàng",
configure_rows_hint: "Chọn một thuộc tính cho hàng để xem bảng này.",
},
},
color_palettes: {
modern: "Hiện đại",
@@ -4983,6 +4997,12 @@ tìm kiếm là chính xác, hãy cho chúng tôi biết.`,
y_axis_metric: "Chỉ số đang thiếu giá trị.",
},
},
table_chart: {
basic: {
x_axis_property: "Cột đang thiếu giá trị.",
group_by: "Hàng đang thiếu giá trị.",
},
},
ask_admin: "Yêu cầu quản trị viên của bạn cấu hình widget này.",
},
},
@@ -4731,6 +4731,20 @@ export default {
},
text_color: "文本颜色",
},
table_chart: {
short_label: "表格",
long_label: "表格图表",
chart_models: {
basic: {
short_label: "基础",
long_label: "表格",
},
},
columns: "列",
rows: "行",
rows_placeholder: "添加行",
configure_rows_hint: "选择行的属性以查看此表格。",
},
},
color_palettes: {
modern: "现代",
@@ -4851,6 +4865,12 @@ export default {
y_axis_metric: "指标缺少值。",
},
},
table_chart: {
basic: {
x_axis_property: "列缺少值。",
group_by: "行缺少值。",
},
},
ask_admin: "请联系管理员配置此组件。",
},
},
@@ -4752,6 +4752,20 @@ export default {
},
text_color: "文字顏色",
},
table_chart: {
short_label: "表格",
long_label: "表格圖表",
chart_models: {
basic: {
short_label: "基本",
long_label: "表格",
},
},
columns: "列",
rows: "行",
rows_placeholder: "添加行",
configure_rows_hint: "選擇行的屬性以查看此表格。",
},
},
color_palettes: {
modern: "現代",
@@ -4872,6 +4886,12 @@ export default {
y_axis_metric: "指標缺少值。",
},
},
table_chart: {
basic: {
x_axis_property: "列缺少值。",
group_by: "行缺少值。",
},
},
ask_admin: "請管理員配置此小工具。",
},
},
@@ -17,3 +17,4 @@ export * from "./donut-chart";
export * from "./line-chart";
export * from "./number";
export * from "./pie-chart";
export * from "./table-chart";
@@ -0,0 +1,43 @@
/**
* SPDX-FileCopyrightText: 2023-present Plane Software, Inc.
* SPDX-License-Identifier: LicenseRef-Plane-Commercial
*
* Licensed under the Plane Commercial License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://plane.so/legals/eula
*
* DO NOT remove or modify this notice.
* NOTICE: Proprietary and confidential. Unauthorized use or distribution is prohibited.
*/
import * as React from "react";
// types
import type { ISvgIcons } from "../type";
export function BasicTableChartIcon({ height = "27", width = "27", className = "", ...rest }: ISvgIcons) {
return (
<svg
width={width}
height={height}
className={className}
viewBox="0 0 27 27"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...rest}
>
<path
d="M21.1181 1.07313e-06H5.54861C4.84577 -2.17364e-05 4.23938 -4.14128e-05 3.73997 0.0407626C3.21284 0.0838306 2.68855 0.178919 2.18404 0.435977C1.43139 0.819471 0.819471 1.43139 0.435977 2.18404C0.178919 2.68855 0.0838306 3.21284 0.0407626 3.73997C-4.14128e-05 4.23938 -2.17364e-05 4.84572 1.07313e-06 5.54856V5.86667C1.07313e-06 6.6134 1.07288e-06 6.98677 0.145326 7.27199C0.273157 7.52287 0.477131 7.72684 0.728014 7.85468C1.01323 8 1.3866 8 2.13334 8H24.5333C25.2801 8 25.6534 8 25.9387 7.85468C26.1895 7.72684 26.3935 7.52287 26.5213 7.27199C26.6667 6.98677 26.6667 6.6134 26.6667 5.86667V5.54858C26.6667 4.84573 26.6667 4.23939 26.6259 3.73997C26.5828 3.21284 26.4878 2.68855 26.2307 2.18404C25.8472 1.43139 25.2353 0.819471 24.4826 0.435977C23.9781 0.178919 23.4538 0.0838306 22.9267 0.0407626C22.4273 -4.14128e-05 21.8209 -2.17364e-05 21.1181 1.07313e-06Z"
fill="currentColor"
/>
<path
d="M26.6667 12.8C26.6667 12.0533 26.6667 11.6799 26.5213 11.3947C26.3935 11.1438 26.1895 10.9398 25.9387 10.812C25.6534 10.6667 25.2801 10.6667 24.5333 10.6667H12.8C12.0533 10.6667 11.6799 10.6667 11.3947 10.812C11.1438 10.9398 10.9398 11.1438 10.812 11.3947C10.6667 11.6799 10.6667 12.0533 10.6667 12.8L10.6667 24.5333C10.6667 25.2801 10.6667 25.6534 10.812 25.9387C10.9398 26.1895 11.1438 26.3935 11.3947 26.5213C11.6799 26.6667 12.0533 26.6667 12.8 26.6667H21.1181C21.8209 26.6667 22.4273 26.6667 22.9267 26.6259C23.4538 26.5828 23.9781 26.4878 24.4826 26.2307C25.2353 25.8472 25.8472 25.2353 26.2307 24.4826C26.4878 23.9781 26.5828 23.4538 26.6259 22.9267C26.6667 22.4273 26.6667 21.8209 26.6667 21.1181V12.8Z"
fill="currentColor"
/>
<path
d="M5.86667 26.6667C6.61341 26.6667 6.98677 26.6667 7.27199 26.5213C7.52287 26.3935 7.72685 26.1895 7.85468 25.9387C8 25.6534 8 25.2801 8 24.5333L8 12.8C8 12.0533 8 11.6799 7.85468 11.3947C7.72684 11.1438 7.52287 10.9398 7.27199 10.812C6.98677 10.6667 6.6134 10.6667 5.86667 10.6667H2.13333C1.3866 10.6667 1.01323 10.6667 0.728014 10.812C0.477131 10.9398 0.273157 11.1438 0.145326 11.3947C1.07288e-06 11.6799 1.07313e-06 12.0533 1.07313e-06 12.8V21.1181C-2.17364e-05 21.8209 -4.14128e-05 22.4273 0.0407626 22.9267C0.0838306 23.4538 0.178919 23.9781 0.435977 24.4826C0.819471 25.2353 1.43139 25.8472 2.18404 26.2307C2.68855 26.4878 3.21284 26.5828 3.73997 26.6259C4.23939 26.6667 4.84573 26.6667 5.54858 26.6667H5.86667Z"
fill="currentColor"
/>
</svg>
);
}
+7 -1
View File
@@ -29,6 +29,7 @@ export enum EWidgetChartTypes {
PIE_CHART = "PIE_CHART",
DONUT_CHART = "DONUT_CHART",
NUMBER = "NUMBER",
TABLE_CHART = "TABLE_CHART",
}
export enum EWidgetXAxisDateGrouping {
@@ -123,13 +124,18 @@ export type TNumberWidgetConfig = {
text_color?: string;
};
// combined
// table chart
export type TTableChartWidgetConfig = TBarChartWidgetConfig;
export type TDashboardWidgetConfig =
| TBarChartWidgetConfig
| TLineChartWidgetConfig
| TAreaChartWidgetConfig
| TDonutChartWidgetConfig
| TPieChartWidgetConfig
| TNumberWidgetConfig;
| TNumberWidgetConfig
| TTableChartWidgetConfig;
export type TDashboardWidget = {
chart_model: EWidgetChartModels | undefined;