Skip to content

Commit

Permalink
feat(aggregate-data-table): create aggregate data-table (dashboard)
Browse files Browse the repository at this point in the history
Signed-off-by: samuel.park <samuel.park@megazone.com>
  • Loading branch information
piggggggggy committed Jan 7, 2025
1 parent 30b1185 commit b355b2d
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ const state = reactive({
description: i18n.t('COMMON.WIDGETS.DATA_TABLE.FORM.QUERY_DESC'),
icon: 'ic_db-where',
},
{
key: DATA_TABLE_OPERATOR.AGGREGATE,
name: 'Aggregate',
description: i18n.t('COMMON.WIDGETS.DATA_TABLE.FORM.AGGREGATE_DESC'),
icon: 'ic_db-dimensions',
},
{
key: DATA_TABLE_OPERATOR.VALUE_MAPPING,
name: 'Value Mapping',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<script setup lang="ts">
import {
computed, reactive, ref, watch,
} from 'vue';
import { cloneDeep } from 'lodash';
import {
PFieldGroup, PSelectDropdown,
} from '@cloudforet/mirinae';
import type { SelectDropdownMenuItem } from '@cloudforet/mirinae/src/controls/dropdown/select-dropdown/type';
import type { MenuItem } from '@cloudforet/mirinae/types/inputs/context-menu/type';
import { i18n } from '@/translations';
import { showErrorMessage } from '@/lib/helper/notice-alert-helper';
import { useProxyValue } from '@/common/composables/proxy-state';
import WidgetFormDataTableCardTransformFormWrapper
from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformFormWrapper.vue';
import {
DATA_TABLE_OPERATOR,
} from '@/common/modules/widgets/_constants/data-table-constant';
import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store';
import type { TransformDataTableInfo, TransformDataTableProps } from '@/common/modules/widgets/types/widget-data-table-type';
import type { AggregateOptions } from '@/common/modules/widgets/types/widget-model';
const props = defineProps<TransformDataTableProps<AggregateOptions>>();
const emit = defineEmits<{(e: 'update:operator-options', value: AggregateOptions): void;
(e: 'update:invalid', value: boolean): void;
}>();
const widgetGenerateStore = useWidgetGenerateStore();
const widgetGenerateState = widgetGenerateStore.state;
const dataTableInfo = ref<TransformDataTableInfo>({
dataTableId: props.originData?.data_table_id,
});
const groupByInfo = ref<AggregateOptions['group_by']>(cloneDeep(props.originData.group_by));
const storeState = reactive({
dataTables: computed(() => widgetGenerateState.dataTables),
});
const state = reactive({
proxyOperatorOptions: useProxyValue<AggregateOptions>('operator-options', props, emit),
selectedDataTable: computed(() => storeState.dataTables.find((dataTable) => dataTable.data_table_id === dataTableInfo.value.dataTableId)),
invalid: computed<boolean>(() => {
if (!state.proxyOperatorOptions?.data_table_id) return true;
if (!state.proxyOperatorOptions.group_by?.length) return true;
return false;
}),
groupByFieldItems: computed<MenuItem[]>(() => {
if (!state.selectedDataTable) return [];
const labelsInfo = state.selectedDataTable.labels_info;
return Object.keys(labelsInfo).map((key) => ({
name: key,
label: key,
}));
}),
selectedGroupByItems: computed(() => {
if (!groupByInfo.value) return [];
return groupByInfo.value.map((groupBy) => ({
name: groupBy,
label: groupBy,
}));
}),
});
/* Event */
const handleUpdateSelectedGroupBy = (selected: SelectDropdownMenuItem[]) => {
const selectedGroupByItems = selected.map((item) => item.name);
groupByInfo.value = selectedGroupByItems;
};
const handleUpdateSelectGroupBy = (selectedItem: SelectDropdownMenuItem, isSelected: boolean) => {
if (isSelected && groupByInfo.value.length > 4) {
groupByInfo.value = groupByInfo.value.filter((groupBy) => groupBy !== selectedItem.name);
showErrorMessage(i18n.t('COMMON.WIDGETS.DATA_TABLE.FORM.ALT_E_ADD_GROUP_BY'), '');
}
};
/* Watcher */
watch([dataTableInfo, groupByInfo], ([_dataTableInfo, _groupByInfo]) => {
state.proxyOperatorOptions = {
data_table_id: _dataTableInfo.dataTableId,
group_by: _groupByInfo,
};
}, { deep: true, immediate: true });
watch(() => state.invalid, (_invalid) => {
emit('update:invalid', _invalid);
}, { immediate: true });
</script>
<template>
<div class="widget-form-data-table-card-transform-aggregate">
<widget-form-data-table-card-transform-form-wrapper :data-table-id="props.baseDataTableId"
:operator="DATA_TABLE_OPERATOR.AGGREGATE"
:data-table-info.sync="dataTableInfo"
>
<p-field-group :label="$t('COMMON.WIDGETS.DIMENSIONS')"
:help-text="$t('COMMON.WIDGETS.DIMENSIONS_DESC')"
style-type="secondary"
required
class="criteria-field"
>
<p-select-dropdown :menu="state.groupByFieldItems"
:selected="state.selectedGroupByItems"
multi-selectable
appearance-type="badge"
:page-size="10"
show-select-marker
is-filterable
block
@update:selected="handleUpdateSelectedGroupBy"
@select="handleUpdateSelectGroupBy"
/>
</p-field-group>
</widget-form-data-table-card-transform-form-wrapper>
</div>
</template>
<style lang="postcss" scoped>
.widget-form-data-table-card-transform-aggregate {
/* custom design-system component - p-field-title */
:deep(.p-field-title) {
.title {
@apply flex;
width: 100%;
}
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import WidgetFormDataTableCardHeaderTitle
from '@/common/modules/widgets/_components/WidgetFormDataTableCardHeaderTitle.vue';
import WidgetFormDataTableCardTransformAddLabels
from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformAddLabels.vue';
import WidgetFormDataTableCardTransformAggregate
from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformAggregate.vue';
import WidgetFormDataTableCardTransformConcatenate
from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformConcatenate.vue';
import WidgetFormDataTableCardTransformEvaluate
Expand All @@ -43,7 +45,7 @@ import type {
DataTableOperator, QueryOptions, EvalOptions,
DataTableTransformOptions,
AddLabelsOptions, PivotOptions,
JoinOptions, ValueMappingOptions, ConcatOptions,
JoinOptions, ValueMappingOptions, ConcatOptions, AggregateOptions, AggregateFunction,
} from '@/common/modules/widgets/types/widget-model';
Expand Down Expand Up @@ -92,6 +94,7 @@ const valueState = reactive({
JOIN: DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.JOIN,
EVAL: DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.EVAL,
QUERY: DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.QUERY,
AGGREGATE: DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.AGGREGATE,
ADD_LABELS: DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.ADD_LABELS,
VALUE_MAPPING: DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.VALUE_MAPPING,
});
Expand All @@ -101,6 +104,7 @@ const invalidState = reactive({
JOIN: false,
EVAL: false,
QUERY: false,
AGGREGATE: false,
ADD_LABELS: false,
VALUE_MAPPING: false,
});
Expand All @@ -115,6 +119,7 @@ const originState = reactive({
JOIN: computed<JoinOptions|undefined>(() => props.item.options.JOIN),
QUERY: computed<QueryOptions|undefined>(() => props.item.options.QUERY),
EVAL: computed<EvalOptions|undefined>(() => props.item.options.EVAL),
AGGREGATE: computed<AggregateOptions|undefined>(() => props.item.options.AGGREGATE),
ADD_LABELS: computed<AddLabelsOptions|undefined>(() => props.item.options.ADD_LABELS),
VALUE_MAPPING: computed<ValueMappingOptions|undefined>(() => props.item.options.VALUE_MAPPING),
PIVOT: computed<PivotOptions|undefined>(() => {
Expand All @@ -134,6 +139,15 @@ const originState = reactive({
const setFailStatus = (status: boolean) => {
state.failStatus = status;
};
const getAggregateFunctionMap = () => {
const referenceDataTable = storeState.dataTables.find((dataTable) => dataTable.data_table_id === valueState.AGGREGATE.data_table_id);
if (!referenceDataTable) return {};
const dataFields = Object.keys(referenceDataTable.data_info ?? {});
return dataFields.reduce((acc, dataField) => {
acc[dataField] = 'sum';
return acc;
}, {} as AggregateFunction);
};
const updateDataTable = async (): Promise<DataTableModel|undefined> => {
const _targetDataTableId: string|undefined = valueState[state.operator].data_table_id;
const _targetDataTables: string[]|undefined = valueState[state.operator].data_tables;
Expand Down Expand Up @@ -168,6 +182,7 @@ const updateDataTable = async (): Promise<DataTableModel|undefined> => {
const concatOptions = cloneDeep(valueState.CONCAT);
const joinOptions = cloneDeep(valueState.JOIN);
const queryOptions = cloneDeep(valueState.QUERY);
const aggregateOptions = cloneDeep(valueState.AGGREGATE);
const valueMappingOptions = cloneDeep(valueState.VALUE_MAPPING);
const evalOptions: EvalOptions = {
data_table_id: valueState.EVAL.data_table_id,
Expand Down Expand Up @@ -195,6 +210,11 @@ const updateDataTable = async (): Promise<DataTableModel|undefined> => {
return queryOptions;
case 'EVAL':
return evalOptions;
case 'AGGREGATE':
return {
...aggregateOptions,
function: getAggregateFunctionMap(),
};
case 'PIVOT':
return pivotOptions;
case 'ADD_LABELS':
Expand Down Expand Up @@ -281,6 +301,7 @@ const setInitialDataTableForm = () => {
valueState.JOIN = !isEmpty(originState.JOIN) ? cloneDeep(originState.JOIN) : cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.JOIN);
valueState.QUERY = !isEmpty(originState.QUERY) ? cloneDeep(originState.QUERY) : cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.QUERY);
valueState.EVAL = !isEmpty(originState.EVAL) ? cloneDeep(originState.EVAL) : cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.EVAL);
valueState.AGGREGATE = !isEmpty(originState.AGGREGATE) ? cloneDeep(originState.AGGREGATE) : cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.AGGREGATE);
valueState.ADD_LABELS = !isEmpty(originState.ADD_LABELS) ? cloneDeep(originState.ADD_LABELS) : cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.ADD_LABELS);
valueState.PIVOT = originState.PIVOT ? cloneDeep(originState.PIVOT) : cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.PIVOT);
valueState.VALUE_MAPPING = !isEmpty(originState.VALUE_MAPPING) ? cloneDeep(originState.VALUE_MAPPING) : cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.VALUE_MAPPING);
Expand Down Expand Up @@ -354,6 +375,13 @@ defineExpose({
:invalid.sync="invalidState.QUERY"
:origin-data="props.item.options[state.operator]"
/>
<widget-form-data-table-card-transform-aggregate v-else-if="state.operator === DATA_TABLE_OPERATOR.AGGREGATE"
:key="`aggregate-${state.resetKey}`"
:base-data-table-id="state.dataTableId"
:operator-options.sync="valueState.AGGREGATE"
:invalid.sync="invalidState.AGGREGATE"
:origin-data="props.item.options[state.operator]"
/>
<widget-form-data-table-card-transform-add-labels v-if="state.operator === DATA_TABLE_OPERATOR.ADD_LABELS"
:key="`add-labels-${state.resetKey}`"
:base-data-table-id="state.dataTableId"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const state = reactive({
if (props.operator === 'JOIN') return { name: 'Join', icon: 'ic_join' };
if (props.operator === 'QUERY') return { name: 'Query', icon: 'ic_db-where' };
if (props.operator === 'EVAL') return { name: 'Evaluate', icon: 'ic_db-evaluation' };
if (props.operator === 'AGGREGATE') return { name: 'Aggregate', icon: 'ic_db-dimensions' };
if (props.operator === 'PIVOT') return { name: 'Pivot', icon: 'ic_db-pivot-table' };
if (props.operator === 'VALUE_MAPPING') return { name: 'Value Mapping', icon: 'ic_db-value-mapping' };
if (props.operator === 'ADD_LABELS') return { name: 'Additional Labels', icon: 'ic_db-additional-labels' };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
AddLabelsOptions,
ConcatOptions, EvalOptions, JoinOptions, PivotOptions, QueryOptions, ValueMappingOptions,
AggregateOptions,
} from '@/common/modules/widgets/types/widget-model';

import { GROUP_BY } from '@/services/cost-explorer/constants/cost-explorer-constant';
Expand All @@ -21,7 +22,7 @@ export const DATA_TABLE_OPERATOR = {
CONCAT: 'CONCAT',
JOIN: 'JOIN',
QUERY: 'QUERY',
// AGGREGATE: 'AGGREGATE',
AGGREGATE: 'AGGREGATE',
EVAL: 'EVAL',
PIVOT: 'PIVOT',
ADD_LABELS: 'ADD_LABELS',
Expand Down Expand Up @@ -113,6 +114,11 @@ export const DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP = {
conditions: [''],
// operator: 'AND',
} as QueryOptions,
AGGREGATE: {
data_table_id: undefined,
group_by: [],
function: {},
} as AggregateOptions,
ADD_LABELS: {
data_table_id: undefined,
labels: { '': '' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ export const useWidgetGenerateStore = defineStore('widget-generate', () => {
CONCAT: cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.CONCAT),
QUERY: cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.QUERY),
EVAL: cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.EVAL),
AGGREGATE: cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.AGGREGATE),
PIVOT: cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.PIVOT),
ADD_LABELS: cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.ADD_LABELS),
VALUE_MAPPING: cloneDeep(DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP.VALUE_MAPPING),
Expand Down
6 changes: 5 additions & 1 deletion apps/web/src/common/modules/widgets/types/widget-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ export interface QueryOptions {
}

export interface AggregateOptions {
data_table_id: string;
data_table_id?: string;
group_by: string[];
function: AggregateFunction;
}
export interface AggregateFunction {
[key: string]: 'sum'|'max'|'min'|'mean';
}

export interface EvalOptions {
Expand Down
63 changes: 63 additions & 0 deletions packages/language-pack/console-translation-2.8.babel
Original file line number Diff line number Diff line change
Expand Up @@ -22250,6 +22250,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>AGGREGATE_DESC</name>
<definition_loaded>false</definition_loaded>
<description/>
<comment/>
<default_text/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>ja-JP</language>
<approved>false</approved>
</translation>
<translation>
<language>ko-KR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>ALT_E_ADD_GROUP_BY</name>
<definition_loaded>false</definition_loaded>
Expand Down Expand Up @@ -23692,6 +23713,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>DIMENSIONS</name>
<definition_loaded>false</definition_loaded>
<description/>
<comment/>
<default_text/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>ja-JP</language>
<approved>false</approved>
</translation>
<translation>
<language>ko-KR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>DIMENSIONS_DESC</name>
<definition_loaded>false</definition_loaded>
<description/>
<comment/>
<default_text/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>ja-JP</language>
<approved>false</approved>
</translation>
<translation>
<language>ko-KR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<folder_node>
<name>DISPLAY_ANNOTATION</name>
<children>
Expand Down
3 changes: 3 additions & 0 deletions packages/language-pack/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,7 @@
"ADD_LABELS_DESC": "Add labels to enhance data clarity.",
"ADD_RULE": "Add Rule",
"ADVANCED_OPTIONS": "Advanced Options",
"AGGREGATE_DESC": "Combine and group label fields using aggregation",
"ALT_E_ADD_GROUP_BY": "There can be a maximum of 3 group-by options.",
"BASED_ON": "Based On",
"CASES": "Cases",
Expand Down Expand Up @@ -1329,6 +1330,8 @@
},
"DEFAULT_WIDTH": "Default Width",
"DELETE": "Delete",
"DIMENSIONS": "Dimensions",
"DIMENSIONS_DESC": "Select up to 3 options to customize your view.",
"DISPLAY_ANNOTATION": {
"DISPLAY_ANNOTATION": "Additional Info",
"INVALID_VALUE": "Please enter info.",
Expand Down
Loading

0 comments on commit b355b2d

Please sign in to comment.