Skip to content

Commit

Permalink
feat(widget-form): apply field-value-manager to widget form & refacto…
Browse files Browse the repository at this point in the history
…r field-value-manager (#5233)

* fix(field-value-manager): replace data proxy to reactivity vue ref & refactor method

Signed-off-by: samuel.park <[email protected]>

* fix(widget-form): apply field manager to widget form

Signed-off-by: samuel.park <[email protected]>

* fix(widget-load): apply new widget load params

Signed-off-by: samuel.park <[email protected]>

* chore: add defense code

Signed-off-by: samuel.park <[email protected]>

---------

Signed-off-by: samuel.park <[email protected]>
  • Loading branch information
piggggggggy authored Dec 17, 2024
1 parent bb868cd commit 10c8949
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { WIDGET_WIDTH_RANGE_LIST } from '@/common/modules/widgets/_constants/wid
import { getWidgetComponent } from '@/common/modules/widgets/_helpers/widget-component-helper';
import { getWidgetConfig } from '@/common/modules/widgets/_helpers/widget-config-helper';
import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store';
import type { WidgetFieldValues } from '@/common/modules/widgets/types/widget-field-value-type';
import WidgetFieldValueManager from '@/common/modules/widgets/_widget-field-value-manager';
import type { WidgetType } from '@/common/modules/widgets/types/widget-model';
import DashboardToolsetDateDropdown from '@/services/dashboards/components/dashboard-detail/DashboardToolsetDateDropdown.vue';
Expand Down Expand Up @@ -53,8 +53,21 @@ const storeState = reactive({
isAdminMode: computed(() => appContextStore.getters.isAdminMode),
});
let fieldManager: WidgetFieldValueManager;
const state = reactive({
mounted: false,
fieldManager: computed<WidgetFieldValueManager>(() => {
if (!fieldManager) {
fieldManager = new WidgetFieldValueManager(
getWidgetConfig(widgetGenerateState.selectedWidgetName),
widgetGenerateGetters.selectedDataTable,
widgetGenerateState.widget?.options || {},
);
}
return fieldManager;
}),
value: computed(() => state.fieldManager?.data?.granularity),
widgetConfig: computed(() => getWidgetConfig(widgetGenerateState.selectedWidgetName)),
selectedWidgetType: widgetGenerateState.widget?.widget_type as WidgetType,
allReferenceTypeInfo: computed<AllReferenceTypeInfo>(() => allReferenceTypeInfoStore.getters.allReferenceTypeInfo),
Expand All @@ -75,13 +88,13 @@ const state = reactive({
return WIDGET_WIDTH_RANGE_LIST[state.widgetSize]?.[0] || 0;
}),
isWidgetFieldChanged: computed<boolean>(() => {
const _isOptionsChanged = isWidgetOptionsChanged(false, widgetGenerateState.widgetFormValueMap, widgetGenerateState.widget?.options || {});
const _isOptionsChanged = !isEqual(state.fieldManager.data, widgetGenerateState.widget?.options);
const _isTypeChanged = widgetGenerateState.selectedWidgetName !== widgetGenerateState.widget?.widget_type;
emit('watch-options-changed', _isOptionsChanged || _isTypeChanged);
return _isOptionsChanged || _isTypeChanged;
}),
disableApplyButton: computed<boolean>(() => {
if (!widgetGenerateGetters.isAllWidgetFormValid) return true;
if (!state.fieldManager?.validateAll()) return true;
const _isWidgetInactive = widgetGenerateState.widget?.state === 'INACTIVE';
return (!_isWidgetInactive && !state.isWidgetFieldChanged) || widgetOptionsInvalid.value;
}),
Expand All @@ -102,38 +115,24 @@ const {
/* Api */
const updateWidget = async () => {
const _isCreating = widgetGenerateState.widget?.state === 'CREATING';
await widgetGenerateStore.updateWidget({
const widget = await widgetGenerateStore.updateWidget({
widget_id: widgetGenerateState.widgetId,
size: widgetGenerateState.size,
widget_type: widgetGenerateState.selectedWidgetName,
data_table_id: widgetGenerateState.selectedDataTableId,
options: widgetGenerateState.widgetFormValueMap,
options: state.fieldManager.data,
state: 'ACTIVE',
});
if (widget) {
state.fieldManager.updateOriginData(widget.options);
}
if (_isCreating) {
await dashboardStore.addWidgetToDashboard(dashboardDetailState.dashboardId || '', widgetGenerateState.widgetId);
}
};
/* Util */
const isWidgetOptionsChanged = (
isChanged: boolean,
widgetForm: Record<string, WidgetFieldValues|undefined>,
widgetOptions: Record<string, WidgetFieldValues|undefined>,
): boolean => {
if (isChanged) return true;
let _isChanged = false;
Object.entries(widgetForm).forEach(([k, v]) => {
if (_isChanged) return;
if (typeof v === 'object' && !Array.isArray(v)) {
_isChanged = isWidgetOptionsChanged(_isChanged, v, widgetOptions?.[k]);
return;
}
_isChanged = !isEqual(widgetOptions?.[k], v);
});
return _isChanged;
};
const initSnapshot = () => {
state.varsSnapshot = cloneDeep(dashboardDetailState.vars);
state.dashboardOptionsSnapshot = cloneDeep(dashboardDetailState.options);
Expand Down Expand Up @@ -197,6 +196,7 @@ onBeforeMount(() => {
onUnmounted(() => {
reset();
});
</script>

<template>
Expand Down Expand Up @@ -262,9 +262,10 @@ onUnmounted(() => {
/>
</div>
</div>
<widget-form-overlay-step2-widget-form v-if="widgetGenerateState.overlayType !== 'EXPAND'"
<widget-form-overlay-step2-widget-form v-if="widgetGenerateState.overlayType !== 'EXPAND' && !!state.fieldManager"
:widget-validation-invalid="widgetOptionsInvalid"
:widget-validation-invalid-text="widgetOptionsInvalidText"
:field-manager="state.fieldManager"
/>
<portal to="apply-button">
<p-button v-if="widgetGenerateState.overlayType !== 'EXPAND'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ import { DATA_TABLE_TYPE } from '@/common/modules/widgets/_constants/data-table-
import { WIDGET_COMPONENT_ICON_MAP } from '@/common/modules/widgets/_constants/widget-components-constant';
import { CONSOLE_WIDGET_CONFIG } from '@/common/modules/widgets/_constants/widget-config-list-constant';
import { DATE_FIELD } from '@/common/modules/widgets/_constants/widget-constant';
import { getWidgetFieldComponent } from '@/common/modules/widgets/_helpers/widget-component-helper';
import {
getWidgetFieldComponent,
} from '@/common/modules/widgets/_helpers/widget-component-helper';
import { getWidgetConfig } from '@/common/modules/widgets/_helpers/widget-config-helper';
import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store';
import type WidgetFieldValueManager from '@/common/modules/widgets/_widget-field-value-manager';
import WidgetHeaderField from '@/common/modules/widgets/_widget-fields/header/WidgetHeaderField.vue';
import type { WidgetFieldValues } from '@/common/modules/widgets/types/widget-field-value-type';
import type { DataTableAddOptions } from '@/common/modules/widgets/types/widget-model';
import { red } from '@/styles/colors';
import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store';
const FORM_TITLE_MAP = {
DATE_CONFIG: 'DATE_CONFIG',
Expand All @@ -39,15 +39,14 @@ const DATE_CONFIG_FIELD_KEYS = ['granularity', 'dateRange'];
interface Props {
widgetValidationInvalid?: boolean;
widgetValidationInvalidText?: string|TranslateResult;
fieldManager: WidgetFieldValueManager;
}
const props = defineProps<Props>();
const widgetGenerateStore = useWidgetGenerateStore();
const widgetGenerateState = widgetGenerateStore.state;
const widgetGenerateGetters = widgetGenerateStore.getters;
const dashboardDetailStore = useDashboardDetailInfoStore();
const dashboardDetailState = dashboardDetailStore.state;
const state = reactive({
chartTypeMenuItems: computed<MenuItem[]>(() => Object.values(CONSOLE_WIDGET_CONFIG).map((d) => ({
name: d.widgetName,
Expand Down Expand Up @@ -81,11 +80,15 @@ const state = reactive({
/* Event */
const handleSelectDataTable = async (dataTableId: string) => {
const selectedDataTable = widgetGenerateState.dataTables.find((d) => d.data_table_id === dataTableId);
if (!selectedDataTable) return;
widgetGenerateStore.setSelectedDataTableId(dataTableId);
await widgetGenerateStore.updateWidget({
data_table_id: dataTableId,
state: 'INACTIVE',
});
props.fieldManager.updateDataTableAndOriginData(selectedDataTable, {});
};
const checkDefaultValidation = () => {
Expand Down Expand Up @@ -122,19 +125,16 @@ const checkDefaultValidation = () => {
}
};
const handleShowErrorModal = (value:number|undefined) => {
state.widgetDefaultValidationModalVisible = true;
state.formErrorModalValue = value;
};
const handleSelectWidgetName = (widgetName: string) => {
if (widgetName === widgetGenerateState.selectedWidgetName) return;
const _config = getWidgetConfig(widgetName);
if (widgetName === widgetGenerateState.selectedWidgetName || !_config) return;
widgetGenerateStore.setSelectedWidgetName(widgetName);
const _config = getWidgetConfig(widgetName);
widgetGenerateStore.setSize(_config.meta.sizes[0]);
widgetGenerateStore.setWidgetFormValueMap({});
widgetGenerateStore.setWidgetValidMap({});
props.fieldManager.updateWidgetType(_config);
checkDefaultValidation();
};
const handleClickEditDataTable = () => {
Expand All @@ -145,24 +145,7 @@ const handleClickCollapsibleTitle = (collapsedTitle: string) => {
state.collapsedTitleMap[collapsedTitle] = !state.collapsedTitleMap[collapsedTitle];
};
const checkFormDependencies = (changedFieldName: string):string[] => state.widgetConfigDependencies[changedFieldName] || [];
const handleUpdateFieldValue = (fieldName: string, value: WidgetFieldValues) => {
const _valueMap = cloneDeep(widgetGenerateState.widgetFormValueMap);
_valueMap[fieldName] = value;
const changedOptions = checkFormDependencies(fieldName);
const isValueChanged = (JSON.stringify(value) !== JSON.stringify(widgetGenerateState.widgetFormValueMap[fieldName]));
if (changedOptions.length && isValueChanged) {
changedOptions.forEach((option) => {
_valueMap[option] = undefined;
});
}
widgetGenerateStore.setWidgetFormValueMap(_valueMap);
};
const handleUpdateFieldValidation = (fieldName: string, isValid: boolean) => {
const _validMap = cloneDeep(widgetGenerateState.widgetValidMap);
_validMap[fieldName] = isValid;
widgetGenerateStore.setWidgetValidMap(_validMap);
};
// const checkFormDependencies = (changedFieldName: string):string[] => state.widgetConfigDependencies[changedFieldName] || [];
onMounted(() => {
checkDefaultValidation();
Expand Down Expand Up @@ -221,12 +204,9 @@ onMounted(() => {
</p-field-group>
</div>
<!-- widget header -->
<widget-header-field :key="`widget-header-${widgetGenerateState.selectedWidgetName}`"
:value="widgetGenerateState.widgetFormValueMap.widgetHeader"
:widget-config="state.widgetConfig"
:is-valid="widgetGenerateState.widgetValidMap.widgetHeader"
@update:value="handleUpdateFieldValue('widgetHeader', $event)"
@update:is-valid="handleUpdateFieldValidation('widgetHeader', $event)"
<widget-header-field :widget-config="state.widgetConfig"
:widget-id="widgetGenerateState.widgetId"
:field-manager="props.fieldManager"
/>
<!-- Date Config -->
<div class="form-group-wrapper"
Expand All @@ -249,16 +229,9 @@ onMounted(() => {
<component :is="getWidgetFieldComponent(fieldName)"
:key="`${fieldName}-${widgetGenerateState.selectedWidgetName}`"
:widget-field-schema="fieldSchema"
:data-table="widgetGenerateGetters.selectedDataTable"
:widget-id="widgetGenerateState.widgetId"
:date-range="dashboardDetailState.options.date_range"
:all-value-map="widgetGenerateState.widgetFormValueMap"
:value="widgetGenerateState.widgetFormValueMap[fieldName]"
:is-valid="widgetGenerateState.widgetValidMap[fieldName]"
:widget-config="state.widgetConfig"
@update:value="handleUpdateFieldValue(fieldName, $event)"
@update:is-valid="handleUpdateFieldValidation(fieldName, $event)"
@show-error-modal="handleShowErrorModal"
:widget-id="widgetGenerateState.widgetId"
:field-manager="props.fieldManager"
/>
</template>
</div>
Expand Down Expand Up @@ -299,16 +272,9 @@ onMounted(() => {
<component :is="getWidgetFieldComponent(fieldName)"
:key="`${fieldName}-${widgetGenerateState.selectedWidgetName}`"
:widget-field-schema="fieldSchema"
:data-table="widgetGenerateGetters.selectedDataTable"
:widget-id="widgetGenerateState.widgetId"
:date-range="dashboardDetailState.options.date_range"
:all-value-map="widgetGenerateState.widgetFormValueMap"
:value="widgetGenerateState.widgetFormValueMap[fieldName]"
:is-valid="widgetGenerateState.widgetValidMap[fieldName]"
:widget-config="state.widgetConfig"
@update:value="handleUpdateFieldValue(fieldName, $event)"
@update:is-valid="handleUpdateFieldValidation(fieldName, $event)"
@show-error-modal="handleShowErrorModal"
:widget-id="widgetGenerateState.widgetId"
:field-manager="props.fieldManager"
/>
</template>
</div>
Expand All @@ -334,13 +300,9 @@ onMounted(() => {
<component :is="getWidgetFieldComponent(fieldName)"
:key="`${fieldName}-${widgetGenerateState.selectedWidgetName}`"
:widget-field-schema="fieldSchema"
:data-table="widgetGenerateGetters.selectedDataTable"
:all-value-map="widgetGenerateState.widgetFormValueMap"
:value="widgetGenerateState.widgetFormValueMap[fieldName]"
:is-valid="widgetGenerateState.widgetValidMap[fieldName]"
:widget-config="state.widgetConfig"
@update:value="handleUpdateFieldValue(fieldName, $event)"
@update:is-valid="handleUpdateFieldValidation(fieldName, $event)"
:widget-id="widgetGenerateState.widgetId"
:field-manager="props.fieldManager"
/>
</template>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,9 +336,6 @@ export const useWidgetGenerateStore = defineStore('widget-generate', () => {
if (!_sort || (_sort && _sort.length === 0)) {
const labelsInfoList = Object.keys(dataTable?.labels_info ?? {});
if (labelsInfoList.includes('Date')) _sort = [{ key: 'Date', desc: false }];
else if (_granularity === 'DAILY') _sort = [{ key: 'Day', desc: false }];
else if (_granularity === 'MONTHLY') _sort = [{ key: 'Month', desc: false }];
else if (_granularity === 'YEARLY') _sort = [{ key: 'Year', desc: false }];
}
const { results, total_count } = await fetcher({
granularity: _granularity,
Expand All @@ -362,21 +359,24 @@ export const useWidgetGenerateStore = defineStore('widget-generate', () => {
state.dataTableLoadLoading = false;
}
},
updateWidget: async (updateParams: Partial<WidgetUpdateParameters>) => {
updateWidget: async (updateParams: Partial<WidgetUpdateParameters>): Promise<WidgetModel|undefined> => {
const isPrivate = state.widgetId.startsWith('private');
const fetcher = isPrivate
? SpaceConnector.clientV2.dashboard.privateWidget.update<PrivateWidgetUpdateParameters, PrivateWidgetModel>
: SpaceConnector.clientV2.dashboard.publicWidget.update<PublicWidgetUpdateParameters, PublicWidgetModel>;
const sanitizedOptions = sanitizeWidgetOptions(updateParams.options ?? {}, updateParams.widget_type ?? 'table');
try {
state.widget = await fetcher({
const result = await fetcher({
widget_id: state.widgetId,
...updateParams,
options: sanitizedOptions, // Sanitize Wrong Options
});
state.widget = result;
return result;
} catch (e: any) {
showErrorMessage(e.message, e);
ErrorHandler.handleError(e);
return undefined;
}
},
/* Step 2 */
Expand All @@ -392,13 +392,13 @@ export const useWidgetGenerateStore = defineStore('widget-generate', () => {
state.widgetFormValueMap = {};
state.allDataTableInvalidMap = {};
},
setWidgetForm: (widgetInfo?: WidgetModel) => {
setWidgetForm: (widgetInfo: WidgetModel) => {
state.selectedWidgetName = widgetInfo?.widget_type || 'table';
const _widgetConfig = getWidgetConfig(widgetInfo?.widget_type || 'table');
const _widgetConfig = getWidgetConfig(widgetInfo.widget_type || 'table');
state.widget = widgetInfo;
state.widgetId = widgetInfo?.widget_id || '';
state.widgetId = widgetInfo.widget_id;
state.size = widgetInfo?.size || _widgetConfig?.meta?.sizes[0] || 'full';
state.selectedDataTableId = widgetInfo?.data_table_id || undefined;
state.selectedDataTableId = widgetInfo?.data_table_id;
state.widgetFormValueMap = widgetInfo?.options || {};
},
};
Expand Down
Loading

0 comments on commit 10c8949

Please sign in to comment.