From 38f6c3678b05016ffb583286533b52d954e112c5 Mon Sep 17 00:00:00 2001 From: Dahyun Yu Date: Fri, 3 Jan 2025 13:46:53 +0900 Subject: [PATCH] feat: refactor xy charts with pivot data (#5390) * fix: apply pivot sort Signed-off-by: yuda * chore: fix type Signed-off-by: yuda * feat: refactor xy charts with pivot data Signed-off-by: yuda * fix: fix drawing pie chart Signed-off-by: yuda * fix: fix drawing Treemap Signed-off-by: yuda * chore: fix type Signed-off-by: yuda * chore: fix dropdown style issue Signed-off-by: yuda --------- Signed-off-by: yuda --- .../widgets/_composables/use-widget-frame.ts | 2 +- .../widgets/_helpers/widget-load-helper.ts | 5 +++- .../ClusteredColumnChart.vue | 16 +++++++++---- .../color-coded-heatmap/ColorCodedHeatmap.vue | 6 ++--- .../ColorCodedTableHeatmap.vue | 24 ++++++++++++------- .../modules/widgets/_widgets/gauge/Gauge.vue | 8 +++---- .../widgets/_widgets/line-chart/LineChart.vue | 15 ++++++++---- .../widgets/_widgets/pie-chart/PieChart.vue | 14 ++++++----- .../StackedColumnChart.vue | 19 ++++++++------- .../StackedHorizontalBarChart.vue | 18 +++++++------- .../widgets/_widgets/treemap/Treemap.vue | 11 ++++----- .../DashboardFolderTreeItem.vue | 1 + .../dashboard-main/DashboardLSBTree.vue | 1 + 13 files changed, 84 insertions(+), 56 deletions(-) diff --git a/apps/web/src/common/modules/widgets/_composables/use-widget-frame.ts b/apps/web/src/common/modules/widgets/_composables/use-widget-frame.ts index ffe55da94c..dfebe0fc0d 100644 --- a/apps/web/src/common/modules/widgets/_composables/use-widget-frame.ts +++ b/apps/web/src/common/modules/widgets/_composables/use-widget-frame.ts @@ -37,7 +37,7 @@ import { COST_EXPLORER_ROUTE } from '@/services/cost-explorer/routes/route-const interface OverridableWidgetFrameState { dateRange?: DateRange | ComputedRef; - errorMessage?: string | ComputedRef; + errorMessage?: string | ComputedRef; widgetLoading?: boolean | ComputedRef; noData?: boolean | ComputedRef; } diff --git a/apps/web/src/common/modules/widgets/_helpers/widget-load-helper.ts b/apps/web/src/common/modules/widgets/_helpers/widget-load-helper.ts index bdc5ca8e7b..36d9e48e31 100644 --- a/apps/web/src/common/modules/widgets/_helpers/widget-load-helper.ts +++ b/apps/web/src/common/modules/widgets/_helpers/widget-load-helper.ts @@ -36,9 +36,12 @@ export const getWidgetLoadApiQueryDateRange = (granularity: string, dateRange: D return dateRange; }; -export const getWidgetLoadApiQuerySort = (xAxisField: string, dataField: string[]): Query['sort'] => { +export const getWidgetLoadApiQuerySort = (xAxisField: string, dataField: string[], isPivot?: boolean): Query['sort'] => { if (xAxisField === 'Date') { return [{ key: 'Date', desc: true }]; } + if (isPivot) { + return [{ key: 'Sub Total', desc: true }]; + } return dataField.map((field) => ({ key: field, desc: true })); }; diff --git a/apps/web/src/common/modules/widgets/_widgets/clustered-column-chart/ClusteredColumnChart.vue b/apps/web/src/common/modules/widgets/_widgets/clustered-column-chart/ClusteredColumnChart.vue index c59ce1ac23..0dc3b01e84 100644 --- a/apps/web/src/common/modules/widgets/_widgets/clustered-column-chart/ClusteredColumnChart.vue +++ b/apps/web/src/common/modules/widgets/_widgets/clustered-column-chart/ClusteredColumnChart.vue @@ -70,6 +70,7 @@ const state = reactive({ runQueries: false, isPrivateWidget: computed(() => props.widgetId.startsWith('private')), dataTable: undefined as PublicDataTableModel|PrivateDataTableModel|undefined, + isPivot: computed(() => state.dataTable?.operator === 'PIVOT'), unitMap: computed>(() => widgetFrameProps.value.unitMap || {}), data: computed(() => queryResult.data?.value ?? null), @@ -193,7 +194,7 @@ const queryResult = useQuery({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: widgetOptionsState.xAxisInfo?.data ? [widgetOptionsState.xAxisInfo?.data] : [], - sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[]), + sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[], state.isPivot), page: { start: 0, limit: widgetOptionsState.xAxisInfo?.count }, vars: props.dashboardVars, ...getWidgetLoadApiQueryDateRange(widgetOptionsState.granularityInfo?.granularity, dateRange.value), @@ -202,8 +203,8 @@ const queryResult = useQuery({ staleTime: WIDGET_LOAD_STALE_TIME, }); -const widgetLoading = computed(() => queryResult.isLoading); -const errorMessage = computed(() => queryResult.error?.value?.message); +const widgetLoading = computed(() => queryResult.isLoading.value); +const errorMessage = computed(() => queryResult.error?.value?.message); /* Util */ const getThreshold = (rawData: WidgetLoadResponse): number => { @@ -234,7 +235,12 @@ const drawChart = (rawData: WidgetLoadResponse|null) => { } const _seriesData: any[] = []; - (widgetOptionsState.dataFieldInfo?.data as string[])?.forEach((field) => { + let _dataFields: string[] = widgetOptionsState.dataFieldInfo?.data as string[] || []; + if (state.isPivot) { + _dataFields = rawData.order?.filter((v) => widgetOptionsState.dataFieldInfo?.data?.includes(v)) || []; + } + _dataFields.forEach((field) => { + if (!widgetOptionsState.dataFieldInfo?.data?.includes(field)) return; const _unit: string|undefined = state.unitMap[field]; _seriesData.push({ name: field, @@ -267,7 +273,7 @@ const loadWidget = () => { const { widgetFrameProps, widgetFrameEventHandlers } = useWidgetFrame(props, emit, { dateRange, errorMessage, - widgetLoading: widgetLoading.value, + widgetLoading, noData: computed(() => (state.data ? !state.data?.results?.length : false)), }); diff --git a/apps/web/src/common/modules/widgets/_widgets/color-coded-heatmap/ColorCodedHeatmap.vue b/apps/web/src/common/modules/widgets/_widgets/color-coded-heatmap/ColorCodedHeatmap.vue index 01c44553dd..489b2619d9 100644 --- a/apps/web/src/common/modules/widgets/_widgets/color-coded-heatmap/ColorCodedHeatmap.vue +++ b/apps/web/src/common/modules/widgets/_widgets/color-coded-heatmap/ColorCodedHeatmap.vue @@ -113,8 +113,8 @@ const queryResult = useQuery({ staleTime: WIDGET_LOAD_STALE_TIME, }); -const widgetLoading = computed(() => queryResult.isLoading); -const errorMessage = computed(() => queryResult.error?.value?.message); +const widgetLoading = computed(() => queryResult.isLoading.value); +const errorMessage = computed(() => queryResult.error?.value?.message); const refinedData = computed(() => { const data = queryResult.data?.value; @@ -144,7 +144,7 @@ const refinedData = computed(() => { const { widgetFrameProps, widgetFrameEventHandlers } = useWidgetFrame(props, emit, { dateRange, errorMessage, - widgetLoading: widgetLoading.value, + widgetLoading, noData: computed(() => (refinedData.value ? !(refinedData.value?.length) : false)), }); diff --git a/apps/web/src/common/modules/widgets/_widgets/color-coded-table-heatmap/ColorCodedTableHeatmap.vue b/apps/web/src/common/modules/widgets/_widgets/color-coded-table-heatmap/ColorCodedTableHeatmap.vue index a14f703e57..aa049c676f 100644 --- a/apps/web/src/common/modules/widgets/_widgets/color-coded-table-heatmap/ColorCodedTableHeatmap.vue +++ b/apps/web/src/common/modules/widgets/_widgets/color-coded-table-heatmap/ColorCodedTableHeatmap.vue @@ -63,8 +63,9 @@ const state = reactive({ runQueries: false, isPrivateWidget: computed(() => props.widgetId.startsWith('private')), dataTable: undefined as PublicDataTableModel|PrivateDataTableModel|undefined, + isPivot: computed(() => state.dataTable?.operator === 'PIVOT'), - data: computed(() => queryResult.data?.value), + data: computed(() => queryResult.data?.value), // unit: computed(() => widgetFrameProps.value.unitMap?.[state.dataField]), boxWidth: BOX_MIN_WIDTH, boxHeight: 0, @@ -78,7 +79,11 @@ const state = reactive({ }), yAxisData: computed(() => { if (!state.data?.results?.length) return []; - return (widgetOptionsState.dataFieldInfo?.data ?? []) as string[]; + let _dataFields: string[] = widgetOptionsState.dataFieldInfo?.data as string[] || []; + if (state.isPivot) { + _dataFields = state.data?.order?.filter((v) => widgetOptionsState.dataFieldInfo?.data?.includes(v)) || []; + } + return _dataFields; }), legendList: [] as WidgetLegend[], widgetDateRange: computed(() => { @@ -95,6 +100,7 @@ const widgetOptionsState = reactive({ granularityInfo: computed(() => props.widgetOptions?.granularity?.value as GranularityValue), dataFieldInfo: computed(() => props.widgetOptions?.dataField?.value as DataFieldValue), xAxisInfo: computed(() => props.widgetOptions?.xAxis?.value as XAxisValue), + xAxisCount: computed(() => widgetOptionsState.xAxisInfo?.count || 0), formatRulesInfo: computed(() => props.widgetOptions?.formatRules?.value as FormatRulesValue), numberFormatInfo: computed(() => props.widgetOptions?.numberFormat?.value as NumberFormatValue), }); @@ -137,8 +143,8 @@ const queryResult = useQuery({ staleTime: WIDGET_LOAD_STALE_TIME, }); -const widgetLoading = computed(() => queryResult.isLoading); -const errorMessage = computed(() => queryResult.error?.value?.message); +const widgetLoading = computed(() => queryResult.isLoading.value); +const errorMessage = computed(() => queryResult.error?.value?.message); /* Util */ const loadWidget = async () => { @@ -203,13 +209,13 @@ useResizeObserver(colorCodedTableRef, throttle(() => { if (!_containerWidth || !_containerHeight) return; // width - const boxWidth = (_containerWidth - Y_AXIS_FIELD_WIDTH) / state.xAxisCount; + const boxWidth = (_containerWidth - Y_AXIS_FIELD_WIDTH) / widgetOptionsState.xAxisCount; if (boxWidth < BOX_MIN_WIDTH) state.boxWidth = BOX_MIN_WIDTH - 2; else state.boxWidth = boxWidth - 2; // height - const yAxisCount = state.yAxisData.length; - const boxHeight = _containerHeight / yAxisCount; + const yAxisCount = state.yAxisData.length || 1; + const boxHeight = (_containerHeight - 16) / yAxisCount; const padding = 20 / yAxisCount; if (boxHeight < 32) state.boxHeight = 32 - padding; else state.boxHeight = boxHeight - padding; @@ -291,12 +297,12 @@ useResizeObserver(colorCodedTableRef, throttle(() => { .table-wrapper { display: flex; width: 100%; - height: 82%; + height: 95%; gap: 0.25rem; overflow: auto; margin-top: 1rem; &.overlay { - height: 90%; + height: 95%; } .y-axis-wrapper { .y-col { diff --git a/apps/web/src/common/modules/widgets/_widgets/gauge/Gauge.vue b/apps/web/src/common/modules/widgets/_widgets/gauge/Gauge.vue index 4412fcaf99..0da374e685 100644 --- a/apps/web/src/common/modules/widgets/_widgets/gauge/Gauge.vue +++ b/apps/web/src/common/modules/widgets/_widgets/gauge/Gauge.vue @@ -168,8 +168,8 @@ const queryResult = useQuery({ staleTime: WIDGET_LOAD_STALE_TIME, }); -const widgetLoading = computed(() => queryResult.isLoading); -const errorMessage = computed(() => queryResult.error?.value?.message); +const widgetLoading = computed(() => queryResult.isLoading.value); +const errorMessage = computed(() => queryResult.error?.value?.message); /* Util */ const drawChart = (rawData: WidgetLoadResponse|null) => { @@ -184,11 +184,11 @@ const loadWidget = () => { const { widgetFrameProps, widgetFrameEventHandlers } = useWidgetFrame(props, emit, { dateRange, errorMessage, - widgetLoading: widgetLoading.value, + widgetLoading, }); /* Watcher */ -watch([() => state.chartData, () => chartContext.value], ([, chartCtx]) => { +watch([() => state.chartData, () => chartContext.value, () => props.widgetOptions], ([, chartCtx]) => { if (chartCtx) { state.chart = init(chartContext.value); state.chart.setOption(state.chartOptions, true); diff --git a/apps/web/src/common/modules/widgets/_widgets/line-chart/LineChart.vue b/apps/web/src/common/modules/widgets/_widgets/line-chart/LineChart.vue index 18b5f56f9c..9e074b7792 100644 --- a/apps/web/src/common/modules/widgets/_widgets/line-chart/LineChart.vue +++ b/apps/web/src/common/modules/widgets/_widgets/line-chart/LineChart.vue @@ -69,6 +69,7 @@ const state = reactive({ runQueries: false, isPrivateWidget: computed(() => props.widgetId.startsWith('private')), dataTable: undefined as PublicDataTableModel|PrivateDataTableModel|undefined, + isPivot: computed(() => state.dataTable?.operator === 'PIVOT'), data: computed(() => queryResult?.data?.value || null), chart: null as EChartsType | null, @@ -199,7 +200,7 @@ const queryResult = useQuery({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: widgetOptionsState.xAxisInfo?.data ? [widgetOptionsState.xAxisInfo?.data] : [], - sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[]), + sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[], state.isPivot), page: { start: 0, limit: widgetOptionsState.xAxisInfo?.count }, vars: props.dashboardVars, ...getWidgetLoadApiQueryDateRange(widgetOptionsState.granularityInfo?.granularity, dateRange.value), @@ -208,8 +209,8 @@ const queryResult = useQuery({ staleTime: WIDGET_LOAD_STALE_TIME, }); -const widgetLoading = computed(() => queryResult.isLoading); -const errorMessage = computed(() => queryResult.error?.value?.message); +const widgetLoading = computed(() => queryResult.isLoading.value); +const errorMessage = computed(() => queryResult.error?.value?.message); /* Util */ const drawChart = (rawData: WidgetLoadResponse|null) => { @@ -217,7 +218,11 @@ const drawChart = (rawData: WidgetLoadResponse|null) => { const _seriesData: any[] = []; const _defaultValue = widgetOptionsState.missingValueInfo?.type === 'lineToZero' ? 0 : undefined; - (widgetOptionsState.dataFieldInfo?.data as string[] ?? []).forEach((_dataField) => { + let _dataFields: string[] = widgetOptionsState.dataFieldInfo?.data as string[] || []; + if (state.isPivot) { + _dataFields = rawData.order?.filter((v) => widgetOptionsState.dataFieldInfo?.data?.includes(v)) || []; + } + _dataFields.forEach((_dataField) => { const _unit: string|undefined = state.unitMap[_dataField]; _seriesData.push({ name: _dataField, @@ -258,7 +263,7 @@ watch([() => state.data, () => props.widgetOptions], ([newData]) => { const { widgetFrameProps, widgetFrameEventHandlers } = useWidgetFrame(props, emit, { dateRange, errorMessage, - widgetLoading: widgetLoading.value, + widgetLoading, noData: computed(() => (state.data ? !state.data.results?.length : false)), }); diff --git a/apps/web/src/common/modules/widgets/_widgets/pie-chart/PieChart.vue b/apps/web/src/common/modules/widgets/_widgets/pie-chart/PieChart.vue index b8895dfd56..bc3f57f866 100644 --- a/apps/web/src/common/modules/widgets/_widgets/pie-chart/PieChart.vue +++ b/apps/web/src/common/modules/widgets/_widgets/pie-chart/PieChart.vue @@ -14,7 +14,7 @@ import type { } from 'echarts/core'; import type { LegendOption, EChartsOption } from 'echarts/types/dist/shared'; import { - groupBy, isEmpty, orderBy, throttle, sumBy, + isEmpty, orderBy, throttle, } from 'lodash'; import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; @@ -58,6 +58,8 @@ import type { import { MASSIVE_CHART_COLORS } from '@/styles/colorsets'; + + interface ChartData { name: string; value: number; @@ -235,12 +237,12 @@ const drawChart = (rawData: WidgetLoadResponse|null) => { if (isEmpty(rawData)) return; // get chart data - const _groupByData = groupBy(rawData.results || [], widgetOptionsState.groupByInfo?.data); - let _refinedData: ChartData[] = Object.entries(_groupByData).map(([k, v]) => ({ - name: k, - value: sumBy(v, widgetOptionsState.groupByInfo?.data as string), + const _groupByData = rawData?.results || []; + let _refinedData: ChartData[] = _groupByData.map((d) => ({ + name: d[widgetOptionsState.groupByInfo?.data as string] as string, + value: d[widgetOptionsState.dataFieldInfo?.data as string] as number, })); - if (isDateField(state.groupByField)) { + if (isDateField(widgetOptionsState.groupByInfo?.data as string)) { _refinedData = orderBy(_refinedData, 'name', 'desc'); _refinedData = _refinedData?.slice(0, widgetOptionsState.groupByInfo?.count); } else { diff --git a/apps/web/src/common/modules/widgets/_widgets/stacked-column-chart/StackedColumnChart.vue b/apps/web/src/common/modules/widgets/_widgets/stacked-column-chart/StackedColumnChart.vue index cc91340be1..1851d21c2a 100644 --- a/apps/web/src/common/modules/widgets/_widgets/stacked-column-chart/StackedColumnChart.vue +++ b/apps/web/src/common/modules/widgets/_widgets/stacked-column-chart/StackedColumnChart.vue @@ -71,6 +71,7 @@ const state = reactive({ runQueries: false, isPrivateWidget: computed(() => props.widgetId.startsWith('private')), dataTable: undefined as PublicDataTableModel|PrivateDataTableModel|undefined, + isPivot: computed(() => state.dataTable?.operator === 'PIVOT'), data: computed(() => queryResult?.data?.value || null), xAxisData: computed(() => { @@ -194,7 +195,7 @@ const queryResult = useQuery({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: widgetOptionsState.xAxisInfo?.data ? [widgetOptionsState.xAxisInfo?.data] : [], - sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[]), + sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[], state.isPivot), page: { start: 0, limit: widgetOptionsState.xAxisInfo?.count }, vars: props.dashboardVars, ...getWidgetLoadApiQueryDateRange(widgetOptionsState.granularityInfo?.granularity, dateRange.value), @@ -203,19 +204,21 @@ const queryResult = useQuery({ staleTime: WIDGET_LOAD_STALE_TIME, }); -const widgetLoading = computed(() => queryResult.isLoading); -const errorMessage = computed(() => queryResult.error?.value?.message); +const widgetLoading = computed(() => queryResult.isLoading.value); +const errorMessage = computed(() => queryResult.error?.value?.message); /* Util */ const drawChart = (rawData?: WidgetLoadResponse|null) => { if (isEmpty(rawData)) return; - // const _maxTotalCount = rawData?.results?.[0]?.[`_total_${state.dataField}`] ?? 0; - // const _threshold = _maxTotalCount * 0.08; - const _seriesData: any[] = []; - (widgetOptionsState.dataFieldInfo?.data as string[])?.forEach((_dataField) => { + let _dataFields: string[] = widgetOptionsState.dataFieldInfo?.data as string[] || []; + if (state.isPivot) { + _dataFields = rawData.order?.filter((v) => widgetOptionsState.dataFieldInfo?.data?.includes(v)) || []; + } + _dataFields.forEach((_dataField) => { + if (!widgetOptionsState.dataFieldInfo?.data?.includes(_dataField)) return; const _unit: string|undefined = state.unitMap[_dataField]; _seriesData.push({ name: _dataField, @@ -247,7 +250,7 @@ const loadWidget = () => { const { widgetFrameProps, widgetFrameEventHandlers } = useWidgetFrame(props, emit, { dateRange, errorMessage, - widgetLoading: widgetLoading.value, + widgetLoading, noData: computed(() => (state.data ? !state.data.results?.length : false)), }); diff --git a/apps/web/src/common/modules/widgets/_widgets/stacked-horizontal-bar-chart/StackedHorizontalBarChart.vue b/apps/web/src/common/modules/widgets/_widgets/stacked-horizontal-bar-chart/StackedHorizontalBarChart.vue index 258041e96e..196c14d3fe 100644 --- a/apps/web/src/common/modules/widgets/_widgets/stacked-horizontal-bar-chart/StackedHorizontalBarChart.vue +++ b/apps/web/src/common/modules/widgets/_widgets/stacked-horizontal-bar-chart/StackedHorizontalBarChart.vue @@ -66,6 +66,7 @@ const state = reactive({ runQueries: false, isPrivateWidget: computed(() => props.widgetId.startsWith('private')), dataTable: undefined as PublicDataTableModel|PrivateDataTableModel|undefined, + isPivot: computed(() => state.dataTable?.operator === 'PIVOT'), data: computed(() => queryResult?.data?.value || null), yAxisData: computed(() => { @@ -186,7 +187,7 @@ const queryResult = useQuery({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: widgetOptionsState.yAxisInfo?.data ? [widgetOptionsState.yAxisInfo?.data] : [], - sort: getWidgetLoadApiQuerySort(widgetOptionsState.yAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[]), + sort: getWidgetLoadApiQuerySort(widgetOptionsState.yAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[], state.isPivot), page: { start: 0, limit: widgetOptionsState.yAxisInfo?.count }, vars: props.dashboardVars, ...getWidgetLoadApiQueryDateRange(widgetOptionsState.granularityInfo?.granularity, dateRange.value), @@ -195,18 +196,19 @@ const queryResult = useQuery({ staleTime: WIDGET_LOAD_STALE_TIME, }); -const widgetLoading = computed(() => queryResult.isLoading); -const errorMessage = computed(() => queryResult.error?.value?.message); +const widgetLoading = computed(() => queryResult.isLoading.value); +const errorMessage = computed(() => queryResult.error?.value?.message); /* Util */ const drawChart = (rawData?: WidgetLoadResponse|null) => { if (isEmpty(rawData)) return; - // const _maxTotalCount = rawData?.results?.[0]?.[`_total_${state.dataField}`] ?? 0; - // const _threshold = _maxTotalCount * 0.08; - const _seriesData: any[] = []; - (widgetOptionsState.dataFieldInfo?.data as string[])?.forEach((_dataField) => { + let _dataFields: string[] = widgetOptionsState.dataFieldInfo?.data as string[] || []; + if (state.isPivot) { + _dataFields = rawData.order?.filter((v) => widgetOptionsState.dataFieldInfo?.data?.includes(v)) || []; + } + _dataFields.forEach((_dataField) => { const _unit: string|undefined = state.unitMap[_dataField]; _seriesData.push({ name: _dataField, @@ -234,7 +236,7 @@ const loadWidget = () => { const { widgetFrameProps, widgetFrameEventHandlers } = useWidgetFrame(props, emit, { dateRange, errorMessage, - widgetLoading: widgetLoading.value, + widgetLoading, noData: computed(() => (state.data ? !state.data.results?.length : false)), }); diff --git a/apps/web/src/common/modules/widgets/_widgets/treemap/Treemap.vue b/apps/web/src/common/modules/widgets/_widgets/treemap/Treemap.vue index 9086193041..a6ef560075 100644 --- a/apps/web/src/common/modules/widgets/_widgets/treemap/Treemap.vue +++ b/apps/web/src/common/modules/widgets/_widgets/treemap/Treemap.vue @@ -12,7 +12,7 @@ import type { EChartsType, } from 'echarts/core'; import { - groupBy, isEmpty, orderBy, sumBy, throttle, + isEmpty, orderBy, throttle, } from 'lodash'; import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; @@ -178,11 +178,10 @@ const errorMessage = computed(() => queryResult.error?.value?.message); const drawChart = (rawData: WidgetLoadResponse|null) => { if (isEmpty(rawData)) return; - const _categoryByData = groupBy(rawData.results || [], widgetOptionsState.categoryByInfo?.data); - let _refinedData: ChartData[] = Object.entries(_categoryByData).map(([k, v]) => ({ - name: k, - value: sumBy(v, widgetOptionsState.dataFieldInfo?.data as string), - })); + let _refinedData: ChartData[] = rawData?.results?.map((d) => ({ + name: d[widgetOptionsState.categoryByInfo?.data as string], + value: d[widgetOptionsState.dataFieldInfo?.data as string], + })) || []; if (isDateField(widgetOptionsState.categoryByInfo?.data)) { _refinedData = orderBy(_refinedData, 'name', 'desc'); _refinedData = _refinedData?.slice(0, widgetOptionsState.categoryByInfo?.count); diff --git a/apps/web/src/services/dashboards/components/dashboard-folder/DashboardFolderTreeItem.vue b/apps/web/src/services/dashboards/components/dashboard-folder/DashboardFolderTreeItem.vue index ff04b7fbe2..9a60b5be3a 100644 --- a/apps/web/src/services/dashboards/components/dashboard-folder/DashboardFolderTreeItem.vue +++ b/apps/web/src/services/dashboards/components/dashboard-folder/DashboardFolderTreeItem.vue @@ -167,6 +167,7 @@ const handleSelectControlButton = (id: string, item: MenuItem) => { size="sm" menu-position="left" reset-selection-on-menu-close + use-fixed-menu-style @select="handleSelectControlButton(node.data.id, $event)" /> { size="sm" menu-position="left" reset-selection-on-menu-close + use-fixed-menu-style @select="handleSelectControlButton(node.data.id, $event)" />