From 478ebd51448f483a445d4c7a8f5bce2a2c53702b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piggy=20Park=20=28=EB=B0=95=EC=9A=A9=ED=83=9C=29?= Date: Mon, 16 Dec 2024 13:44:11 +0900 Subject: [PATCH] fix(date-range): refactor date-range widget field (#5223) Signed-off-by: samuel.park --- ...getFormDataTableCardTransformPivotForm.vue | 5 +- .../constant/default-value-registry.ts | 7 +- .../constant/validator-registry.ts | 14 + .../_widget-field-value-manager/index.ts | 2 +- .../_widget-field-value-manager/type.ts | 2 +- .../date-range/_WidgetFieldDateRange.vue | 624 ++++++++++++++++++ .../_widget-fields/date-range/constant.ts | 4 + .../_widget-fields/date-range/helper.ts | 50 ++ .../widgets/types/widget-field-type.ts | 3 +- 9 files changed, 702 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/common/modules/widgets/_widget-fields/date-range/_WidgetFieldDateRange.vue create mode 100644 apps/web/src/common/modules/widgets/_widget-fields/date-range/helper.ts diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformPivotForm.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformPivotForm.vue index 7fafaa2010..2ddba81eb2 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformPivotForm.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformPivotForm.vue @@ -30,10 +30,7 @@ import type { PivotOptions } from '@/common/modules/widgets/types/widget-model'; const props = defineProps>(); -const emit = defineEmits<{(e: 'update:operator-options', value: PivotOptions): void; - (e: 'update:form-data', value: Omit): void; - (e: 'update:data-table-info', value: TransformDataTableInfo): void; -}>(); +const emit = defineEmits<{(e: 'update:operator-options', value: PivotOptions): void; }>(); const widgetGenerateStore = useWidgetGenerateStore(); const widgetGenerateState = widgetGenerateStore.state; diff --git a/apps/web/src/common/modules/widgets/_widget-field-value-manager/constant/default-value-registry.ts b/apps/web/src/common/modules/widgets/_widget-field-value-manager/constant/default-value-registry.ts index 9bc2be14a8..8321abe546 100644 --- a/apps/web/src/common/modules/widgets/_widget-field-value-manager/constant/default-value-registry.ts +++ b/apps/web/src/common/modules/widgets/_widget-field-value-manager/constant/default-value-registry.ts @@ -59,7 +59,12 @@ export const widgetFieldDefaultValueMap: DefaultValueRegistry = { dateFormat: { format: Object.keys(DATE_FORMAT)[0], }, - dateRange: {}, + dateRange: { + inherit: true, + options: { + value: 'auto', + }, + }, displayAnnotation: undefined, displaySeriesLabel: undefined, granularity: { diff --git a/apps/web/src/common/modules/widgets/_widget-field-value-manager/constant/validator-registry.ts b/apps/web/src/common/modules/widgets/_widget-field-value-manager/constant/validator-registry.ts index 1d2cfbd421..2e0052b5a5 100644 --- a/apps/web/src/common/modules/widgets/_widget-field-value-manager/constant/validator-registry.ts +++ b/apps/web/src/common/modules/widgets/_widget-field-value-manager/constant/validator-registry.ts @@ -7,6 +7,9 @@ import type { ColorSchemaValue } from '@/common/modules/widgets/_widget-fields/c import type { ComparisonValue } from '@/common/modules/widgets/_widget-fields/comparison/type'; import type { _CustomTableColumnWidthValue } from '@/common/modules/widgets/_widget-fields/custom-table-column-width/type'; import type { DataFieldOptions, DataFieldValue } from '@/common/modules/widgets/_widget-fields/data-field/type'; +import { DAILY_ENABLED_VALUES, MONTHLY_ENABLED_VALUES, YEARLY_ENABLED_VALUES } from '@/common/modules/widgets/_widget-fields/date-range/constant'; +import { checkInvalidCustomValue } from '@/common/modules/widgets/_widget-fields/date-range/helper'; +import type { DateRangeValue } from '@/common/modules/widgets/_widget-fields/date-range/type'; import type { DisplayAnnotationValue } from '@/common/modules/widgets/_widget-fields/display-annotation/type'; import type { DisplaySeriesLabelValue } from '@/common/modules/widgets/_widget-fields/display-series-label/type'; import type { GranularityValue } from '@/common/modules/widgets/_widget-fields/granularity/type'; @@ -26,6 +29,17 @@ export interface WidgetValidatorRegistry { } export const widgetValidatorRegistry: WidgetValidatorRegistry = { + dateRange: (fieldValue: DateRangeValue, widgetConfig, allValueMap) => { + const _dateRangeType = fieldValue.options.value; + const _granularity = allValueMap.granularity?.value?.granularity; + if (!_dateRangeType || !_granularity) return false; + if (checkInvalidCustomValue(fieldValue, _granularity).invalid) return false; + if (_granularity === 'MONTHLY' && !MONTHLY_ENABLED_VALUES.includes(_dateRangeType)) return false; + if (_granularity === 'DAILY' && !DAILY_ENABLED_VALUES.includes(_dateRangeType)) return false; + if (_granularity === 'YEARLY' && !YEARLY_ENABLED_VALUES.includes(_dateRangeType)) return false; + + return true; + }, dataField: (fieldValue: DataFieldValue, widgetConfig) => { const _fieldsSchema = integrateFieldsSchema(widgetConfig.requiredFieldsSchema, widgetConfig.optionalFieldsSchema); const dataFieldOptions = _fieldsSchema.dataField?.options as DataFieldOptions; diff --git a/apps/web/src/common/modules/widgets/_widget-field-value-manager/index.ts b/apps/web/src/common/modules/widgets/_widget-field-value-manager/index.ts index 1271b4c000..2d17018bcc 100644 --- a/apps/web/src/common/modules/widgets/_widget-field-value-manager/index.ts +++ b/apps/web/src/common/modules/widgets/_widget-field-value-manager/index.ts @@ -61,7 +61,7 @@ export default class WidgetFieldValueManager { const validator = widgetValidatorRegistry[key]; if (validator) { - const isValid = validator(this.modifiedData[key], this.widgetConfig); + const isValid = validator(this.modifiedData[key], this.widgetConfig, this.modifiedData); if (!isValid) { this.validationErrors[key as string] = `Invalid value for field "${key}"`; return false; diff --git a/apps/web/src/common/modules/widgets/_widget-field-value-manager/type.ts b/apps/web/src/common/modules/widgets/_widget-field-value-manager/type.ts index 9748e0b1b7..f61958ef6f 100644 --- a/apps/web/src/common/modules/widgets/_widget-field-value-manager/type.ts +++ b/apps/web/src/common/modules/widgets/_widget-field-value-manager/type.ts @@ -33,7 +33,7 @@ import type { _XAxisValue } from '@/common/modules/widgets/_widget-fields/x-axis import type { _YAxisValue } from '@/common/modules/widgets/_widget-fields/y-axis/type'; import type { WidgetConfig } from '@/common/modules/widgets/types/widget-config-type'; -export type FieldValueValidator = (fieldValue: T, widgetConfig: WidgetConfig) => boolean; +export type FieldValueValidator = (fieldValue: T, widgetConfig: WidgetConfig, allValueMap: WidgetFieldValueMap) => boolean; export type FieldDefaultValueConvertor = (widgetConfig: WidgetConfig, dataTable: PublicDataTableModel|PrivateDataTableModel) => WidgetFieldTypeMap[T]['value']; export interface WidgetFieldValueMap { diff --git a/apps/web/src/common/modules/widgets/_widget-fields/date-range/_WidgetFieldDateRange.vue b/apps/web/src/common/modules/widgets/_widget-fields/date-range/_WidgetFieldDateRange.vue new file mode 100644 index 0000000000..284e4220e3 --- /dev/null +++ b/apps/web/src/common/modules/widgets/_widget-fields/date-range/_WidgetFieldDateRange.vue @@ -0,0 +1,624 @@ + + + + + diff --git a/apps/web/src/common/modules/widgets/_widget-fields/date-range/constant.ts b/apps/web/src/common/modules/widgets/_widget-fields/date-range/constant.ts index 330661933e..2ffaee9b2e 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/date-range/constant.ts +++ b/apps/web/src/common/modules/widgets/_widget-fields/date-range/constant.ts @@ -33,3 +33,7 @@ export const DATE_RANGE_ADVANCED_OPERATOR_MAP = { ADD: 'ADD', SUBSTRACT: 'SUBSTRACT', } as const; + +export const MONTHLY_ENABLED_VALUES = ['auto', ...DATE_RANGE_MONTHLY_VALUES, 'custom', 'advanced']; +export const DAILY_ENABLED_VALUES = ['auto', ...DATE_RANGE_DAILY_VALUES, 'custom', 'advanced']; +export const YEARLY_ENABLED_VALUES = ['auto', ...DATE_RANGE_YEARLY_VALUES, 'custom', 'advanced']; diff --git a/apps/web/src/common/modules/widgets/_widget-fields/date-range/helper.ts b/apps/web/src/common/modules/widgets/_widget-fields/date-range/helper.ts new file mode 100644 index 0000000000..e872f8798e --- /dev/null +++ b/apps/web/src/common/modules/widgets/_widget-fields/date-range/helper.ts @@ -0,0 +1,50 @@ +import dayjs from 'dayjs'; + +import { i18n } from '@/translations'; + +import { DATE_RANGE_ADVANCED_OPERATOR_MAP } from '@/common/modules/widgets/_widget-fields/date-range/constant'; +import type { DateRangeValue } from '@/common/modules/widgets/_widget-fields/date-range/type'; +import type { GranularityValue } from '@/common/modules/widgets/_widget-fields/granularity/type'; + + +export const checkInvalidCustomValue = (fieldValue: DateRangeValue, granularity: GranularityValue['granularity']) => { + const _value = fieldValue?.options?.value; + if (_value === 'custom') { + if (!fieldValue.options.start || !fieldValue.options.end) return { invalid: true, text: '' }; + if (fieldValue?.inherit) { + const inheritCustomStartValue = fieldValue?.options?.start || 0; + const inheritCustomEndValue = fieldValue?.options?.end || 0; + if (inheritCustomStartValue > inheritCustomEndValue) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_RANGE_TEXT') }; + const gap = inheritCustomEndValue - inheritCustomStartValue; + if (granularity === 'YEARLY' && gap >= 3) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + if (granularity === 'MONTHLY' && gap >= 12) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + if (granularity === 'DAILY' && gap >= 31) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + } else { + const _startDate = dayjs.utc(fieldValue?.options?.start); + const _endDate = dayjs.utc(fieldValue?.options.end); + if (granularity === 'YEARLY' && _endDate.diff(_startDate, 'year') >= 3) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + if (granularity === 'MONTHLY' && _endDate.diff(_startDate, 'month') >= 12) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + if (granularity === 'DAILY' && _endDate.diff(_startDate, 'day') >= 31) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + if (_startDate.isAfter(_endDate)) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_RANGE_TEXT') }; + } + } else if (_value === 'advanced') { + if ( + (fieldValue.options.start === undefined || fieldValue.options.end === undefined) + || (Number.isNaN(fieldValue.options.start) || Number.isNaN(fieldValue.options.end)) + ) return { invalid: true, text: '' }; + const _startOperator = fieldValue?.options?.start_operator; + const _endOperator = fieldValue?.options?.end_operator; + const _start = fieldValue?.options?.start as number|undefined; + const _end = fieldValue?.options?.end as number|undefined; + const _startValue: number = _startOperator === DATE_RANGE_ADVANCED_OPERATOR_MAP.ADD ? _start || 0 : (_start || 0) * -1; + const _endValue: number = _endOperator === DATE_RANGE_ADVANCED_OPERATOR_MAP.ADD ? _end || 0 : (_end || 0) * -1; + + const gap = _endValue - _startValue; + + if (gap < 0) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_RANGE_TEXT') }; + if (granularity === 'YEARLY' && gap >= 3) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + if (granularity === 'MONTHLY' && gap >= 12) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + if (granularity === 'DAILY' && gap >= 31) return { invalid: true, text: i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_2.DATE_RANGE_INVALID_LIMIT_TEXT') }; + } + return { invalid: false, text: '' }; +}; diff --git a/apps/web/src/common/modules/widgets/types/widget-field-type.ts b/apps/web/src/common/modules/widgets/types/widget-field-type.ts index 1f11be2290..ab6ecac756 100644 --- a/apps/web/src/common/modules/widgets/types/widget-field-type.ts +++ b/apps/web/src/common/modules/widgets/types/widget-field-type.ts @@ -22,7 +22,6 @@ import type { MinOptions } from '@/common/modules/widgets/_widget-fields/min/typ import type { MissingValueOptions } from '@/common/modules/widgets/_widget-fields/missing-value/type'; import type { NumberFormatOptions } from '@/common/modules/widgets/_widget-fields/number-format/type'; import type { PieChartTypeOptions } from '@/common/modules/widgets/_widget-fields/pie-chart-type/type'; -import type { ProgressBarOptions } from '@/common/modules/widgets/_widget-fields/progress-bar/type'; import type { StackByOptions } from '@/common/modules/widgets/_widget-fields/stack-by/type'; import type { SubTotalOptions } from '@/common/modules/widgets/_widget-fields/sub-total/type'; import type { TableColumnWidthOptions } from '@/common/modules/widgets/_widget-fields/table-column-width/type'; @@ -43,7 +42,7 @@ export type WidgetFieldOptions = DataFieldOptions | TableDataFieldOptions | XAxi | StackByOptions | GroupByOptions | CategoryByOptions | FormatRulesOptions | AdvancedFormatRulesOptions | MinOptions | MaxOptions | LegendOptions | IconOptions | SubTotalOptions | TotalOptions - | ComparisonOptions | ProgressBarOptions | ColorSchemaOptions | PieChartTypeOptions | DateFormatOptions + | ComparisonOptions | ColorSchemaOptions | PieChartTypeOptions | DateFormatOptions | NumberFormatOptions | DataFieldHeatmapColorOptions | TextWrapOptions | TableColumnWidthOptions | CustomTableColumnWidthOptions | MissingValueOptions | WidgetHeightOptions | DisplaySeriesLabelOptions | DateRangeOptions | TooltipNumberFormatOptions;