From d0f36fc81a6270483af5cbc5e8ef8f2028628002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Mon, 10 Nov 2025 10:19:18 +0100 Subject: [PATCH 1/9] range --- .../src/plugins/ui_feature/header_visibility_ui.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/o-spreadsheet-engine/src/plugins/ui_feature/header_visibility_ui.ts b/packages/o-spreadsheet-engine/src/plugins/ui_feature/header_visibility_ui.ts index 6092a9263f..a6dfbf1d64 100644 --- a/packages/o-spreadsheet-engine/src/plugins/ui_feature/header_visibility_ui.ts +++ b/packages/o-spreadsheet-engine/src/plugins/ui_feature/header_visibility_ui.ts @@ -1,4 +1,3 @@ -import { range } from "../../helpers/misc"; import { CellPosition, Dimension, HeaderIndex, UID } from "../../types/misc"; import { ExcelWorkbookData } from "../../types/workbook_data"; import { UIPlugin } from "../ui_plugin"; @@ -78,10 +77,12 @@ export class HeaderVisibilityUIPlugin extends UIPlugin { dimension: Dimension, { last, first }: { first: HeaderIndex; last: HeaderIndex } ): HeaderIndex { - const lastVisibleIndex = range(last, first, -1).find( - (index) => !this.isHeaderHidden(sheetId, dimension, index) - ); - return lastVisibleIndex || first; + for (let header = last; header >= first; header--) { + if (!this.isHeaderHidden(sheetId, dimension, header)) { + return header; + } + } + return first; } findFirstVisibleColRowIndex(sheetId: UID, dimension: Dimension) { From 2da470aad0fa2890a43d8ccba3ef396dda7b0f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Mon, 17 Nov 2025 16:09:59 +0100 Subject: [PATCH 2/9] [REF] chart: explicit default humanize Currently, 'humanize' is not explicitely set when creating a new chart. The default value `true` is later assigned as a fallback in the Chart class. I'd like to simplify those classes. --- .../helpers/figures/charts/abstract_chart.ts | 4 ++-- .../src/migrations/migration_steps.ts | 12 ++++++++++++ .../figures/charts/smart_chart_engine.ts | 17 ++++++++++++++--- .../chart/menu_item_insert_chart.test.ts | 1 + tests/test_helpers/constants.ts | 4 ++++ 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/o-spreadsheet-engine/src/helpers/figures/charts/abstract_chart.ts b/packages/o-spreadsheet-engine/src/helpers/figures/charts/abstract_chart.ts index 3a1a264ac6..c5152d0115 100644 --- a/packages/o-spreadsheet-engine/src/helpers/figures/charts/abstract_chart.ts +++ b/packages/o-spreadsheet-engine/src/helpers/figures/charts/abstract_chart.ts @@ -24,13 +24,13 @@ export abstract class AbstractChart { readonly title: TitleDesign; abstract readonly type: ChartType; protected readonly getters: CoreGetters; - readonly humanize: boolean; + readonly humanize: boolean | undefined; constructor(definition: ChartDefinition, sheetId: UID, getters: CoreGetters) { this.title = definition.title; this.sheetId = sheetId; this.getters = getters; - this.humanize = definition.humanize ?? true; + this.humanize = definition.humanize; } /** diff --git a/packages/o-spreadsheet-engine/src/migrations/migration_steps.ts b/packages/o-spreadsheet-engine/src/migrations/migration_steps.ts index e2f75c309d..4fddc0a249 100644 --- a/packages/o-spreadsheet-engine/src/migrations/migration_steps.ts +++ b/packages/o-spreadsheet-engine/src/migrations/migration_steps.ts @@ -553,6 +553,18 @@ migrationStepRegistry } return data; }, + }) + .add("19.1.0", { + migrate(data: WorkbookData): any { + for (const sheet of data.sheets || []) { + for (const figure of sheet.figures || []) { + if (figure.tag === "chart" && !("humanize" in figure.data)) { + figure.data.humanize = true; + } + } + } + return data; + }, }); function fixOverlappingFilters(data: any): any { diff --git a/src/helpers/figures/charts/smart_chart_engine.ts b/src/helpers/figures/charts/smart_chart_engine.ts index 804c58d437..f43ef4f537 100644 --- a/src/helpers/figures/charts/smart_chart_engine.ts +++ b/src/helpers/figures/charts/smart_chart_engine.ts @@ -17,6 +17,7 @@ const DEFAULT_BAR_CHART_CONFIG: BarChartDefinition = { legendPosition: "none", dataSetsHaveTitle: false, stacked: false, + humanize: true, }; const DEFAULT_LINE_CHART_CONFIG: LineChartDefinition = { @@ -28,6 +29,7 @@ const DEFAULT_LINE_CHART_CONFIG: LineChartDefinition = { stacked: false, cumulative: false, labelsAsText: false, + humanize: true, }; interface ColumnInfo { @@ -342,10 +344,19 @@ export function getSmartChartDefinition(zones: Zone[], getters: Getters): ChartD const nonEmptyColumns = columns.filter((col) => col.type !== "empty"); switch (nonEmptyColumns.length) { case 1: - return buildSingleColumnChart(nonEmptyColumns[0], getters); + return { + humanize: true, + ...buildSingleColumnChart(nonEmptyColumns[0], getters), + }; case 2: - return buildTwoColumnChart(nonEmptyColumns, getters); + return { + humanize: true, + ...buildTwoColumnChart(nonEmptyColumns, getters), + }; default: - return buildMultiColumnChart(nonEmptyColumns, getters); + return { + humanize: true, + ...buildMultiColumnChart(nonEmptyColumns, getters), + }; } } diff --git a/tests/figures/chart/menu_item_insert_chart.test.ts b/tests/figures/chart/menu_item_insert_chart.test.ts index a11777f5fa..bde7e7430f 100644 --- a/tests/figures/chart/menu_item_insert_chart.test.ts +++ b/tests/figures/chart/menu_item_insert_chart.test.ts @@ -116,6 +116,7 @@ describe("Insert chart menu item", () => { legendPosition: "none", title: {}, type: "bar", + humanize: true, }, }; }); diff --git a/tests/test_helpers/constants.ts b/tests/test_helpers/constants.ts index bb21610be8..904876493d 100644 --- a/tests/test_helpers/constants.ts +++ b/tests/test_helpers/constants.ts @@ -21,6 +21,7 @@ export const TEST_CHART_DATA = { background: BACKGROUND_CHART_COLOR, stacked: false, legendPosition: "top" as const, + humanize: true, }, combo: { type: "combo" as const, @@ -34,6 +35,7 @@ export const TEST_CHART_DATA = { title: { text: "hello" }, background: BACKGROUND_CHART_COLOR, legendPosition: "top" as const, + humanize: true, }, scorecard: { type: "scorecard" as const, @@ -42,11 +44,13 @@ export const TEST_CHART_DATA = { title: { text: "hello" }, baselineDescr: { text: "description" }, baselineMode: "difference" as const, + humanize: true, }, gauge: { type: "gauge" as const, dataRange: "B1:B4", title: { text: "hello" }, + humanize: true, sectionRule: { rangeMin: "0", rangeMax: "100", From 5e43925be3f66294428886dc6309e0db10a7f75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Tue, 18 Nov 2025 14:55:48 +0100 Subject: [PATCH 3/9] [IMP] charts: validate definition --- .../helpers/figures/charts/abstract_chart.ts | 13 +++ .../helpers/figures/charts/chart_factory.ts | 5 + .../helpers/figures/charts/scorecard_chart.ts | 13 ++- .../src/migrations/data.ts | 1 + .../src/migrations/migration_steps.ts | 22 +++++ .../src/plugins/core/chart.ts | 4 +- .../src/registries/chart_registry.ts | 1 + .../src/types/chart/scatter_chart.ts | 2 +- .../src/types/validator.ts | 5 +- src/helpers/figures/charts/bar_chart.ts | 74 ++++++--------- src/helpers/figures/charts/combo_chart.ts | 69 +++++--------- src/helpers/figures/charts/funnel_chart.ts | 77 +++++---------- src/helpers/figures/charts/gauge_chart.ts | 8 +- src/helpers/figures/charts/geo_chart.ts | 57 ++++------- src/helpers/figures/charts/line_chart.ts | 89 ++++++------------ src/helpers/figures/charts/pie_chart.ts | 66 +++++-------- src/helpers/figures/charts/pyramid_chart.ts | 70 +++++--------- src/helpers/figures/charts/radar_chart.ts | 72 +++++--------- src/helpers/figures/charts/scatter_chart.ts | 73 +++++--------- src/helpers/figures/charts/sunburst_chart.ts | 64 +++++-------- src/helpers/figures/charts/tree_map_chart.ts | 67 +++++-------- src/helpers/figures/charts/waterfall_chart.ts | 94 ++++++------------- src/registries/chart_types.ts | 14 +++ .../__snapshots__/chart_plugin.test.ts.snap | 2 +- .../sunburst/sunburst_chart_plugin.test.ts | 1 + tests/model/model_import_export.test.ts | 37 ++++++++ tests/test_helpers/commands_helpers.ts | 32 ++++++- 27 files changed, 442 insertions(+), 590 deletions(-) diff --git a/packages/o-spreadsheet-engine/src/helpers/figures/charts/abstract_chart.ts b/packages/o-spreadsheet-engine/src/helpers/figures/charts/abstract_chart.ts index c5152d0115..832564f12c 100644 --- a/packages/o-spreadsheet-engine/src/helpers/figures/charts/abstract_chart.ts +++ b/packages/o-spreadsheet-engine/src/helpers/figures/charts/abstract_chart.ts @@ -2,6 +2,7 @@ import { ChartCreationContext, ChartDefinition, ChartType, + ChartWithDataSetDefinition, DataSet, ExcelChartDataset, ExcelChartDefinition, @@ -26,6 +27,18 @@ export abstract class AbstractChart { protected readonly getters: CoreGetters; readonly humanize: boolean | undefined; + static commonKeys: readonly (keyof ChartDefinition)[] = [ + "type", + "title", + "background", + "humanize", + ]; + static dataSetKeys: readonly (keyof ChartWithDataSetDefinition)[] = [ + "dataSets", + "dataSetsHaveTitle", + "labelRange", + ]; + constructor(definition: ChartDefinition, sheetId: UID, getters: CoreGetters) { this.title = definition.title; this.sheetId = sheetId; diff --git a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_factory.ts b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_factory.ts index 53f61ce5fc..77388420e6 100644 --- a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_factory.ts +++ b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_factory.ts @@ -58,6 +58,11 @@ export function validateChartDefinition( if (!validators) { throw new Error("Unknown chart type."); } + const allowedKeys = new Set(validators.allowedDefinitionKeys); + const hasExtraKeys = !new Set(Object.keys(definition)).isSubsetOf(allowedKeys); + if (hasExtraKeys) { + return CommandResult.InvalidChartDefinition; + } return validators.validateChartDefinition(validator, definition); } diff --git a/packages/o-spreadsheet-engine/src/helpers/figures/charts/scorecard_chart.ts b/packages/o-spreadsheet-engine/src/helpers/figures/charts/scorecard_chart.ts index 7b451b6dab..6ee6119c22 100644 --- a/packages/o-spreadsheet-engine/src/helpers/figures/charts/scorecard_chart.ts +++ b/packages/o-spreadsheet-engine/src/helpers/figures/charts/scorecard_chart.ts @@ -171,6 +171,17 @@ export class ScorecardChart extends AbstractChart { readonly humanize: boolean; readonly type = "scorecard"; + static allowedDefinitionKeys: readonly (keyof ScorecardChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "keyValue", + "keyDescr", + "baseline", + "baselineMode", + "baselineDescr", + "baselineColorUp", + "baselineColorDown", + ] as const; + constructor(definition: ScorecardChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.keyValue = createValidRange(getters, sheetId, definition.keyValue); @@ -249,7 +260,7 @@ export class ScorecardChart extends AbstractChart { getContextCreation(): ChartCreationContext { return { - ...this, + ...this.getDefinition(), range: this.keyValue ? [{ dataRange: this.getters.getRangeString(this.keyValue, this.sheetId) }] : undefined, diff --git a/packages/o-spreadsheet-engine/src/migrations/data.ts b/packages/o-spreadsheet-engine/src/migrations/data.ts index c6c433191e..aa182556d4 100644 --- a/packages/o-spreadsheet-engine/src/migrations/data.ts +++ b/packages/o-spreadsheet-engine/src/migrations/data.ts @@ -308,6 +308,7 @@ function fixChartDefinitions(data: Partial, initialMessages: State const definition = map[cmd.chartId]; const newDefinition = { ...definition, ...cmd.definition }; command = { ...cmd, definition: newDefinition }; + delete newDefinition.chartId; map[cmd.chartId] = newDefinition; break; } diff --git a/packages/o-spreadsheet-engine/src/migrations/migration_steps.ts b/packages/o-spreadsheet-engine/src/migrations/migration_steps.ts index 4fddc0a249..ed0ddd9d5a 100644 --- a/packages/o-spreadsheet-engine/src/migrations/migration_steps.ts +++ b/packages/o-spreadsheet-engine/src/migrations/migration_steps.ts @@ -5,6 +5,7 @@ import { getUniqueText, sanitizeSheetName } from "../helpers/misc"; import { getMaxObjectId } from "../helpers/pivot/pivot_helpers"; import { DEFAULT_TABLE_CONFIG } from "../helpers/table_presets"; import { overlap, toZone, zoneToXc } from "../helpers/zones"; +import { chartRegistry } from "../registries/chart_registry"; import { Registry } from "../registry"; import { CustomizedDataSet } from "../types/chart"; import { Format } from "../types/format"; @@ -565,6 +566,27 @@ migrationStepRegistry } return data; }, + }) + .add("19.1.1", { + migrate(data: WorkbookData): any { + for (const sheet of data.sheets || []) { + for (const figure of sheet.figures || []) { + if (figure.tag === "chart") { + const definition = figure.data; + const allowedDefinitionKeys = new Set( + chartRegistry.get(definition.type).allowedDefinitionKeys + ); + allowedDefinitionKeys.add("chartId"); + for (const key in definition) { + if (!allowedDefinitionKeys.has(key)) { + delete definition[key]; + } + } + } + } + } + return data; + }, }); function fixOverlappingFilters(data: any): any { diff --git a/packages/o-spreadsheet-engine/src/plugins/core/chart.ts b/packages/o-spreadsheet-engine/src/plugins/core/chart.ts index 83d54244dd..68825c85b2 100644 --- a/packages/o-spreadsheet-engine/src/plugins/core/chart.ts +++ b/packages/o-spreadsheet-engine/src/plugins/core/chart.ts @@ -220,7 +220,9 @@ export class ChartPlugin extends CorePlugin implements ChartState { // instead of in figure.data if (figure.tag === "chart") { const chartId = figure.data.chartId; - const chart = this.createChart(figure.id, figure.data, sheet.id); + const definition = { ...figure.data }; + delete definition.chartId; + const chart = this.createChart(figure.id, definition, sheet.id); this.charts[chartId] = { chart, figureId: figure.id }; } else if (figure.tag === "carousel") { for (const chartId in figure.data.chartDefinitions || {}) { diff --git a/packages/o-spreadsheet-engine/src/registries/chart_registry.ts b/packages/o-spreadsheet-engine/src/registries/chart_registry.ts index d980a51af9..5e3ddc70bc 100644 --- a/packages/o-spreadsheet-engine/src/registries/chart_registry.ts +++ b/packages/o-spreadsheet-engine/src/registries/chart_registry.ts @@ -27,6 +27,7 @@ export interface ChartBuilder { applyRange: RangeAdapter ): ChartDefinition; getChartDefinitionFromContextCreation(context: ChartCreationContext): ChartDefinition; + allowedDefinitionKeys: readonly string[]; sequence: number; dataSeriesLimit?: number; } diff --git a/packages/o-spreadsheet-engine/src/types/chart/scatter_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/scatter_chart.ts index 6b508e901d..ec1216ca17 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/scatter_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/scatter_chart.ts @@ -1,7 +1,7 @@ import { LineChartDefinition, LineChartRuntime } from "./line_chart"; export interface ScatterChartDefinition - extends Omit { + extends Omit { readonly type: "scatter"; } diff --git a/packages/o-spreadsheet-engine/src/types/validator.ts b/packages/o-spreadsheet-engine/src/types/validator.ts index 4921eb161e..297361af75 100644 --- a/packages/o-spreadsheet-engine/src/types/validator.ts +++ b/packages/o-spreadsheet-engine/src/types/validator.ts @@ -15,5 +15,8 @@ export interface Validator { */ chainValidations(...validations: Validation[]): Validation; - checkValidations(command: T, ...validations: Validation[]): CommandResult | CommandResult[]; + checkValidations( + command: T, + ...validations: Validation>[] + ): CommandResult | CommandResult[]; } diff --git a/src/helpers/figures/charts/bar_chart.ts b/src/helpers/figures/charts/bar_chart.ts index e1d83dbf36..91a2304739 100644 --- a/src/helpers/figures/charts/bar_chart.ts +++ b/src/helpers/figures/charts/bar_chart.ts @@ -20,17 +20,14 @@ import { BarChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/bar_chart"; import { - AxesDesign, ChartCreationContext, CustomizedDataSet, DataSet, - DatasetDesign, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { LegendPosition } from "@odoo/o-spreadsheet-engine/types/chart/common_chart"; import { CommandResult } from "@odoo/o-spreadsheet-engine/types/commands"; import { Getters } from "@odoo/o-spreadsheet-engine/types/getters"; -import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine/types/misc"; +import { ApplyRangeChange, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine/types/misc"; import { Range } from "@odoo/o-spreadsheet-engine/types/range"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import type { ChartConfiguration } from "chart.js"; @@ -48,19 +45,23 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class BarChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; - readonly stacked: boolean; - readonly aggregated?: boolean; readonly type = "bar"; - readonly dataSetsHaveTitle: boolean; - readonly dataSetDesign?: DatasetDesign[]; - readonly axesDesign?: AxesDesign; - readonly horizontal?: boolean; - readonly showValues?: boolean; - readonly zoomable?: boolean; - - constructor(definition: BarChartDefinition, sheetId: UID, getters: CoreGetters) { + + static allowedDefinitionKeys: readonly (keyof BarChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "horizontal", + "axesDesign", + "stacked", + "aggregated", + "showValues", + "zoomable", + ] as const; + + constructor(private definition: BarChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -69,16 +70,6 @@ export class BarChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.stacked = definition.stacked; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.dataSetDesign = definition.dataSets; - this.axesDesign = definition.axesDesign; - this.horizontal = definition.horizontal; - this.showValues = definition.showValues; - this.zoomable = definition.zoomable; } static transformDefinition( @@ -119,12 +110,12 @@ export class BarChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -164,41 +155,32 @@ export class BarChart extends AbstractChart { const ranges: CustomizedDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), }); } return { - type: "bar", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - stacked: this.stacked, - aggregated: this.aggregated, - axesDesign: this.axesDesign, - horizontal: this.horizontal, - showValues: this.showValues, - zoomable: this.horizontal ? undefined : this.zoomable, - humanize: this.humanize, + zoomable: this.definition.horizontal ? undefined : this.definition.zoomable, }; } getDefinitionForExcel(): ExcelChartDefinition | undefined { + const definition = this.getDefinition(); const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel( this.labelRange, this.dataSets, - shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle) + shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], definition.dataSetsHaveTitle) ); - const definition = this.getDefinition(); return { ...definition, - backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR), - fontColor: toXlsxHexColor(chartFontColor(this.background)), + backgroundColor: toXlsxHexColor(definition.background || BACKGROUND_CHART_COLOR), + fontColor: toXlsxHexColor(chartFontColor(definition.background)), dataSets, labelRange, verticalAxis: getDefinedAxis(definition), @@ -232,7 +214,7 @@ export function createBarChartRuntime(chart: BarChart, getters: Getters): BarCha }, options: { ...CHART_COMMON_OPTIONS, - indexAxis: chart.horizontal ? "y" : "x", + indexAxis: definition.horizontal ? "y" : "x", layout: getChartLayout(definition, chartData), scales: getBarChartScales(definition, chartData), plugins: { @@ -244,5 +226,5 @@ export function createBarChartRuntime(chart: BarChart, getters: Getters): BarCha }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { chartJsConfig: config, background: definition.background || BACKGROUND_CHART_COLOR }; } diff --git a/src/helpers/figures/charts/combo_chart.ts b/src/helpers/figures/charts/combo_chart.ts index c26a267b51..26c910f355 100644 --- a/src/helpers/figures/charts/combo_chart.ts +++ b/src/helpers/figures/charts/combo_chart.ts @@ -15,11 +15,6 @@ import { } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; -import { - AxesDesign, - CustomizedDataSet, - LegendPosition, -} from "@odoo/o-spreadsheet-engine/types/chart"; import { ComboChartDataSet, ComboChartDefinition, @@ -30,8 +25,8 @@ import { ChartConfiguration } from "chart.js"; import { ApplyRangeChange, ChartCreationContext, - Color, CommandResult, + CustomizedDataSet, DataSet, ExcelChartDefinition, Getters, @@ -53,18 +48,22 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class ComboChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range; - readonly background?: Color; - readonly legendPosition: LegendPosition; - readonly aggregated?: boolean; - readonly dataSetsHaveTitle: boolean; - readonly dataSetDesign?: ComboChartDataSet[]; - readonly axesDesign?: AxesDesign; readonly type = "combo"; - readonly showValues?: boolean; - readonly hideDataMarkers?: boolean; - readonly zoomable?: boolean; - constructor(definition: ComboChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof ComboChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "aggregated", + "axesDesign", + "showValues", + "hideDataMarkers", + "zoomable", + ] as const; + + constructor(private definition: ComboChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -73,15 +72,6 @@ export class ComboChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.dataSetDesign = definition.dataSets; - this.axesDesign = definition.axesDesign; - this.showValues = definition.showValues; - this.hideDataMarkers = definition.hideDataMarkers; - this.zoomable = definition.zoomable; } static transformDefinition( @@ -103,12 +93,12 @@ export class ComboChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -128,41 +118,32 @@ export class ComboChart extends AbstractChart { const ranges: ComboChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), - type: this.dataSetDesign?.[i]?.type ?? (i ? "line" : "bar"), + type: this.definition.dataSets?.[i]?.type ?? (i ? "line" : "bar"), }); } return { - type: "combo", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - aggregated: this.aggregated, - axesDesign: this.axesDesign, - showValues: this.showValues, - hideDataMarkers: this.hideDataMarkers, - zoomable: this.zoomable, - humanize: this.humanize, }; } getDefinitionForExcel(): ExcelChartDefinition | undefined { + const definition = this.getDefinition(); const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel( this.labelRange, this.dataSets, - shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle) + shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], definition.dataSetsHaveTitle) ); - const definition = this.getDefinition(); return { ...definition, - backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR), - fontColor: toXlsxHexColor(chartFontColor(this.background)), + backgroundColor: toXlsxHexColor(definition.background || BACKGROUND_CHART_COLOR), + fontColor: toXlsxHexColor(chartFontColor(definition.background)), dataSets, labelRange, verticalAxis: getDefinedAxis(definition), @@ -249,5 +230,5 @@ export function createComboChartRuntime(chart: ComboChart, getters: Getters): Co }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { chartJsConfig: config, background: definition.background || BACKGROUND_CHART_COLOR }; } diff --git a/src/helpers/figures/charts/funnel_chart.ts b/src/helpers/figures/charts/funnel_chart.ts index e21028bb66..41cb234b63 100644 --- a/src/helpers/figures/charts/funnel_chart.ts +++ b/src/helpers/figures/charts/funnel_chart.ts @@ -12,30 +12,15 @@ import { } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; +import { FunnelChartDefinition, FunnelChartRuntime } from "@odoo/o-spreadsheet-engine/types/chart"; import { - FunnelChartColors, - FunnelChartDefinition, - FunnelChartRuntime, - LegendPosition, -} from "@odoo/o-spreadsheet-engine/types/chart"; -import { - AxesDesign, ChartCreationContext, CustomizedDataSet, DataSet, - DatasetDesign, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -49,19 +34,23 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class FunnelChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; - readonly aggregated?: boolean; readonly type = "funnel"; - readonly dataSetsHaveTitle: boolean; - readonly dataSetDesign?: DatasetDesign[]; - readonly axesDesign?: AxesDesign; - readonly horizontal = true; - readonly showValues?: boolean; - readonly funnelColors?: FunnelChartColors; - readonly cumulative?: boolean; - - constructor(definition: FunnelChartDefinition, sheetId: UID, getters: CoreGetters) { + + static allowedDefinitionKeys: readonly (keyof FunnelChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "axesDesign", + "legendPosition", + "horizontal", + "aggregated", + "showValues", + "funnelColors", + "cumulative", + ] as const; + + constructor(private definition: FunnelChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -70,16 +59,6 @@ export class FunnelChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.dataSetDesign = definition.dataSets; - this.axesDesign = definition.axesDesign; - this.showValues = definition.showValues; - this.horizontal = true; - this.funnelColors = definition.funnelColors; - this.cumulative = definition.cumulative; } static transformDefinition( @@ -120,12 +99,12 @@ export class FunnelChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -165,27 +144,17 @@ export class FunnelChart extends AbstractChart { const ranges: CustomizedDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), }); } return { - type: "funnel", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - aggregated: this.aggregated, - horizontal: this.horizontal, - axesDesign: this.axesDesign, - showValues: this.showValues, - funnelColors: this.funnelColors, - cumulative: this.cumulative, - humanize: this.humanize, }; } @@ -232,5 +201,5 @@ export function createFunnelChartRuntime(chart: FunnelChart, getters: Getters): }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { chartJsConfig: config, background: definition.background || BACKGROUND_CHART_COLOR }; } diff --git a/src/helpers/figures/charts/gauge_chart.ts b/src/helpers/figures/charts/gauge_chart.ts index f109172144..fd4b99c696 100644 --- a/src/helpers/figures/charts/gauge_chart.ts +++ b/src/helpers/figures/charts/gauge_chart.ts @@ -143,6 +143,12 @@ export class GaugeChart extends AbstractChart { readonly background?: Color; readonly type = "gauge"; + static allowedDefinitionKeys: readonly (keyof GaugeChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "dataRange", + "sectionRule", + ] as const; + constructor(definition: GaugeChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange); @@ -267,7 +273,7 @@ export class GaugeChart extends AbstractChart { getContextCreation(): ChartCreationContext { return { - ...this, + ...this.getDefinition(), range: this.dataRange ? [{ dataRange: this.getters.getRangeString(this.dataRange, this.sheetId) }] : undefined, diff --git a/src/helpers/figures/charts/geo_chart.ts b/src/helpers/figures/charts/geo_chart.ts index bebb910b85..0d8e8a897e 100644 --- a/src/helpers/figures/charts/geo_chart.ts +++ b/src/helpers/figures/charts/geo_chart.ts @@ -12,29 +12,18 @@ import { } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; -import { LegendPosition } from "@odoo/o-spreadsheet-engine/types/chart"; import { ChartCreationContext, CustomizedDataSet, DataSet, - DatasetDesign, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { - GeoChartColorScale, GeoChartDefinition, GeoChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/geo_chart"; import { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getChartTitle, getGeoChartData, @@ -47,16 +36,20 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class GeoChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; readonly type = "geo"; - readonly dataSetsHaveTitle: boolean; - readonly dataSetDesign?: DatasetDesign[]; - readonly colorScale?: GeoChartColorScale; - readonly missingValueColor?: Color; - readonly region?: string; - constructor(definition: GeoChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof GeoChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "colorScale", + "missingValueColor", + "region", + ] as const; + + constructor(private definition: GeoChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -65,13 +58,6 @@ export class GeoChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.dataSetDesign = definition.dataSets; - this.colorScale = definition.colorScale; - this.missingValueColor = definition.missingValueColor; - this.region = definition.region; } static transformDefinition( @@ -106,12 +92,12 @@ export class GeoChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -151,24 +137,17 @@ export class GeoChart extends AbstractChart { const ranges: CustomizedDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), }); } return { - type: "geo", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - colorScale: this.colorScale, - missingValueColor: this.missingValueColor, - region: this.region, - humanize: this.humanize, }; } @@ -212,5 +191,5 @@ export function createGeoChartRuntime(chart: GeoChart, getters: Getters): GeoCha }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { chartJsConfig: config, background: definition.background || BACKGROUND_CHART_COLOR }; } diff --git a/src/helpers/figures/charts/line_chart.ts b/src/helpers/figures/charts/line_chart.ts index 47111ac58d..ab4725e4f0 100644 --- a/src/helpers/figures/charts/line_chart.ts +++ b/src/helpers/figures/charts/line_chart.ts @@ -16,27 +16,16 @@ import { import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { - AxesDesign, ChartCreationContext, ChartJSRuntime, CustomizedDataSet, DataSet, - DatasetDesign, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { LegendPosition } from "@odoo/o-spreadsheet-engine/types/chart/common_chart"; import { LineChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart/line_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -51,22 +40,26 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class LineChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; - readonly labelsAsText: boolean; - readonly stacked: boolean; - readonly aggregated?: boolean; readonly type = "line"; - readonly dataSetsHaveTitle: boolean; - readonly cumulative: boolean; - readonly dataSetDesign?: DatasetDesign[]; - readonly axesDesign?: AxesDesign; - readonly fillArea?: boolean; - readonly showValues?: boolean; - readonly hideDataMarkers?: boolean; - readonly zoomable?: boolean; - constructor(definition: LineChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof LineChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "labelsAsText", + "stacked", + "aggregated", + "cumulative", + "axesDesign", + "fillArea", + "showValues", + "hideDataMarkers", + "zoomable", + ] as const; + + constructor(private definition: LineChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( this.getters, @@ -75,19 +68,6 @@ export class LineChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.labelsAsText = definition.labelsAsText; - this.stacked = definition.stacked; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.cumulative = definition.cumulative; - this.dataSetDesign = definition.dataSets; - this.axesDesign = definition.axesDesign; - this.fillArea = definition.fillArea; - this.showValues = definition.showValues; - this.hideDataMarkers = definition.hideDataMarkers; - this.zoomable = definition.zoomable; } static validateChartDefinition( @@ -139,30 +119,17 @@ export class LineChart extends AbstractChart { const ranges: CustomizedDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), }); } return { - type: "line", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - labelsAsText: this.labelsAsText, - stacked: this.stacked, - aggregated: this.aggregated, - cumulative: this.cumulative, - axesDesign: this.axesDesign, - fillArea: this.fillArea, - showValues: this.showValues, - hideDataMarkers: this.hideDataMarkers, - zoomable: this.zoomable, - humanize: this.humanize, }; } @@ -170,12 +137,12 @@ export class LineChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -198,16 +165,16 @@ export class LineChart extends AbstractChart { } getDefinitionForExcel(): ExcelChartDefinition | undefined { + const definition = this.getDefinition(); const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel( this.labelRange, this.dataSets, - shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle) + shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], definition.dataSetsHaveTitle) ); - const definition = this.getDefinition(); return { ...definition, - backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR), - fontColor: toXlsxHexColor(chartFontColor(this.background)), + backgroundColor: toXlsxHexColor(definition.background || BACKGROUND_CHART_COLOR), + fontColor: toXlsxHexColor(chartFontColor(definition.background)), dataSets, labelRange, verticalAxis: getDefinedAxis(definition), @@ -260,6 +227,6 @@ export function createLineChartRuntime(chart: LineChart, getters: Getters): Char return { chartJsConfig: config, - background: chart.background || BACKGROUND_CHART_COLOR, + background: definition.background || BACKGROUND_CHART_COLOR, }; } diff --git a/src/helpers/figures/charts/pie_chart.ts b/src/helpers/figures/charts/pie_chart.ts index 164ad4116c..8e01d37e9d 100644 --- a/src/helpers/figures/charts/pie_chart.ts +++ b/src/helpers/figures/charts/pie_chart.ts @@ -19,22 +19,13 @@ import { DataSet, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { LegendPosition } from "@odoo/o-spreadsheet-engine/types/chart/common_chart"; import { PieChartDefinition, PieChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/pie_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import type { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -48,16 +39,21 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class PieChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; readonly type = "pie"; - readonly aggregated?: boolean; - readonly dataSetsHaveTitle: boolean; - readonly isDoughnut?: boolean; - readonly showValues?: boolean; - readonly pieHolePercentage?: number; - constructor(definition: PieChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof PieChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "aggregated", + "isDoughnut", + "pieHolePercentage", + "showValues", + ] as const; + + constructor(private definition: PieChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -66,13 +62,6 @@ export class PieChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.isDoughnut = definition.isDoughnut; - this.showValues = definition.showValues; - this.pieHolePercentage = definition.pieHolePercentage; } static transformDefinition( @@ -113,7 +102,7 @@ export class PieChart extends AbstractChart { getContextCreation(): ChartCreationContext { return { - ...this, + ...this.getDefinition(), range: this.dataSets.map((ds: DataSet) => ({ dataRange: this.getters.getRangeString(ds.dataRange, this.sheetId), })), @@ -129,22 +118,14 @@ export class PieChart extends AbstractChart { targetSheetId?: UID ): PieChartDefinition { return { - type: "pie", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: dataSets.map((ds: DataSet) => ({ dataRange: this.getters.getRangeString(ds.dataRange, targetSheetId || this.sheetId), })), - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - aggregated: this.aggregated, - isDoughnut: this.isDoughnut, - showValues: this.showValues, - pieHolePercentage: this.pieHolePercentage, - humanize: this.humanize, }; } @@ -169,15 +150,16 @@ export class PieChart extends AbstractChart { } getDefinitionForExcel(): ExcelChartDefinition | undefined { + const definition = this.getDefinition(); const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel( this.labelRange, this.dataSets, - shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle) + shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], definition.dataSetsHaveTitle) ); return { - ...this.getDefinition(), - backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR), - fontColor: toXlsxHexColor(chartFontColor(this.background)), + ...definition, + backgroundColor: toXlsxHexColor(definition.background || BACKGROUND_CHART_COLOR), + fontColor: toXlsxHexColor(chartFontColor(definition.background)), dataSets, labelRange, }; @@ -203,7 +185,7 @@ export function createPieChartRuntime(chart: PieChart, getters: Getters): PieCha const chartData = getPieChartData(definition, chart.dataSets, chart.labelRange, getters); const config: ChartConfiguration<"doughnut" | "pie"> = { - type: chart.isDoughnut ? "doughnut" : "pie", + type: definition.isDoughnut ? "doughnut" : "pie", data: { labels: chartData.labels, datasets: getPieChartDatasets(definition, chartData), @@ -211,7 +193,7 @@ export function createPieChartRuntime(chart: PieChart, getters: Getters): PieCha options: { ...CHART_COMMON_OPTIONS, cutout: - chart.isDoughnut && definition.pieHolePercentage !== undefined + definition.isDoughnut && definition.pieHolePercentage !== undefined ? definition.pieHolePercentage + "%" : undefined, layout: getChartLayout(definition, chartData), @@ -224,5 +206,5 @@ export function createPieChartRuntime(chart: PieChart, getters: Getters): PieCha }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { chartJsConfig: config, background: definition.background || BACKGROUND_CHART_COLOR }; } diff --git a/src/helpers/figures/charts/pyramid_chart.ts b/src/helpers/figures/charts/pyramid_chart.ts index beb742033d..987c851a7c 100644 --- a/src/helpers/figures/charts/pyramid_chart.ts +++ b/src/helpers/figures/charts/pyramid_chart.ts @@ -16,29 +16,18 @@ import { import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { - AxesDesign, ChartCreationContext, CustomizedDataSet, DataSet, - DatasetDesign, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { LegendPosition } from "@odoo/o-spreadsheet-engine/types/chart/common_chart"; import { PyramidChartDefinition, PyramidChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/pyramid_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getBarChartDatasets, getBarChartLegend, @@ -53,18 +42,23 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class PyramidChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; - readonly aggregated?: boolean; readonly type = "pyramid"; - readonly dataSetsHaveTitle: boolean; - readonly dataSetDesign?: DatasetDesign[]; - readonly axesDesign?: AxesDesign; - readonly horizontal = true; - readonly stacked = true; - readonly showValues?: boolean; - constructor(definition: PyramidChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof PyramidChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "showValues", + "aggregated", + "axesDesign", + "stacked", + "horizontal", + "zoomable", + ] as const; + + constructor(private definition: PyramidChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -73,13 +67,6 @@ export class PyramidChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.dataSetDesign = definition.dataSets; - this.axesDesign = definition.axesDesign; - this.showValues = definition.showValues; } static transformDefinition( @@ -119,12 +106,12 @@ export class PyramidChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -164,36 +151,29 @@ export class PyramidChart extends AbstractChart { const ranges: CustomizedDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), }); } return { - type: "pyramid", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - aggregated: this.aggregated, - axesDesign: this.axesDesign, horizontal: true, stacked: true, - showValues: this.showValues, - humanize: this.humanize, }; } getDefinitionForExcel(getters: Getters): ExcelChartDefinition | undefined { + const definition = this.getDefinition(); const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel( this.labelRange, this.dataSets, - shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle) + shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], definition.dataSetsHaveTitle) ); - const definition = this.getDefinition(); const chartData = getPyramidChartData(definition, this.dataSets, this.labelRange, getters); const { dataSetsValues } = chartData; const maxValue = Math.max( @@ -202,8 +182,8 @@ export class PyramidChart extends AbstractChart { return { ...definition, horizontal: true, - backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR), - fontColor: toXlsxHexColor(chartFontColor(this.background)), + backgroundColor: toXlsxHexColor(definition.background || BACKGROUND_CHART_COLOR), + fontColor: toXlsxHexColor(chartFontColor(definition.background)), dataSets, labelRange, verticalAxis: getDefinedAxis(definition), @@ -253,5 +233,5 @@ export function createPyramidChartRuntime( }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { chartJsConfig: config, background: definition.background || BACKGROUND_CHART_COLOR }; } diff --git a/src/helpers/figures/charts/radar_chart.ts b/src/helpers/figures/charts/radar_chart.ts index 0207878cda..59366950b4 100644 --- a/src/helpers/figures/charts/radar_chart.ts +++ b/src/helpers/figures/charts/radar_chart.ts @@ -19,7 +19,6 @@ import { CustomizedDataSet, DataSet, ExcelChartDefinition, - LegendPosition, } from "@odoo/o-spreadsheet-engine/types/chart"; import { RadarChartDefinition, @@ -27,16 +26,7 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart/radar_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - DatasetDesign, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -51,18 +41,22 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class RadarChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; - readonly stacked: boolean; - readonly aggregated?: boolean; readonly type = "radar"; - readonly dataSetsHaveTitle: boolean; - readonly dataSetDesign?: DatasetDesign[]; - readonly fillArea?: boolean; - readonly showValues?: boolean; - readonly hideDataMarkers?: boolean; - constructor(definition: RadarChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof RadarChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "showValues", + "aggregated", + "stacked", + "fillArea", + "hideDataMarkers", + ] as const; + + constructor(private definition: RadarChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -71,15 +65,6 @@ export class RadarChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.stacked = definition.stacked; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.dataSetDesign = definition.dataSets; - this.fillArea = definition.fillArea; - this.showValues = definition.showValues; - this.hideDataMarkers = definition.hideDataMarkers; } static transformDefinition( @@ -119,12 +104,12 @@ export class RadarChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -164,40 +149,31 @@ export class RadarChart extends AbstractChart { const ranges: CustomizedDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), }); } return { - type: "radar", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - stacked: this.stacked, - aggregated: this.aggregated, - fillArea: this.fillArea, - showValues: this.showValues, - hideDataMarkers: this.hideDataMarkers, - humanize: this.humanize, }; } getDefinitionForExcel(): ExcelChartDefinition | undefined { + const definition = this.getDefinition(); const { dataSets, labelRange } = this.getCommonDataSetAttributesForExcel( this.labelRange, this.dataSets, - shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle) + shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], definition.dataSetsHaveTitle) ); - const definition = this.getDefinition(); return { ...definition, - backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR), - fontColor: toXlsxHexColor(chartFontColor(this.background)), + backgroundColor: toXlsxHexColor(definition.background || BACKGROUND_CHART_COLOR), + fontColor: toXlsxHexColor(chartFontColor(definition.background)), dataSets, labelRange, }; @@ -241,5 +217,5 @@ export function createRadarChartRuntime(chart: RadarChart, getters: Getters): Ra }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { chartJsConfig: config, background: definition.background || BACKGROUND_CHART_COLOR }; } diff --git a/src/helpers/figures/charts/scatter_chart.ts b/src/helpers/figures/charts/scatter_chart.ts index 565f3490fd..6115101fb9 100644 --- a/src/helpers/figures/charts/scatter_chart.ts +++ b/src/helpers/figures/charts/scatter_chart.ts @@ -18,30 +18,19 @@ import { import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { - AxesDesign, ChartCreationContext, CustomizedDataSet, DataSet, - DatasetDesign, ExcelChartDataset, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { LegendPosition } from "@odoo/o-spreadsheet-engine/types/chart/common_chart"; import { ScatterChartDefinition, ScatterChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/scatter_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -56,18 +45,22 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class ScatterChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; - readonly labelsAsText: boolean; - readonly aggregated?: boolean; readonly type = "scatter"; - readonly dataSetsHaveTitle: boolean; - readonly dataSetDesign?: DatasetDesign[]; - readonly axesDesign?: AxesDesign; - readonly showValues?: boolean; - readonly zoomable?: boolean; - constructor(definition: ScatterChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof ScatterChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "showValues", + "labelsAsText", + "aggregated", + "axesDesign", + "zoomable", + ] as const; + + constructor(private definition: ScatterChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( this.getters, @@ -76,15 +69,6 @@ export class ScatterChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.labelsAsText = definition.labelsAsText; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.dataSetDesign = definition.dataSets; - this.axesDesign = definition.axesDesign; - this.showValues = definition.showValues; - this.zoomable = definition.zoomable; } static validateChartDefinition( @@ -132,26 +116,17 @@ export class ScatterChart extends AbstractChart { const ranges: CustomizedDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), }); } return { - type: "scatter", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - labelsAsText: this.labelsAsText, - aggregated: this.aggregated, - axesDesign: this.axesDesign, - showValues: this.showValues, - zoomable: this.zoomable, - humanize: this.humanize, }; } @@ -159,12 +134,12 @@ export class ScatterChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -187,19 +162,19 @@ export class ScatterChart extends AbstractChart { } getDefinitionForExcel(): ExcelChartDefinition | undefined { + const definition = this.getDefinition(); const dataSets: ExcelChartDataset[] = this.dataSets .map((ds: DataSet) => toExcelDataset(this.getters, ds)) .filter((ds) => ds.range !== ""); const labelRange = toExcelLabelRange( this.getters, this.labelRange, - shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle) + shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], definition.dataSetsHaveTitle) ); - const definition = this.getDefinition(); return { ...definition, - backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR), - fontColor: toXlsxHexColor(chartFontColor(this.background)), + backgroundColor: toXlsxHexColor(definition.background || BACKGROUND_CHART_COLOR), + fontColor: toXlsxHexColor(chartFontColor(definition.background)), dataSets, labelRange, verticalAxis: getDefinedAxis(definition), @@ -257,6 +232,6 @@ export function createScatterChartRuntime( return { chartJsConfig: config, - background: chart.background || BACKGROUND_CHART_COLOR, + background: definition.background || BACKGROUND_CHART_COLOR, }; } diff --git a/src/helpers/figures/charts/sunburst_chart.ts b/src/helpers/figures/charts/sunburst_chart.ts index b1374d71f7..19c574408a 100644 --- a/src/helpers/figures/charts/sunburst_chart.ts +++ b/src/helpers/figures/charts/sunburst_chart.ts @@ -18,22 +18,12 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart"; import { ChartCreationContext, - ChartStyle, CustomizedDataSet, DataSet, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { LegendPosition } from "@odoo/o-spreadsheet-engine/types/chart/common_chart"; import type { ChartConfiguration, ChartOptions } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getChartTitle, getHierarchalChartData, @@ -47,17 +37,22 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class SunburstChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; readonly type = "sunburst"; - readonly dataSetsHaveTitle: boolean; - readonly showValues?: boolean; - readonly showLabels?: boolean; - readonly valuesDesign?: ChartStyle; - readonly groupColors?: (Color | undefined | null)[]; - readonly pieHolePercentage?: number; - - constructor(definition: SunburstChartDefinition, sheetId: UID, getters: CoreGetters) { + + static allowedDefinitionKeys: readonly (keyof SunburstChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "showValues", + "showLabels", + "valuesDesign", + "groupColors", + "pieHolePercentage", + ] as const; + + constructor(private definition: SunburstChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -66,14 +61,6 @@ export class SunburstChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.showValues = definition.showValues; - this.showLabels = definition.showLabels; - this.valuesDesign = definition.valuesDesign; - this.groupColors = definition.groupColors; - this.pieHolePercentage = definition.pieHolePercentage; } static transformDefinition( @@ -111,6 +98,7 @@ export class SunburstChart extends AbstractChart { valuesDesign: context.valuesDesign, groupColors: context.groupColors, humanize: context.humanize, + pieHolePercentage: context.pieHolePercentage, }; } @@ -121,7 +109,7 @@ export class SunburstChart extends AbstractChart { getContextCreation(): ChartCreationContext { const leafRange = this.dataSets.at(-1)?.dataRange; return { - ...this, + ...this.getDefinition(), range: this.labelRange ? [{ dataRange: this.getters.getRangeString(this.labelRange, this.sheetId) }] : [], @@ -138,23 +126,14 @@ export class SunburstChart extends AbstractChart { targetSheetId?: UID ): SunburstChartDefinition { return { - type: "sunburst", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: dataSets.map((ds: DataSet) => ({ dataRange: this.getters.getRangeString(ds.dataRange, targetSheetId || this.sheetId), })), - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - showValues: this.showValues, - showLabels: this.showLabels, - valuesDesign: this.valuesDesign, - groupColors: this.groupColors, - pieHolePercentage: this.pieHolePercentage, - humanize: this.humanize, }; } @@ -210,7 +189,8 @@ export function createSunburstChartRuntime( datasets: getSunburstChartDatasets(definition, chartData), }, options: { - cutout: chart.pieHolePercentage === undefined ? "25%" : `${chart.pieHolePercentage}%`, + cutout: + definition.pieHolePercentage === undefined ? "25%" : `${definition.pieHolePercentage}%`, ...(CHART_COMMON_OPTIONS as ChartOptions<"doughnut">), layout: getChartLayout(definition, chartData), plugins: { @@ -223,5 +203,5 @@ export function createSunburstChartRuntime( }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { chartJsConfig: config, background: definition.background || BACKGROUND_CHART_COLOR }; } diff --git a/src/helpers/figures/charts/tree_map_chart.ts b/src/helpers/figures/charts/tree_map_chart.ts index 48e0763774..6d544fc96f 100644 --- a/src/helpers/figures/charts/tree_map_chart.ts +++ b/src/helpers/figures/charts/tree_map_chart.ts @@ -17,24 +17,13 @@ import { CustomizedDataSet, DataSet, ExcelChartDefinition, - TitleDesign, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { LegendPosition } from "@odoo/o-spreadsheet-engine/types/chart/common_chart"; import { TreeMapChartDefinition, TreeMapChartRuntime, - TreeMapColoringOptions, } from "@odoo/o-spreadsheet-engine/types/chart/tree_map_chart"; import { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getChartTitle, getHierarchalChartData, @@ -53,18 +42,23 @@ export class TreeMapChart extends AbstractChart { }; readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly legendPosition: LegendPosition; readonly type = "treemap"; - readonly dataSetsHaveTitle: boolean; - readonly showHeaders?: boolean; - readonly headerDesign?: TitleDesign; - readonly showValues?: boolean; - readonly showLabels?: boolean; - readonly valuesDesign?: TitleDesign; - readonly coloringOptions?: TreeMapColoringOptions; - constructor(definition: TreeMapChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof TreeMapChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "showHeaders", + "headerDesign", + "showLabels", + "valuesDesign", + "coloringOptions", + "showValues", + ] as const; + + constructor(private definition: TreeMapChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -73,15 +67,6 @@ export class TreeMapChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.legendPosition = definition.legendPosition; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.showHeaders = definition.showHeaders; - this.headerDesign = definition.headerDesign; - this.showValues = definition.showValues; - this.showLabels = definition.showLabels; - this.valuesDesign = definition.valuesDesign; - this.coloringOptions = definition.coloringOptions; } static transformDefinition( @@ -127,7 +112,8 @@ export class TreeMapChart extends AbstractChart { getContextCreation(): ChartCreationContext { const leafRange = this.dataSets.at(-1)?.dataRange; return { - ...this, + ...this.getDefinition(), + treemapColoringOptions: this.definition.coloringOptions, range: this.labelRange ? [{ dataRange: this.getters.getRangeString(this.labelRange, this.sheetId) }] : [], @@ -170,22 +156,12 @@ export class TreeMapChart extends AbstractChart { dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), })); return { - type: "treemap", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - showValues: this.showValues, - showHeaders: this.showHeaders, - headerDesign: this.headerDesign, - showLabels: this.showLabels, - valuesDesign: this.valuesDesign, - coloringOptions: this.coloringOptions, - humanize: this.humanize, }; } @@ -232,5 +208,8 @@ export function createTreeMapChartRuntime( }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { + chartJsConfig: config, + background: definition.background || BACKGROUND_CHART_COLOR, + }; } diff --git a/src/helpers/figures/charts/waterfall_chart.ts b/src/helpers/figures/charts/waterfall_chart.ts index 204a81d914..e9ba0ecc18 100644 --- a/src/helpers/figures/charts/waterfall_chart.ts +++ b/src/helpers/figures/charts/waterfall_chart.ts @@ -13,30 +13,17 @@ import { import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { - AxesDesign, ChartCreationContext, CustomizedDataSet, DataSet, ExcelChartDefinition, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { - LegendPosition, - VerticalAxisPosition, -} from "@odoo/o-spreadsheet-engine/types/chart/common_chart"; import { WaterfallChartDefinition, WaterfallChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/waterfall_chart"; import type { ChartConfiguration } from "chart.js"; -import { - ApplyRangeChange, - Color, - CommandResult, - Getters, - Range, - RangeAdapter, - UID, -} from "../../../types"; +import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; import { getBarChartData, getChartTitle, @@ -51,24 +38,28 @@ import { getChartLayout } from "./runtime/chartjs_layout"; export class WaterfallChart extends AbstractChart { readonly dataSets: DataSet[]; readonly labelRange?: Range | undefined; - readonly background?: Color; - readonly verticalAxisPosition: VerticalAxisPosition; - readonly legendPosition: LegendPosition; - readonly aggregated?: boolean; readonly type = "waterfall"; - readonly dataSetsHaveTitle: boolean; - readonly showSubTotals: boolean; - readonly firstValueAsSubtotal?: boolean; - readonly showConnectorLines: boolean; - readonly positiveValuesColor?: Color; - readonly negativeValuesColor?: Color; - readonly subTotalValuesColor?: Color; - readonly dataSetDesign: CustomizedDataSet[]; - readonly axesDesign?: AxesDesign; - readonly showValues?: boolean; - readonly zoomable?: boolean; - constructor(definition: WaterfallChartDefinition, sheetId: UID, getters: CoreGetters) { + static allowedDefinitionKeys: readonly (keyof WaterfallChartDefinition)[] = [ + ...AbstractChart.commonKeys, + "legendPosition", + "dataSets", + "dataSetsHaveTitle", + "labelRange", + "verticalAxisPosition", + "aggregated", + "showSubTotals", + "showConnectorLines", + "firstValueAsSubtotal", + "positiveValuesColor", + "negativeValuesColor", + "subTotalValuesColor", + "zoomable", + "axesDesign", + "showValues", + ] as const; + + constructor(private definition: WaterfallChartDefinition, sheetId: UID, getters: CoreGetters) { super(definition, sheetId, getters); this.dataSets = createDataSets( getters, @@ -77,21 +68,6 @@ export class WaterfallChart extends AbstractChart { definition.dataSetsHaveTitle ); this.labelRange = createValidRange(getters, sheetId, definition.labelRange); - this.background = definition.background; - this.verticalAxisPosition = definition.verticalAxisPosition; - this.legendPosition = definition.legendPosition; - this.aggregated = definition.aggregated; - this.dataSetsHaveTitle = definition.dataSetsHaveTitle; - this.showSubTotals = definition.showSubTotals; - this.showConnectorLines = definition.showConnectorLines; - this.positiveValuesColor = definition.positiveValuesColor; - this.negativeValuesColor = definition.negativeValuesColor; - this.subTotalValuesColor = definition.subTotalValuesColor; - this.firstValueAsSubtotal = definition.firstValueAsSubtotal; - this.dataSetDesign = definition.dataSets; - this.axesDesign = definition.axesDesign; - this.showValues = definition.showValues; - this.zoomable = definition.zoomable; } static transformDefinition( @@ -134,12 +110,12 @@ export class WaterfallChart extends AbstractChart { const range: CustomizedDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, this.sheetId), }); } return { - ...this, + ...this.getDefinition(), range, auxiliaryRange: this.labelRange ? this.getters.getRangeString(this.labelRange, this.sheetId) @@ -179,32 +155,17 @@ export class WaterfallChart extends AbstractChart { const ranges: CustomizedDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ - ...this.dataSetDesign?.[i], + ...this.definition.dataSets?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), }); } return { - type: "waterfall", + ...this.definition, dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false, - background: this.background, dataSets: ranges, - legendPosition: this.legendPosition, - verticalAxisPosition: this.verticalAxisPosition, labelRange: labelRange ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId) : undefined, - title: this.title, - aggregated: this.aggregated, - showSubTotals: this.showSubTotals, - showConnectorLines: this.showConnectorLines, - positiveValuesColor: this.positiveValuesColor, - negativeValuesColor: this.negativeValuesColor, - subTotalValuesColor: this.subTotalValuesColor, - firstValueAsSubtotal: this.firstValueAsSubtotal, - axesDesign: this.axesDesign, - showValues: this.showValues, - zoomable: this.zoomable, - humanize: this.humanize, }; } @@ -256,5 +217,8 @@ export function createWaterfallChartRuntime( }, }; - return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR }; + return { + chartJsConfig: config, + background: definition.background || BACKGROUND_CHART_COLOR, + }; } diff --git a/src/registries/chart_types.ts b/src/registries/chart_types.ts index c3117c0c83..26f1a0feaf 100644 --- a/src/registries/chart_types.ts +++ b/src/registries/chart_types.ts @@ -55,6 +55,7 @@ chartRegistry.add("bar", { validateChartDefinition: BarChart.validateChartDefinition, transformDefinition: BarChart.transformDefinition, getChartDefinitionFromContextCreation: BarChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: BarChart.allowedDefinitionKeys, sequence: 10, }); chartRegistry.add("combo", { @@ -65,6 +66,7 @@ chartRegistry.add("combo", { validateChartDefinition: ComboChart.validateChartDefinition, transformDefinition: ComboChart.transformDefinition, getChartDefinitionFromContextCreation: ComboChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: ComboChart.allowedDefinitionKeys, sequence: 15, }); chartRegistry.add("line", { @@ -75,6 +77,7 @@ chartRegistry.add("line", { validateChartDefinition: LineChart.validateChartDefinition, transformDefinition: LineChart.transformDefinition, getChartDefinitionFromContextCreation: LineChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: LineChart.allowedDefinitionKeys, sequence: 20, }); chartRegistry.add("pie", { @@ -85,6 +88,7 @@ chartRegistry.add("pie", { validateChartDefinition: PieChart.validateChartDefinition, transformDefinition: PieChart.transformDefinition, getChartDefinitionFromContextCreation: PieChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: PieChart.allowedDefinitionKeys, sequence: 30, }); chartRegistry.add("scorecard", { @@ -95,6 +99,7 @@ chartRegistry.add("scorecard", { validateChartDefinition: ScorecardChart.validateChartDefinition, transformDefinition: ScorecardChart.transformDefinition, getChartDefinitionFromContextCreation: ScorecardChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: ScorecardChart.allowedDefinitionKeys, sequence: 40, }); chartRegistry.add("gauge", { @@ -105,6 +110,7 @@ chartRegistry.add("gauge", { validateChartDefinition: GaugeChart.validateChartDefinition, transformDefinition: GaugeChart.transformDefinition, getChartDefinitionFromContextCreation: GaugeChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: GaugeChart.allowedDefinitionKeys, sequence: 50, }); chartRegistry.add("scatter", { @@ -115,6 +121,7 @@ chartRegistry.add("scatter", { validateChartDefinition: ScatterChart.validateChartDefinition, transformDefinition: ScatterChart.transformDefinition, getChartDefinitionFromContextCreation: ScatterChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: ScatterChart.allowedDefinitionKeys, sequence: 60, }); chartRegistry.add("waterfall", { @@ -125,6 +132,7 @@ chartRegistry.add("waterfall", { validateChartDefinition: WaterfallChart.validateChartDefinition, transformDefinition: WaterfallChart.transformDefinition, getChartDefinitionFromContextCreation: WaterfallChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: WaterfallChart.allowedDefinitionKeys, sequence: 70, }); chartRegistry.add("pyramid", { @@ -135,6 +143,7 @@ chartRegistry.add("pyramid", { validateChartDefinition: PyramidChart.validateChartDefinition, transformDefinition: PyramidChart.transformDefinition, getChartDefinitionFromContextCreation: PyramidChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: PyramidChart.allowedDefinitionKeys, sequence: 80, dataSeriesLimit: 2, }); @@ -146,6 +155,7 @@ chartRegistry.add("radar", { validateChartDefinition: RadarChart.validateChartDefinition, transformDefinition: RadarChart.transformDefinition, getChartDefinitionFromContextCreation: RadarChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: RadarChart.allowedDefinitionKeys, sequence: 80, }); chartRegistry.add("geo", { @@ -156,6 +166,7 @@ chartRegistry.add("geo", { validateChartDefinition: GeoChart.validateChartDefinition, transformDefinition: GeoChart.transformDefinition, getChartDefinitionFromContextCreation: GeoChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: GeoChart.allowedDefinitionKeys, sequence: 90, dataSeriesLimit: 1, }); @@ -167,6 +178,7 @@ chartRegistry.add("funnel", { validateChartDefinition: FunnelChart.validateChartDefinition, transformDefinition: FunnelChart.transformDefinition, getChartDefinitionFromContextCreation: FunnelChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: FunnelChart.allowedDefinitionKeys, sequence: 100, dataSeriesLimit: 1, }); @@ -178,6 +190,7 @@ chartRegistry.add("sunburst", { validateChartDefinition: SunburstChart.validateChartDefinition, transformDefinition: SunburstChart.transformDefinition, getChartDefinitionFromContextCreation: SunburstChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: SunburstChart.allowedDefinitionKeys, sequence: 30, }); chartRegistry.add("treemap", { @@ -188,6 +201,7 @@ chartRegistry.add("treemap", { validateChartDefinition: TreeMapChart.validateChartDefinition, transformDefinition: TreeMapChart.transformDefinition, getChartDefinitionFromContextCreation: TreeMapChart.getDefinitionFromContextCreation, + allowedDefinitionKeys: TreeMapChart.allowedDefinitionKeys, sequence: 100, }); diff --git a/tests/figures/chart/__snapshots__/chart_plugin.test.ts.snap b/tests/figures/chart/__snapshots__/chart_plugin.test.ts.snap index b06bc464aa..122fabde34 100644 --- a/tests/figures/chart/__snapshots__/chart_plugin.test.ts.snap +++ b/tests/figures/chart/__snapshots__/chart_plugin.test.ts.snap @@ -58,7 +58,7 @@ exports[`datasource tests create a chart with stacked bar 1`] = ` "chartShowValuesPlugin": { "background": undefined, "callback": [Function], - "horizontal": undefined, + "horizontal": false, "showValues": false, }, "legend": { diff --git a/tests/figures/chart/sunburst/sunburst_chart_plugin.test.ts b/tests/figures/chart/sunburst/sunburst_chart_plugin.test.ts index 1c1e5cf58e..f2fbd76d05 100644 --- a/tests/figures/chart/sunburst/sunburst_chart_plugin.test.ts +++ b/tests/figures/chart/sunburst/sunburst_chart_plugin.test.ts @@ -67,6 +67,7 @@ describe("Sunburst chart chart", () => { valuesDesign: { italic: true }, groupColors: ["#123456", "#654321"], humanize: false, + pieHolePercentage: 0, }); }); diff --git a/tests/model/model_import_export.test.ts b/tests/model/model_import_export.test.ts index 90fd3b9571..a91c20e76b 100644 --- a/tests/model/model_import_export.test.ts +++ b/tests/model/model_import_export.test.ts @@ -183,6 +183,7 @@ describe("Migrations", () => { legendPosition: "top", stacked: false, humanize: true, + verticalAxisPosition: "left", }); expect(data.sheets[0].figures[1].data).toEqual({ chartId: "2", @@ -195,6 +196,7 @@ describe("Migrations", () => { legendPosition: "top", stacked: false, humanize: true, + verticalAxisPosition: "left", }); expect(data.sheets[0].figures[2].data).toEqual({ chartId: "3", @@ -207,6 +209,7 @@ describe("Migrations", () => { legendPosition: "top", stacked: false, humanize: true, + verticalAxisPosition: "left", }); expect(data.sheets[0].figures[3].data).toEqual({ chartId: "4", @@ -219,6 +222,7 @@ describe("Migrations", () => { legendPosition: "top", stacked: false, humanize: true, + verticalAxisPosition: "left", }); }); test.each(FORBIDDEN_SHEETNAME_CHARS)("migrate version 7: sheet Names", (char) => { @@ -781,6 +785,39 @@ test("migrate version 18.5.1: chartId is added to figure data", () => { expect(model.exportData().sheets[0].figures[0].data.chartId).toBe("someuuid"); }); +test("migrate version 19.1.1: remove extra keys from chart definition", () => { + const definition = { + type: "line", + title: "demo chart", + labelRange: "A1:A4", + humanize: true, + dataSets: [], + dataSetsHaveTitle: false, + }; + const data = { + version: "18.5.1", + sheets: [ + { + id: "sh1", + figures: [ + { + id: "someuuid", + tag: "chart", + data: { + ...definition, + chartId: "someuuid", + extraKey1: "extraValue1", + extraKey2: "extraValue2", + }, + }, + ], + }, + ], + }; + const model = new Model(data); + expect(model.getters.getChartDefinition("someuuid")).toEqual(definition); +}); + describe("Import", () => { test("Import sheet with rows/cols size defined.", () => { const model = new Model({ diff --git a/tests/test_helpers/commands_helpers.ts b/tests/test_helpers/commands_helpers.ts index ed78fb5826..df47295f63 100644 --- a/tests/test_helpers/commands_helpers.ts +++ b/tests/test_helpers/commands_helpers.ts @@ -44,6 +44,9 @@ import { import { createEqualCF, target, toRangeData, toRangesData } from "./helpers"; import { ICON_SETS } from "@odoo/o-spreadsheet-engine/components/icons/icons"; +// import { chartFactory } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_factory"; +// import { chartRegistry } from "@odoo/o-spreadsheet-engine/registries/chart_registry"; +import { chartRegistry } from "@odoo/o-spreadsheet-engine/registries/chart_registry"; import { SunburstChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart"; import { ComboChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart/combo_chart"; import { FunnelChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart/funnel_chart"; @@ -222,6 +225,8 @@ export function createChart( ) { const id = chartId || model.uuidGenerator.uuidv4(); sheetId = sheetId || model.getters.getActiveSheetId(); + + // definition with all possible fields filled const definition = { ...data, title: data.title || { text: "test" }, @@ -241,6 +246,13 @@ export function createChart( showSubTotals: ("showSubTotals" in data && data.showSubTotals) || false, showConnectorLines: ("showConnectorLines" in data && data.showConnectorLines) || false, }; + + const keys = new Set(chartRegistry.get(data.type).allowedDefinitionKeys); + for (const key of Object.keys(definition)) { + if (!keys.has(key)) { + delete definition[key]; + } + } return model.dispatch("CREATE_CHART", { figureId: figureData.figureId || model.uuidGenerator.smallUuid(), chartId: id, @@ -471,15 +483,25 @@ export function updateChart( definition: Partial, sheetId: UID = model.getters.getActiveSheetId() ): DispatchResult { - const def: ChartDefinition = { - ...model.getters.getChartDefinition(chartId), - ...definition, - } as ChartDefinition; + const currentDefinition = model.getters.getChartDefinition(chartId); + let updatedDef: ChartDefinition; + if (definition.type && definition.type !== currentDefinition.type) { + const context = model.getters.getContextCreationChart(chartId); + const converted = chartRegistry + .get(definition.type!) + .getChartDefinitionFromContextCreation(context ?? {}); + updatedDef = { ...converted, ...definition } as ChartDefinition; + } else { + updatedDef = { + ...currentDefinition, + ...definition, + } as ChartDefinition; + } return model.dispatch("UPDATE_CHART", { figureId: model.getters.getFigureIdFromChartId(chartId), chartId, sheetId, - definition: def, + definition: updatedDef, }); } From 67b9546df659b201252675619c4b8c62ae811594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Fri, 14 Nov 2025 16:54:04 +0100 Subject: [PATCH 4/9] [REF] charts: decouple types from Range --- .../src/helpers/figures/charts/chart_common.ts | 15 +++++++-------- .../src/migrations/migration_steps.ts | 4 ++-- .../src/types/chart/bar_chart.ts | 4 ++-- .../src/types/chart/chart.ts | 16 ++++++++++++---- .../src/types/chart/combo_chart.ts | 8 ++++---- .../src/types/chart/common_chart.ts | 11 +++++++---- .../src/types/chart/funnel_chart.ts | 4 ++-- .../src/types/chart/geo_chart.ts | 4 ++-- .../src/types/chart/line_chart.ts | 4 ++-- .../src/types/chart/pie_chart.ts | 4 ++-- .../src/types/chart/radar_chart.ts | 4 ++-- .../src/types/chart/sunburst_chart.ts | 4 ++-- .../src/types/chart/tree_map_chart.ts | 4 ++-- .../src/types/chart/waterfall_chart.ts | 4 ++-- .../building_blocks/data_series/data_series.ts | 4 ++-- .../generic_side_panel/config_panel.ts | 8 ++++---- .../gauge_chart_config_panel.ts | 4 ++-- src/helpers/figures/charts/bar_chart.ts | 6 +++--- src/helpers/figures/charts/combo_chart.ts | 6 ++++-- src/helpers/figures/charts/funnel_chart.ts | 6 +++--- src/helpers/figures/charts/geo_chart.ts | 6 +++--- src/helpers/figures/charts/line_chart.ts | 6 +++--- src/helpers/figures/charts/pyramid_chart.ts | 6 +++--- src/helpers/figures/charts/radar_chart.ts | 6 +++--- src/helpers/figures/charts/scatter_chart.ts | 6 +++--- src/helpers/figures/charts/sunburst_chart.ts | 4 ++-- src/helpers/figures/charts/tree_map_chart.ts | 6 +++--- src/helpers/figures/charts/waterfall_chart.ts | 6 +++--- .../figures/chart/menu_item_insert_chart.test.ts | 6 +++--- tests/xlsx/xlsx_export.test.ts | 4 ++-- 30 files changed, 96 insertions(+), 84 deletions(-) diff --git a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts index e1a43c2aa4..07eb396fe4 100644 --- a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts +++ b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts @@ -3,12 +3,13 @@ import { _t } from "../../../translation"; import { ChartAxisFormats, ChartWithDataSetDefinition, - CustomizedDataSet, + ChartWithRangeDataSetDefinition, DataSet, DatasetValues, ExcelChartDataset, ExcelChartTrendConfiguration, GenericDefinition, + RangeChartDataSet, } from "../../../types/chart"; import { CommandResult } from "../../../types/commands"; import { CoreGetters } from "../../../types/core_getters"; @@ -159,7 +160,7 @@ export function adaptChartRange( */ export function createDataSets( getters: CoreGetters, - customizedDataSets: CustomizedDataSet[], + customizedDataSets: RangeChartDataSet[], sheetId: UID, dataSetsHaveTitle: boolean ): DataSet[] { @@ -323,11 +324,9 @@ export function toExcelLabelRange( * Transform a chart definition which supports dataSets (dataSets and LabelRange) * with an executed command */ -export function transformChartDefinitionWithDataSetsWithZone( - chartSheetId: UID, - definition: T, - applyChange: RangeAdapter -): T { +export function transformChartDefinitionWithDataSetsWithZone< + T extends ChartWithRangeDataSetDefinition +>(chartSheetId: UID, definition: T, applyChange: RangeAdapter): T { let labelRange: string | undefined; if (definition.labelRange) { const adaptedRange = adaptStringRange(chartSheetId, definition.labelRange, applyChange); @@ -336,7 +335,7 @@ export function transformChartDefinitionWithDataSetsWithZone ({ dataRange })); + const newDataSets: RangeChartDataSet = dataSets.map((dataRange) => ({ dataRange })); newData.dataSets = newDataSets; sheet.figures[f].data = newData; } diff --git a/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts index 1e06fa9f07..9e01a4eaa8 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts @@ -1,8 +1,8 @@ import { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { CommonChartDefinition } from "./index"; +import { ChartRangeDefinition } from "./index"; -export interface BarChartDefinition extends CommonChartDefinition { +export interface BarChartDefinition extends ChartRangeDefinition { readonly type: "bar"; readonly stacked: boolean; readonly horizontal?: boolean; diff --git a/packages/o-spreadsheet-engine/src/types/chart/chart.ts b/packages/o-spreadsheet-engine/src/types/chart/chart.ts index 028063eff2..234a2cb1c6 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/chart.ts @@ -63,6 +63,11 @@ export type ChartWithDataSetDefinition = Extract< { dataSets: CustomizedDataSet[]; labelRange?: string; humanize?: boolean } >; +export type ChartWithRangeDataSetDefinition = Extract< + ChartDefinition, + { dataSets: RangeChartDataSet[] } +>; + export type ChartWithAxisDefinition = Extract< ChartWithDataSetDefinition, { axesDesign?: AxesDesign } @@ -136,11 +141,14 @@ export interface TrendConfiguration { window?: number; } -export type CustomizedDataSet = { - readonly dataRange: string; +type CustomizedDataSet = { readonly trend?: TrendConfiguration; } & DatasetDesign; +export type RangeChartDataSet = CustomizedDataSet & { + readonly dataRange: string; +}; + export type AxisType = "category" | "linear" | "time"; export type ChartDatasetOrientation = "rows" | "columns"; @@ -194,8 +202,8 @@ export interface ExcelChartDefinition { } export interface ChartCreationContext { - readonly range?: CustomizedDataSet[]; - readonly hierarchicalRanges?: CustomizedDataSet[]; + readonly range?: RangeChartDataSet[]; + readonly hierarchicalRanges?: RangeChartDataSet[]; readonly title?: TitleDesign; readonly background?: Color; readonly auxiliaryRange?: string; diff --git a/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts index cd0485854a..369abda629 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts @@ -1,16 +1,16 @@ import { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { CustomizedDataSet } from "./chart"; -import { CommonChartDefinition } from "./common_chart"; +import { RangeChartDataSet } from "./chart"; +import { ChartRangeDefinition } from "./common_chart"; -export interface ComboChartDefinition extends CommonChartDefinition { +export interface ComboChartDefinition extends ChartRangeDefinition { readonly dataSets: ComboChartDataSet[]; readonly type: "combo"; readonly hideDataMarkers?: boolean; readonly zoomable?: boolean; } -export type ComboChartDataSet = CustomizedDataSet & { type?: "bar" | "line" }; +export type ComboChartDataSet = RangeChartDataSet & { type?: "bar" | "line" }; export type ComboChartRuntime = { chartJsConfig: ChartConfiguration; diff --git a/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts index a6c5348483..30a67511f8 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts @@ -1,13 +1,10 @@ import { Color } from "../misc"; -import { AxesDesign, CustomizedDataSet, TitleDesign } from "./chart"; +import { AxesDesign, RangeChartDataSet, TitleDesign } from "./chart"; export type VerticalAxisPosition = "left" | "right"; export type LegendPosition = "top" | "bottom" | "left" | "right" | "none"; export interface CommonChartDefinition { - readonly dataSets: CustomizedDataSet[]; - readonly dataSetsHaveTitle: boolean; - readonly labelRange?: string; readonly title: TitleDesign; readonly background?: Color; readonly legendPosition: LegendPosition; @@ -16,3 +13,9 @@ export interface CommonChartDefinition { readonly showValues?: boolean; readonly humanize?: boolean; } + +export interface ChartRangeDefinition extends CommonChartDefinition { + readonly dataSetsHaveTitle: boolean; + readonly labelRange?: string; + readonly dataSets: RangeChartDataSet[]; +} diff --git a/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts index de633d3b21..21d57dca7d 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts @@ -1,11 +1,11 @@ import { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { AxesDesign, CustomizedDataSet, TitleDesign } from "./chart"; +import { AxesDesign, RangeChartDataSet, TitleDesign } from "./chart"; import { LegendPosition } from "./common_chart"; export interface FunnelChartDefinition { readonly type: "funnel"; - readonly dataSets: CustomizedDataSet[]; + readonly dataSets: RangeChartDataSet[]; readonly dataSetsHaveTitle: boolean; readonly labelRange?: string; readonly title: TitleDesign; diff --git a/packages/o-spreadsheet-engine/src/types/chart/geo_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/geo_chart.ts index 8077c12926..01478d5a5b 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/geo_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/geo_chart.ts @@ -1,11 +1,11 @@ import { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { ChartRuntimeGenerationArgs, CustomizedDataSet, TitleDesign } from "./chart"; +import { ChartRuntimeGenerationArgs, RangeChartDataSet, TitleDesign } from "./chart"; import { LegendPosition } from "./common_chart"; export interface GeoChartDefinition { readonly type: "geo"; - readonly dataSets: CustomizedDataSet[]; + readonly dataSets: RangeChartDataSet[]; readonly dataSetsHaveTitle: boolean; readonly labelRange?: string; readonly title: TitleDesign; diff --git a/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts index 6e056932af..df4397acf0 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts @@ -1,8 +1,8 @@ import type { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { CommonChartDefinition } from "./common_chart"; +import { ChartRangeDefinition } from "./common_chart"; -export interface LineChartDefinition extends CommonChartDefinition { +export interface LineChartDefinition extends ChartRangeDefinition { readonly type: "line"; readonly labelsAsText: boolean; readonly stacked: boolean; diff --git a/packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts index 6070949b93..5b193840c9 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts @@ -1,8 +1,8 @@ import type { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { CommonChartDefinition } from "./common_chart"; +import { ChartRangeDefinition } from "./common_chart"; -export interface PieChartDefinition extends CommonChartDefinition { +export interface PieChartDefinition extends ChartRangeDefinition { readonly type: "pie"; readonly aggregated?: boolean; readonly isDoughnut?: boolean; diff --git a/packages/o-spreadsheet-engine/src/types/chart/radar_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/radar_chart.ts index d7ffe4c57a..230bb5bf49 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/radar_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/radar_chart.ts @@ -1,8 +1,8 @@ import { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { CommonChartDefinition } from "./common_chart"; +import { ChartRangeDefinition } from "./common_chart"; -export interface RadarChartDefinition extends CommonChartDefinition { +export interface RadarChartDefinition extends ChartRangeDefinition { readonly type: "radar"; readonly aggregated?: boolean; readonly stacked: boolean; diff --git a/packages/o-spreadsheet-engine/src/types/chart/sunburst_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/sunburst_chart.ts index 608243dada..6f1a67ec57 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/sunburst_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/sunburst_chart.ts @@ -1,11 +1,11 @@ import type { ChartConfiguration, ChartDataset } from "chart.js"; import { Color } from "../misc"; -import { ChartStyle, CustomizedDataSet, TitleDesign } from "./chart"; +import { ChartStyle, RangeChartDataSet, TitleDesign } from "./chart"; import { LegendPosition } from "./common_chart"; export interface SunburstChartDefinition { readonly type: "sunburst"; - readonly dataSets: CustomizedDataSet[]; + readonly dataSets: RangeChartDataSet[]; readonly dataSetsHaveTitle: boolean; readonly labelRange?: string; readonly title: TitleDesign; diff --git a/packages/o-spreadsheet-engine/src/types/chart/tree_map_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/tree_map_chart.ts index e014fedadf..911bdd0edd 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/tree_map_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/tree_map_chart.ts @@ -1,12 +1,12 @@ import { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { CustomizedDataSet, TitleDesign } from "./chart"; +import { RangeChartDataSet, TitleDesign } from "./chart"; import { TreemapDataPoint } from "./chartjs_tree_map_type"; import { LegendPosition } from "./common_chart"; export interface TreeMapChartDefinition { readonly type: "treemap"; - readonly dataSets: CustomizedDataSet[]; + readonly dataSets: RangeChartDataSet[]; readonly dataSetsHaveTitle: boolean; readonly labelRange?: string; readonly title: TitleDesign; diff --git a/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts index bbafe0b16d..d4dd9174e0 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts @@ -1,8 +1,8 @@ import type { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { CommonChartDefinition, VerticalAxisPosition } from "./common_chart"; +import { ChartRangeDefinition, VerticalAxisPosition } from "./common_chart"; -export interface WaterfallChartDefinition extends CommonChartDefinition { +export interface WaterfallChartDefinition extends ChartRangeDefinition { readonly type: "waterfall"; readonly verticalAxisPosition: VerticalAxisPosition; readonly aggregated?: boolean; diff --git a/src/components/side_panel/chart/building_blocks/data_series/data_series.ts b/src/components/side_panel/chart/building_blocks/data_series/data_series.ts index 1cf6d675aa..45687b8c3f 100644 --- a/src/components/side_panel/chart/building_blocks/data_series/data_series.ts +++ b/src/components/side_panel/chart/building_blocks/data_series/data_series.ts @@ -1,12 +1,12 @@ import { _t } from "@odoo/o-spreadsheet-engine/translation"; import { SpreadsheetChildEnv } from "@odoo/o-spreadsheet-engine/types/spreadsheet_env"; import { Component } from "@odoo/owl"; -import { ChartDatasetOrientation, Color, CustomizedDataSet } from "../../../../../types"; +import { ChartDatasetOrientation, Color, RangeChartDataSet } from "../../../../../types"; import { SelectionInput } from "../../../../selection_input/selection_input"; import { Section } from "../../../components/section/section"; interface Props { - ranges: CustomizedDataSet[]; + ranges: RangeChartDataSet[]; hasSingleRange?: boolean; onSelectionChanged: (ranges: string[]) => void; onSelectionReordered?: (indexes: number[]) => void; diff --git a/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts b/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts index 38b3af3827..f704941d1d 100644 --- a/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts +++ b/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts @@ -20,8 +20,8 @@ import { ChartDatasetOrientation, ChartWithDataSetDefinition, CommandResult, - CustomizedDataSet, DispatchResult, + RangeChartDataSet, UID, Zone, } from "../../../../../types"; @@ -64,7 +64,7 @@ export class GenericChartConfigPanel extends Component }); } - getDataRange(): CustomizedDataSet { + getDataRange(): RangeChartDataSet { return { dataRange: this.dataRange || "" }; } } diff --git a/src/helpers/figures/charts/bar_chart.ts b/src/helpers/figures/charts/bar_chart.ts index 91a2304739..7bfe203c99 100644 --- a/src/helpers/figures/charts/bar_chart.ts +++ b/src/helpers/figures/charts/bar_chart.ts @@ -21,9 +21,9 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart/bar_chart"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { CommandResult } from "@odoo/o-spreadsheet-engine/types/commands"; import { Getters } from "@odoo/o-spreadsheet-engine/types/getters"; @@ -107,7 +107,7 @@ export class BarChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], @@ -152,7 +152,7 @@ export class BarChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): BarChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: RangeChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.definition.dataSets?.[i], diff --git a/src/helpers/figures/charts/combo_chart.ts b/src/helpers/figures/charts/combo_chart.ts index 26c910f355..236599efc8 100644 --- a/src/helpers/figures/charts/combo_chart.ts +++ b/src/helpers/figures/charts/combo_chart.ts @@ -15,6 +15,9 @@ import { } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; +import { + RangeChartDataSet, +} from "@odoo/o-spreadsheet-engine/types/chart"; import { ComboChartDataSet, ComboChartDefinition, @@ -26,7 +29,6 @@ import { ApplyRangeChange, ChartCreationContext, CommandResult, - CustomizedDataSet, DataSet, ExcelChartDefinition, Getters, @@ -90,7 +92,7 @@ export class ComboChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], diff --git a/src/helpers/figures/charts/funnel_chart.ts b/src/helpers/figures/charts/funnel_chart.ts index 41cb234b63..cf8f1a18f4 100644 --- a/src/helpers/figures/charts/funnel_chart.ts +++ b/src/helpers/figures/charts/funnel_chart.ts @@ -15,9 +15,9 @@ import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { FunnelChartDefinition, FunnelChartRuntime } from "@odoo/o-spreadsheet-engine/types/chart"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { ChartConfiguration } from "chart.js"; import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; @@ -96,7 +96,7 @@ export class FunnelChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], @@ -141,7 +141,7 @@ export class FunnelChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): FunnelChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: RangeChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.definition.dataSets?.[i], diff --git a/src/helpers/figures/charts/geo_chart.ts b/src/helpers/figures/charts/geo_chart.ts index 0d8e8a897e..bc71dec2d0 100644 --- a/src/helpers/figures/charts/geo_chart.ts +++ b/src/helpers/figures/charts/geo_chart.ts @@ -14,9 +14,9 @@ import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { GeoChartDefinition, @@ -89,7 +89,7 @@ export class GeoChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], @@ -134,7 +134,7 @@ export class GeoChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): GeoChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: RangeChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.definition.dataSets?.[i], diff --git a/src/helpers/figures/charts/line_chart.ts b/src/helpers/figures/charts/line_chart.ts index ab4725e4f0..31141ddda3 100644 --- a/src/helpers/figures/charts/line_chart.ts +++ b/src/helpers/figures/charts/line_chart.ts @@ -18,9 +18,9 @@ import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { ChartCreationContext, ChartJSRuntime, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { LineChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart/line_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; @@ -116,7 +116,7 @@ export class LineChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): LineChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: RangeChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.definition.dataSets?.[i], @@ -134,7 +134,7 @@ export class LineChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], diff --git a/src/helpers/figures/charts/pyramid_chart.ts b/src/helpers/figures/charts/pyramid_chart.ts index 987c851a7c..facb008b86 100644 --- a/src/helpers/figures/charts/pyramid_chart.ts +++ b/src/helpers/figures/charts/pyramid_chart.ts @@ -17,9 +17,9 @@ import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { PyramidChartDefinition, @@ -103,7 +103,7 @@ export class PyramidChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], @@ -148,7 +148,7 @@ export class PyramidChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): PyramidChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: RangeChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.definition.dataSets?.[i], diff --git a/src/helpers/figures/charts/radar_chart.ts b/src/helpers/figures/charts/radar_chart.ts index 59366950b4..e9711964b5 100644 --- a/src/helpers/figures/charts/radar_chart.ts +++ b/src/helpers/figures/charts/radar_chart.ts @@ -16,9 +16,9 @@ import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart"; import { RadarChartDefinition, @@ -101,7 +101,7 @@ export class RadarChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], @@ -146,7 +146,7 @@ export class RadarChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): RadarChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: RangeChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.definition.dataSets?.[i], diff --git a/src/helpers/figures/charts/scatter_chart.ts b/src/helpers/figures/charts/scatter_chart.ts index 6115101fb9..897c3aa0b9 100644 --- a/src/helpers/figures/charts/scatter_chart.ts +++ b/src/helpers/figures/charts/scatter_chart.ts @@ -19,10 +19,10 @@ import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDataset, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { ScatterChartDefinition, @@ -113,7 +113,7 @@ export class ScatterChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): ScatterChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: RangeChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.definition.dataSets?.[i], @@ -131,7 +131,7 @@ export class ScatterChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], diff --git a/src/helpers/figures/charts/sunburst_chart.ts b/src/helpers/figures/charts/sunburst_chart.ts index 19c574408a..2ce0cb80fd 100644 --- a/src/helpers/figures/charts/sunburst_chart.ts +++ b/src/helpers/figures/charts/sunburst_chart.ts @@ -18,9 +18,9 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import type { ChartConfiguration, ChartOptions } from "chart.js"; import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; @@ -79,7 +79,7 @@ export class SunburstChart extends AbstractChart { } static getDefinitionFromContextCreation(context: ChartCreationContext): SunburstChartDefinition { - const dataSets: CustomizedDataSet[] = []; + const dataSets: RangeChartDataSet[] = []; if (context.hierarchicalRanges?.length) { dataSets.push(...context.hierarchicalRanges); } else if (context.auxiliaryRange) { diff --git a/src/helpers/figures/charts/tree_map_chart.ts b/src/helpers/figures/charts/tree_map_chart.ts index 6d544fc96f..1d1e58d8bc 100644 --- a/src/helpers/figures/charts/tree_map_chart.ts +++ b/src/helpers/figures/charts/tree_map_chart.ts @@ -14,9 +14,9 @@ import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { TreeMapChartDefinition, @@ -85,7 +85,7 @@ export class TreeMapChart extends AbstractChart { } static getDefinitionFromContextCreation(context: ChartCreationContext): TreeMapChartDefinition { - const dataSets: CustomizedDataSet[] = []; + const dataSets: RangeChartDataSet[] = []; if (context.hierarchicalRanges?.length) { dataSets.push(...context.hierarchicalRanges); } else if (context.auxiliaryRange) { @@ -152,7 +152,7 @@ export class TreeMapChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): TreeMapChartDefinition { - const ranges: CustomizedDataSet[] = dataSets.map((dataSet) => ({ + const ranges: RangeChartDataSet[] = dataSets.map((dataSet) => ({ dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), })); return { diff --git a/src/helpers/figures/charts/waterfall_chart.ts b/src/helpers/figures/charts/waterfall_chart.ts index e9ba0ecc18..2a5ec41e37 100644 --- a/src/helpers/figures/charts/waterfall_chart.ts +++ b/src/helpers/figures/charts/waterfall_chart.ts @@ -14,9 +14,9 @@ import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { ChartCreationContext, - CustomizedDataSet, DataSet, ExcelChartDefinition, + RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { WaterfallChartDefinition, @@ -107,7 +107,7 @@ export class WaterfallChart extends AbstractChart { } getContextCreation(): ChartCreationContext { - const range: CustomizedDataSet[] = []; + const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { range.push({ ...this.definition.dataSets?.[i], @@ -152,7 +152,7 @@ export class WaterfallChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): WaterfallChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: RangeChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.definition.dataSets?.[i], diff --git a/tests/figures/chart/menu_item_insert_chart.test.ts b/tests/figures/chart/menu_item_insert_chart.test.ts index bde7e7430f..ad56a60433 100644 --- a/tests/figures/chart/menu_item_insert_chart.test.ts +++ b/tests/figures/chart/menu_item_insert_chart.test.ts @@ -5,7 +5,7 @@ import { DEFAULT_FIGURE_WIDTH, } from "@odoo/o-spreadsheet-engine/constants"; import { SpreadsheetChildEnv } from "@odoo/o-spreadsheet-engine/types/spreadsheet_env"; -import { ChartDefinition, CustomizedDataSet, Model } from "../../../src"; +import { ChartDefinition, Model, RangeChartDataSet } from "../../../src"; import { toXC, zoneToXc } from "../../../src/helpers"; import { addColumns, @@ -537,7 +537,7 @@ describe("Smart chart type detection", () => { doAction(["insert", "insert_chart"], env); const datasetLastCol = datasetPattern.findIndex((p) => !p.includes("text")); - const expectedDatasets: CustomizedDataSet[] = []; + const expectedDatasets: RangeChartDataSet[] = []; for (let i = 0; i < datasetLastCol; i++) { expectedDatasets.push({ dataRange: toXC(i, 0) + ":" + toXC(i, 5) }); } @@ -567,7 +567,7 @@ describe("Smart chart type detection", () => { createDatasetFromDescription(datasetPattern); doAction(["insert", "insert_chart"], env); - const expectedDatasets: CustomizedDataSet[] = []; + const expectedDatasets: RangeChartDataSet[] = []; for (let i = 1; i < datasetPattern.length; i++) { expectedDatasets.push({ dataRange: toXC(i, 0) + ":" + toXC(i, 5) }); } diff --git a/tests/xlsx/xlsx_export.test.ts b/tests/xlsx/xlsx_export.test.ts index 5274b69e2e..5c996355fd 100644 --- a/tests/xlsx/xlsx_export.test.ts +++ b/tests/xlsx/xlsx_export.test.ts @@ -7,7 +7,7 @@ import { hexaToInt } from "@odoo/o-spreadsheet-engine/xlsx/conversion"; import { adaptFormulaToExcel } from "@odoo/o-spreadsheet-engine/xlsx/functions/cells"; import { escapeXml, parseXML } from "@odoo/o-spreadsheet-engine/xlsx/helpers/xml_helpers"; import { buildSheetLink, toXC } from "../../src/helpers"; -import { CustomizedDataSet, Dimension } from "../../src/types"; +import { Dimension, RangeChartDataSet } from "../../src/types"; import { arg } from "@odoo/o-spreadsheet-engine/functions/arguments"; import { functionRegistry } from "@odoo/o-spreadsheet-engine/functions/function_registry"; @@ -1132,7 +1132,7 @@ describe("Test XLSX export", () => { ["radar", [{ dataRange: "Sheet1!B1:B4" }]], ])( "simple %s chart with dataset %s", - async (chartType: string, dataSets: CustomizedDataSet[]) => { + async (chartType: string, dataSets: RangeChartDataSet[]) => { const model = new Model(chartData); createChart( model, From 0ae02dc24ea4fa189d3a3d1d3e777b792f7a5e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Sat, 15 Nov 2025 10:48:03 +0100 Subject: [PATCH 5/9] [REF] charts: simplify types Those types are too precise for what's actually needed. A weaker type is enough --- src/helpers/figures/charts/runtime/chartjs_show_values.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/figures/charts/runtime/chartjs_show_values.ts b/src/helpers/figures/charts/runtime/chartjs_show_values.ts index 6f0a319c64..a85e403239 100644 --- a/src/helpers/figures/charts/runtime/chartjs_show_values.ts +++ b/src/helpers/figures/charts/runtime/chartjs_show_values.ts @@ -1,7 +1,7 @@ import { formatChartDatasetValue } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { + ChartDefinition, ChartRuntimeGenerationArgs, - ChartWithDataSetDefinition, SunburstChartDefaults, SunburstChartDefinition, WaterfallChartDefinition, @@ -11,7 +11,7 @@ import { ChartShowValuesPluginOptions } from "../../../../components/figures/cha import { ChartSunburstLabelsPluginOptions } from "../../../../components/figures/chart/chartJs/chartjs_sunburst_labels_plugin"; export function getChartShowValues( - definition: ChartWithDataSetDefinition, + definition: ChartDefinition, args: ChartRuntimeGenerationArgs ): ChartShowValuesPluginOptions { const { axisFormats, locale } = args; @@ -46,7 +46,7 @@ export function getSunburstShowValues( } export function getPyramidChartShowValues( - definition: ChartWithDataSetDefinition, + definition: ChartDefinition, args: ChartRuntimeGenerationArgs ): ChartShowValuesPluginOptions { const { axisFormats, locale } = args; @@ -93,7 +93,7 @@ export function getWaterfallChartShowValues( }; } -function getDatasetAxisId(definition: ChartWithDataSetDefinition, dataset: ChartMeta): string { +function getDatasetAxisId(definition: ChartDefinition, dataset: ChartMeta): string { if (dataset.rAxisID) { return dataset.rAxisID; } From 5e2f108bcfb5aa0ae73af05a472924cb6afa8e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Mon, 17 Nov 2025 15:09:24 +0100 Subject: [PATCH 6/9] it's building --- .../src/helpers/figures/charts/chart_common.ts | 4 ++-- .../generic_side_panel/config_panel.ts | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts index 07eb396fe4..d47f10bba2 100644 --- a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts +++ b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts @@ -371,7 +371,7 @@ export function chartMutedFontColor(backgroundColor: Color | undefined): Color { return relativeLuminance(backgroundColor) < 0.3 ? "#C8C8C8" : "#666666"; } -export function checkDataset(definition: ChartWithDataSetDefinition): CommandResult { +export function checkDataset(definition: ChartWithRangeDataSetDefinition): CommandResult { if (definition.dataSets) { const invalidRanges = definition.dataSets.find((range) => !rangeReference.test(range.dataRange)) !== undefined; @@ -386,7 +386,7 @@ export function checkDataset(definition: ChartWithDataSetDefinition): CommandRes return CommandResult.Success; } -export function checkLabelRange(definition: ChartWithDataSetDefinition): CommandResult { +export function checkLabelRange(definition: ChartWithRangeDataSetDefinition): CommandResult { if (definition.labelRange) { const invalidLabels = !rangeReference.test(definition.labelRange || ""); if (invalidLabels) { diff --git a/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts b/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts index f704941d1d..4e77036585 100644 --- a/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts +++ b/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts @@ -18,7 +18,7 @@ import { createDataSets } from "../../../../../helpers/figures/charts"; import { getChartColorsGenerator } from "../../../../../helpers/figures/charts/runtime"; import { ChartDatasetOrientation, - ChartWithDataSetDefinition, + ChartWithRangeDataSetDefinition, CommandResult, DispatchResult, RangeChartDataSet, @@ -33,9 +33,15 @@ import { ChartLabelRange } from "../label_range/label_range"; interface Props { chartId: UID; - definition: ChartWithDataSetDefinition; - canUpdateChart: (chartId: UID, definition: Partial) => DispatchResult; - updateChart: (chartId: UID, definition: Partial) => DispatchResult; + definition: ChartWithRangeDataSetDefinition; + canUpdateChart: ( + chartId: UID, + definition: Partial + ) => DispatchResult; + updateChart: ( + chartId: UID, + definition: Partial + ) => DispatchResult; } interface ChartPanelState { @@ -270,7 +276,9 @@ export class GenericChartConfigPanel extends Component Date: Wed, 19 Nov 2025 16:13:43 +0100 Subject: [PATCH 7/9] brol --- .../src/types/chart/bar_chart.ts | 8 +++-- .../src/types/chart/chart.ts | 32 +++++++++++-------- .../src/types/chart/combo_chart.ts | 13 ++++---- .../src/types/chart/common_chart.ts | 20 ++++++++++-- .../src/types/chart/funnel_chart.ts | 11 +++---- .../src/types/chart/geo_chart.ts | 11 +++---- .../src/types/chart/line_chart.ts | 9 ++++-- .../src/types/chart/pie_chart.ts | 4 +-- .../src/types/chart/radar_chart.ts | 4 +-- .../src/types/chart/waterfall_chart.ts | 4 +-- 10 files changed, 69 insertions(+), 47 deletions(-) diff --git a/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts index 9e01a4eaa8..d6ff493399 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts @@ -1,12 +1,14 @@ import { ChartConfiguration } from "chart.js"; -import { Color } from "../misc"; -import { ChartRangeDefinition } from "./index"; +import { Color, UID } from "../misc"; +import { ChartDataSource, CommonChartDefinition, DataSetDesign } from "./index"; -export interface BarChartDefinition extends ChartRangeDefinition { +export interface BarChartDefinition extends CommonChartDefinition { readonly type: "bar"; readonly stacked: boolean; readonly horizontal?: boolean; readonly zoomable?: boolean; + readonly datasetsDesign: Record; + readonly dataSource: ChartDataSource; } export type BarChartRuntime = { diff --git a/packages/o-spreadsheet-engine/src/types/chart/chart.ts b/packages/o-spreadsheet-engine/src/types/chart/chart.ts index 234a2cb1c6..ba5d4c788d 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/chart.ts @@ -1,5 +1,5 @@ import { Point } from "chart.js"; -import { Align, Color, VerticalAlign } from "../misc"; +import { Align, Color, UID, VerticalAlign } from "../misc"; import { XlsxHexColor } from "../xlsx"; import { BarChartDefinition, BarChartRuntime } from "./bar_chart"; import { ComboChartDefinition, ComboChartRuntime } from "./combo_chart"; @@ -58,10 +58,17 @@ export type ChartDefinition = | SunburstChartDefinition | TreeMapChartDefinition; -export type ChartWithDataSetDefinition = Extract< - ChartDefinition, - { dataSets: CustomizedDataSet[]; labelRange?: string; humanize?: boolean } ->; +// export type ChartWithDataSetDefinition = Extract< +// ChartDefinition, +// { dataSets: CustomizedDataSet[]; labelRange?: string; humanize?: boolean } +// >; +export interface ChartWithDataSetDefinition { + readonly datasetsDesign: Record; +} + +// const a: ChartWithDataSetDefinition = {}; + +// a. export type ChartWithRangeDataSetDefinition = Extract< ChartDefinition, @@ -102,12 +109,6 @@ export interface DatasetValues { readonly hidden?: boolean; } -export interface DatasetDesign { - readonly backgroundColor?: string; - readonly yAxisId?: string; - readonly label?: string; -} - export interface AxisDesign { readonly title?: TitleDesign; } @@ -141,11 +142,14 @@ export interface TrendConfiguration { window?: number; } -type CustomizedDataSet = { +export type DataSetDesign = { readonly trend?: TrendConfiguration; -} & DatasetDesign; + readonly backgroundColor?: string; + readonly yAxisId?: string; + readonly label?: string; +}; -export type RangeChartDataSet = CustomizedDataSet & { +export type RangeChartDataSet = DataSetDesign & { readonly dataRange: string; }; diff --git a/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts index 369abda629..52839d6d13 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts @@ -1,16 +1,17 @@ import { ChartConfiguration } from "chart.js"; -import { Color } from "../misc"; -import { RangeChartDataSet } from "./chart"; -import { ChartRangeDefinition } from "./common_chart"; +import { Color, UID } from "../misc"; +import { DataSetDesign } from "./chart"; +import { ChartDataSource, CommonChartDefinition } from "./common_chart"; -export interface ComboChartDefinition extends ChartRangeDefinition { - readonly dataSets: ComboChartDataSet[]; +export interface ComboChartDefinition extends CommonChartDefinition { + readonly datasetsDesign: Record; + readonly dataSource: ChartDataSource; readonly type: "combo"; readonly hideDataMarkers?: boolean; readonly zoomable?: boolean; } -export type ComboChartDataSet = RangeChartDataSet & { type?: "bar" | "line" }; +export type ComboDataSetDesign = DataSetDesign & { type?: "bar" | "line" }; export type ComboChartRuntime = { chartJsConfig: ChartConfiguration; diff --git a/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts index 30a67511f8..6d9742175d 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts @@ -1,5 +1,5 @@ -import { Color } from "../misc"; -import { AxesDesign, RangeChartDataSet, TitleDesign } from "./chart"; +import { Color, UID } from "../misc"; +import { AxesDesign, TitleDesign } from "./chart"; export type VerticalAxisPosition = "left" | "right"; export type LegendPosition = "top" | "bottom" | "left" | "right" | "none"; @@ -15,7 +15,21 @@ export interface CommonChartDefinition { } export interface ChartRangeDefinition extends CommonChartDefinition { + dataSource: ChartDataSource; +} + +interface ChartCellsDataSource { + readonly type: "cells"; readonly dataSetsHaveTitle: boolean; readonly labelRange?: string; - readonly dataSets: RangeChartDataSet[]; + readonly dataSets: { dataRange: string; id: UID }[]; } + +interface ChartPivotDataSource { + readonly type: "pivot"; + readonly pivotId: UID; + readonly measureId: UID; + readonly mainAxis: "rows" | "columns"; +} + +export type ChartDataSource = ChartCellsDataSource | ChartPivotDataSource; diff --git a/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts index 21d57dca7d..eaadbce5cf 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts @@ -1,13 +1,12 @@ import { ChartConfiguration } from "chart.js"; -import { Color } from "../misc"; -import { AxesDesign, RangeChartDataSet, TitleDesign } from "./chart"; -import { LegendPosition } from "./common_chart"; +import { Color, UID } from "../misc"; +import { AxesDesign, DataSetDesign, TitleDesign } from "./chart"; +import { ChartDataSource, LegendPosition } from "./common_chart"; export interface FunnelChartDefinition { readonly type: "funnel"; - readonly dataSets: RangeChartDataSet[]; - readonly dataSetsHaveTitle: boolean; - readonly labelRange?: string; + readonly datasetsDesign: Record; + readonly dataSource: ChartDataSource; readonly title: TitleDesign; readonly background?: Color; readonly legendPosition: LegendPosition; diff --git a/packages/o-spreadsheet-engine/src/types/chart/geo_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/geo_chart.ts index 01478d5a5b..717afc52e9 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/geo_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/geo_chart.ts @@ -1,13 +1,12 @@ import { ChartConfiguration } from "chart.js"; -import { Color } from "../misc"; -import { ChartRuntimeGenerationArgs, RangeChartDataSet, TitleDesign } from "./chart"; -import { LegendPosition } from "./common_chart"; +import { Color, UID } from "../misc"; +import { ChartRuntimeGenerationArgs, DataSetDesign, TitleDesign } from "./chart"; +import { ChartDataSource, LegendPosition } from "./common_chart"; export interface GeoChartDefinition { readonly type: "geo"; - readonly dataSets: RangeChartDataSet[]; - readonly dataSetsHaveTitle: boolean; - readonly labelRange?: string; + readonly datasetsDesign: Record; + readonly dataSource: ChartDataSource; readonly title: TitleDesign; readonly background?: Color; readonly legendPosition: LegendPosition; diff --git a/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts index df4397acf0..2d9224d01d 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts @@ -1,9 +1,12 @@ import type { ChartConfiguration } from "chart.js"; -import { Color } from "../misc"; -import { ChartRangeDefinition } from "./common_chart"; +import { Color, UID } from "../misc"; +import { DataSetDesign } from "./chart"; +import { ChartDataSource, CommonChartDefinition } from "./common_chart"; -export interface LineChartDefinition extends ChartRangeDefinition { +export interface LineChartDefinition extends CommonChartDefinition { readonly type: "line"; + readonly datasetsDesign: Record; + readonly dataSource: ChartDataSource; readonly labelsAsText: boolean; readonly stacked: boolean; readonly aggregated?: boolean; diff --git a/packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts index 5b193840c9..6070949b93 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts @@ -1,8 +1,8 @@ import type { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { ChartRangeDefinition } from "./common_chart"; +import { CommonChartDefinition } from "./common_chart"; -export interface PieChartDefinition extends ChartRangeDefinition { +export interface PieChartDefinition extends CommonChartDefinition { readonly type: "pie"; readonly aggregated?: boolean; readonly isDoughnut?: boolean; diff --git a/packages/o-spreadsheet-engine/src/types/chart/radar_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/radar_chart.ts index 230bb5bf49..d7ffe4c57a 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/radar_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/radar_chart.ts @@ -1,8 +1,8 @@ import { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { ChartRangeDefinition } from "./common_chart"; +import { CommonChartDefinition } from "./common_chart"; -export interface RadarChartDefinition extends ChartRangeDefinition { +export interface RadarChartDefinition extends CommonChartDefinition { readonly type: "radar"; readonly aggregated?: boolean; readonly stacked: boolean; diff --git a/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts index d4dd9174e0..8c9c822240 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts @@ -1,8 +1,8 @@ import type { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { ChartRangeDefinition, VerticalAxisPosition } from "./common_chart"; +import { VerticalAxisPosition } from "./common_chart"; -export interface WaterfallChartDefinition extends ChartRangeDefinition { +export interface WaterfallChartDefinition extends CommonChartDefinition { readonly type: "waterfall"; readonly verticalAxisPosition: VerticalAxisPosition; readonly aggregated?: boolean; From 33bc5135d24ee9ae31d6cd59002a70df93c64178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Thu, 20 Nov 2025 09:15:56 +0100 Subject: [PATCH 8/9] m --- .../helpers/figures/charts/chart_common.ts | 93 ++++++++++--------- .../helpers/figures/charts/chart_factory.ts | 8 ++ .../src/registries/chart_registry.ts | 28 +++--- .../src/types/chart/bar_chart.ts | 6 +- .../src/types/chart/chart.ts | 5 +- .../src/types/chart/combo_chart.ts | 7 +- .../src/types/chart/common_chart.ts | 4 +- .../src/types/chart/funnel_chart.ts | 16 +--- .../src/types/chart/line_chart.ts | 7 +- .../src/types/chart/sunburst_chart.ts | 11 +-- .../src/types/chart/tree_map_chart.ts | 11 +-- .../src/types/chart/waterfall_chart.ts | 2 +- src/helpers/figures/charts/bar_chart.ts | 28 +----- src/helpers/figures/charts/combo_chart.ts | 31 +------ src/helpers/figures/charts/funnel_chart.ts | 27 +----- src/helpers/figures/charts/geo_chart.ts | 27 +----- src/helpers/figures/charts/line_chart.ts | 27 +----- src/helpers/figures/charts/pie_chart.ts | 27 +----- src/helpers/figures/charts/pyramid_chart.ts | 27 +----- src/helpers/figures/charts/radar_chart.ts | 27 +----- src/helpers/figures/charts/scatter_chart.ts | 27 +----- src/helpers/figures/charts/sunburst_chart.ts | 27 +----- src/helpers/figures/charts/tree_map_chart.ts | 27 +----- src/helpers/figures/charts/waterfall_chart.ts | 22 +---- src/registries/chart_types.ts | 50 +++++----- 25 files changed, 170 insertions(+), 402 deletions(-) diff --git a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts index d47f10bba2..14e62b763f 100644 --- a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts +++ b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_common.ts @@ -2,8 +2,8 @@ import { DEFAULT_WINDOW_SIZE, MAX_CHAR_LABEL } from "../../../constants"; import { _t } from "../../../translation"; import { ChartAxisFormats, + ChartDataSource, ChartWithDataSetDefinition, - ChartWithRangeDataSetDefinition, DataSet, DatasetValues, ExcelChartDataset, @@ -325,32 +325,36 @@ export function toExcelLabelRange( * with an executed command */ export function transformChartDefinitionWithDataSetsWithZone< - T extends ChartWithRangeDataSetDefinition + T extends { dataSource: ChartDataSource } >(chartSheetId: UID, definition: T, applyChange: RangeAdapter): T { - let labelRange: string | undefined; - if (definition.labelRange) { - const adaptedRange = adaptStringRange(chartSheetId, definition.labelRange, applyChange); - if (adaptedRange !== CellErrorType.InvalidReference) { - labelRange = adaptedRange; - } - } - - const dataSets: RangeChartDataSet[] = []; - for (const dataSet of definition.dataSets) { - const newDataSet = { ...dataSet }; - const adaptedRange = adaptStringRange(chartSheetId, dataSet.dataRange, applyChange); - - if (adaptedRange !== CellErrorType.InvalidReference) { - newDataSet.dataRange = adaptedRange; - dataSets.push(newDataSet); + switch (definition.dataSource.type) { + case "cells": { + const dataSource = definition.dataSource; + let labelRange: string | undefined; + if (dataSource.labelRange) { + const adaptedRange = adaptStringRange(chartSheetId, dataSource.labelRange, applyChange); + if (adaptedRange !== CellErrorType.InvalidReference) { + labelRange = adaptedRange; + } + } + const dataSets: RangeChartDataSet[] = []; + for (const dataSet of dataSource.dataSets) { + const newDataSet = { ...dataSet }; + const adaptedRange = adaptStringRange(chartSheetId, dataSet.dataRange, applyChange); + if (adaptedRange !== CellErrorType.InvalidReference) { + newDataSet.dataRange = adaptedRange; + dataSets.push(newDataSet); + } + } + return { + ...definition, + dataSets, + labelRange, + }; } + case "pivot": + return definition; } - - return { - ...definition, - dataSets, - labelRange, - }; } /** @@ -371,29 +375,30 @@ export function chartMutedFontColor(backgroundColor: Color | undefined): Color { return relativeLuminance(backgroundColor) < 0.3 ? "#C8C8C8" : "#666666"; } -export function checkDataset(definition: ChartWithRangeDataSetDefinition): CommandResult { - if (definition.dataSets) { - const invalidRanges = - definition.dataSets.find((range) => !rangeReference.test(range.dataRange)) !== undefined; - if (invalidRanges) { - return CommandResult.InvalidDataSet; - } - const zones = definition.dataSets.map((ds) => toUnboundedZone(ds.dataRange)); - if (zones.some((zone) => zone.top !== zone.bottom && isFullRow(zone))) { - return CommandResult.InvalidDataSet; +export function checkChartDataSource(dataSource: ChartDataSource): CommandResult { + switch (dataSource.type) { + case "cells": { + const invalidRanges = + dataSource.dataSets.find((range) => !rangeReference.test(range.dataRange)) !== undefined; + if (invalidRanges) { + return CommandResult.InvalidDataSet; + } + const zones = dataSource.dataSets.map((ds) => toUnboundedZone(ds.dataRange)); + if (zones.some((zone) => zone.top !== zone.bottom && isFullRow(zone))) { + return CommandResult.InvalidDataSet; + } + if (dataSource.labelRange) { + const invalidLabels = !rangeReference.test(dataSource.labelRange || ""); + if (invalidLabels) { + return CommandResult.InvalidLabelRange; + } + } + return CommandResult.Success; } - } - return CommandResult.Success; -} - -export function checkLabelRange(definition: ChartWithRangeDataSetDefinition): CommandResult { - if (definition.labelRange) { - const invalidLabels = !rangeReference.test(definition.labelRange || ""); - if (invalidLabels) { - return CommandResult.InvalidLabelRange; + case "pivot": { + return CommandResult.Success; } } - return CommandResult.Success; } export function shouldRemoveFirstLabel( diff --git a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_factory.ts b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_factory.ts index 77388420e6..474ee6364c 100644 --- a/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_factory.ts +++ b/packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_factory.ts @@ -7,6 +7,7 @@ import { Getters } from "../../../types/getters"; import { RangeAdapter, UID } from "../../../types/misc"; import { Validator } from "../../../types/validator"; import { AbstractChart } from "./abstract_chart"; +import { checkChartDataSource } from "./chart_common"; import { generateMasterChartConfig } from "./runtime/chart_zoom"; /** @@ -66,6 +67,13 @@ export function validateChartDefinition( return validators.validateChartDefinition(validator, definition); } +export function validateChartWithDataSource(alidator: Validator, definition: ChartDefinition) { + if ("dataSource" in definition) { + return checkChartDataSource(definition.dataSource); + } + return CommandResult.Success; +} + /** * Get a new chart definition transformed with the executed command. This * functions will be called during operational transform process diff --git a/packages/o-spreadsheet-engine/src/registries/chart_registry.ts b/packages/o-spreadsheet-engine/src/registries/chart_registry.ts index 5e3ddc70bc..f3a10db970 100644 --- a/packages/o-spreadsheet-engine/src/registries/chart_registry.ts +++ b/packages/o-spreadsheet-engine/src/registries/chart_registry.ts @@ -10,30 +10,30 @@ import { Registry } from "./registry"; /** * Instantiate a chart object based on a definition */ -export interface ChartBuilder { +export interface ChartBuilder { /** * Check if this factory should be used */ - match: (type: ChartType) => boolean; - createChart: (definition: ChartDefinition, sheetId: UID, getters: CoreGetters) => AbstractChart; + match: (type: T["type"]) => boolean; + createChart: (definition: T, sheetId: UID, getters: CoreGetters) => AbstractChart; getChartRuntime: (chart: AbstractChart, getters: Getters) => ChartRuntime; - validateChartDefinition( - validator: Validator, - definition: ChartDefinition - ): CommandResult | CommandResult[]; - transformDefinition( - chartSheetId: UID, - definition: ChartDefinition, - applyRange: RangeAdapter - ): ChartDefinition; - getChartDefinitionFromContextCreation(context: ChartCreationContext): ChartDefinition; + validateChartDefinition(validator: Validator, definition: T): CommandResult | CommandResult[]; + transformDefinition(chartSheetId: UID, definition: T, applyRange: RangeAdapter): T; + getChartDefinitionFromContextCreation(context: ChartCreationContext): T; allowedDefinitionKeys: readonly string[]; sequence: number; dataSeriesLimit?: number; } +interface ChartRegistry extends Registry> { + add( + type: T, + builder: NoInfer>> + ): this; +} + /** * This registry is intended to map a cell content (raw string) to * an instance of a cell. */ -export const chartRegistry = new Registry(); +export const chartRegistry: ChartRegistry = new Registry(); diff --git a/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts index d6ff493399..1e06fa9f07 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/bar_chart.ts @@ -1,14 +1,12 @@ import { ChartConfiguration } from "chart.js"; -import { Color, UID } from "../misc"; -import { ChartDataSource, CommonChartDefinition, DataSetDesign } from "./index"; +import { Color } from "../misc"; +import { CommonChartDefinition } from "./index"; export interface BarChartDefinition extends CommonChartDefinition { readonly type: "bar"; readonly stacked: boolean; readonly horizontal?: boolean; readonly zoomable?: boolean; - readonly datasetsDesign: Record; - readonly dataSource: ChartDataSource; } export type BarChartRuntime = { diff --git a/packages/o-spreadsheet-engine/src/types/chart/chart.ts b/packages/o-spreadsheet-engine/src/types/chart/chart.ts index ba5d4c788d..f3949e85e6 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/chart.ts @@ -3,7 +3,7 @@ import { Align, Color, UID, VerticalAlign } from "../misc"; import { XlsxHexColor } from "../xlsx"; import { BarChartDefinition, BarChartRuntime } from "./bar_chart"; import { ComboChartDefinition, ComboChartRuntime } from "./combo_chart"; -import { LegendPosition } from "./common_chart"; +import { ChartDataSource, LegendPosition } from "./common_chart"; import { FunnelChartColors, FunnelChartDefinition, FunnelChartRuntime } from "./funnel_chart"; import { GaugeChartDefinition, GaugeChartRuntime } from "./gauge_chart"; import { GeoChartDefinition, GeoChartRuntime } from "./geo_chart"; @@ -72,7 +72,7 @@ export interface ChartWithDataSetDefinition { export type ChartWithRangeDataSetDefinition = Extract< ChartDefinition, - { dataSets: RangeChartDataSet[] } + { dataSource: ChartDataSource } >; export type ChartWithAxisDefinition = Extract< @@ -207,6 +207,7 @@ export interface ExcelChartDefinition { export interface ChartCreationContext { readonly range?: RangeChartDataSet[]; + readonly datasetsDesign?: Record; readonly hierarchicalRanges?: RangeChartDataSet[]; readonly title?: TitleDesign; readonly background?: Color; diff --git a/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts index 52839d6d13..5f80f82c38 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/combo_chart.ts @@ -1,12 +1,11 @@ import { ChartConfiguration } from "chart.js"; -import { Color, UID } from "../misc"; +import { Color } from "../misc"; import { DataSetDesign } from "./chart"; -import { ChartDataSource, CommonChartDefinition } from "./common_chart"; +import { CommonChartDefinition } from "./common_chart"; export interface ComboChartDefinition extends CommonChartDefinition { - readonly datasetsDesign: Record; - readonly dataSource: ChartDataSource; readonly type: "combo"; + readonly datasetsDesign: Record; readonly hideDataMarkers?: boolean; readonly zoomable?: boolean; } diff --git a/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts index 6d9742175d..02a9af68d2 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/common_chart.ts @@ -1,10 +1,12 @@ import { Color, UID } from "../misc"; -import { AxesDesign, TitleDesign } from "./chart"; +import { AxesDesign, DataSetDesign, TitleDesign } from "./chart"; export type VerticalAxisPosition = "left" | "right"; export type LegendPosition = "top" | "bottom" | "left" | "right" | "none"; export interface CommonChartDefinition { + readonly datasetsDesign: Record; + readonly dataSource: ChartDataSource; readonly title: TitleDesign; readonly background?: Color; readonly legendPosition: LegendPosition; diff --git a/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts index eaadbce5cf..ec291a55e8 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/funnel_chart.ts @@ -1,22 +1,12 @@ import { ChartConfiguration } from "chart.js"; -import { Color, UID } from "../misc"; -import { AxesDesign, DataSetDesign, TitleDesign } from "./chart"; -import { ChartDataSource, LegendPosition } from "./common_chart"; +import { Color } from "../misc"; +import { CommonChartDefinition } from "./common_chart"; -export interface FunnelChartDefinition { +export interface FunnelChartDefinition extends CommonChartDefinition { readonly type: "funnel"; - readonly datasetsDesign: Record; - readonly dataSource: ChartDataSource; - readonly title: TitleDesign; - readonly background?: Color; - readonly legendPosition: LegendPosition; readonly horizontal?: boolean; - readonly axesDesign?: AxesDesign; - readonly aggregated?: boolean; - readonly showValues?: boolean; readonly funnelColors?: FunnelChartColors; readonly cumulative?: boolean; - readonly humanize?: boolean; } export type FunnelChartRuntime = { diff --git a/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts index 2d9224d01d..6e056932af 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/line_chart.ts @@ -1,12 +1,9 @@ import type { ChartConfiguration } from "chart.js"; -import { Color, UID } from "../misc"; -import { DataSetDesign } from "./chart"; -import { ChartDataSource, CommonChartDefinition } from "./common_chart"; +import { Color } from "../misc"; +import { CommonChartDefinition } from "./common_chart"; export interface LineChartDefinition extends CommonChartDefinition { readonly type: "line"; - readonly datasetsDesign: Record; - readonly dataSource: ChartDataSource; readonly labelsAsText: boolean; readonly stacked: boolean; readonly aggregated?: boolean; diff --git a/packages/o-spreadsheet-engine/src/types/chart/sunburst_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/sunburst_chart.ts index 6f1a67ec57..50bc22ba20 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/sunburst_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/sunburst_chart.ts @@ -1,13 +1,12 @@ import type { ChartConfiguration, ChartDataset } from "chart.js"; -import { Color } from "../misc"; -import { ChartStyle, RangeChartDataSet, TitleDesign } from "./chart"; -import { LegendPosition } from "./common_chart"; +import { Color, UID } from "../misc"; +import { ChartStyle, DataSetDesign, TitleDesign } from "./chart"; +import { ChartDataSource, LegendPosition } from "./common_chart"; export interface SunburstChartDefinition { readonly type: "sunburst"; - readonly dataSets: RangeChartDataSet[]; - readonly dataSetsHaveTitle: boolean; - readonly labelRange?: string; + readonly datasetsDesign: Record; + readonly dataSource: ChartDataSource; readonly title: TitleDesign; readonly background?: Color; readonly legendPosition: LegendPosition; diff --git a/packages/o-spreadsheet-engine/src/types/chart/tree_map_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/tree_map_chart.ts index 911bdd0edd..83317caaec 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/tree_map_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/tree_map_chart.ts @@ -1,14 +1,13 @@ import { ChartConfiguration } from "chart.js"; -import { Color } from "../misc"; -import { RangeChartDataSet, TitleDesign } from "./chart"; +import { Color, UID } from "../misc"; +import { DataSetDesign, TitleDesign } from "./chart"; import { TreemapDataPoint } from "./chartjs_tree_map_type"; -import { LegendPosition } from "./common_chart"; +import { ChartDataSource, LegendPosition } from "./common_chart"; export interface TreeMapChartDefinition { readonly type: "treemap"; - readonly dataSets: RangeChartDataSet[]; - readonly dataSetsHaveTitle: boolean; - readonly labelRange?: string; + readonly datasetsDesign: Record; + readonly dataSource: ChartDataSource; readonly title: TitleDesign; readonly background?: Color; readonly legendPosition: LegendPosition; diff --git a/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts b/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts index 8c9c822240..bbafe0b16d 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/waterfall_chart.ts @@ -1,6 +1,6 @@ import type { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; -import { VerticalAxisPosition } from "./common_chart"; +import { CommonChartDefinition, VerticalAxisPosition } from "./common_chart"; export interface WaterfallChartDefinition extends CommonChartDefinition { readonly type: "waterfall"; diff --git a/src/helpers/figures/charts/bar_chart.ts b/src/helpers/figures/charts/bar_chart.ts index 7bfe203c99..24faf5bfeb 100644 --- a/src/helpers/figures/charts/bar_chart.ts +++ b/src/helpers/figures/charts/bar_chart.ts @@ -1,16 +1,13 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { chartFontColor, - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, getDefinedAxis, shouldRemoveFirstLabel, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -25,9 +22,8 @@ import { ExcelChartDefinition, RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; -import { CommandResult } from "@odoo/o-spreadsheet-engine/types/commands"; import { Getters } from "@odoo/o-spreadsheet-engine/types/getters"; -import { ApplyRangeChange, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine/types/misc"; +import { ApplyRangeChange, UID } from "@odoo/o-spreadsheet-engine/types/misc"; import { Range } from "@odoo/o-spreadsheet-engine/types/range"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import type { ChartConfiguration } from "chart.js"; @@ -50,9 +46,8 @@ export class BarChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof BarChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "horizontal", "axesDesign", "stacked", @@ -72,21 +67,6 @@ export class BarChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: BarChartDefinition, - applyChange: RangeAdapter - ): BarChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: BarChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): BarChartDefinition { return { background: context.background, diff --git a/src/helpers/figures/charts/combo_chart.ts b/src/helpers/figures/charts/combo_chart.ts index 236599efc8..606e3bfeec 100644 --- a/src/helpers/figures/charts/combo_chart.ts +++ b/src/helpers/figures/charts/combo_chart.ts @@ -1,23 +1,18 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { chartFontColor, - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, getDefinedAxis, shouldRemoveFirstLabel, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; -import { - RangeChartDataSet, -} from "@odoo/o-spreadsheet-engine/types/chart"; +import { RangeChartDataSet } from "@odoo/o-spreadsheet-engine/types/chart"; import { ComboChartDataSet, ComboChartDefinition, @@ -28,12 +23,10 @@ import { ChartConfiguration } from "chart.js"; import { ApplyRangeChange, ChartCreationContext, - CommandResult, DataSet, ExcelChartDefinition, Getters, Range, - RangeAdapter, UID, } from "../../../types"; import { @@ -55,9 +48,8 @@ export class ComboChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof ComboChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "aggregated", "axesDesign", "showValues", @@ -76,21 +68,6 @@ export class ComboChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: ComboChartDefinition, - applyChange: RangeAdapter - ): ComboChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: ComboChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - getContextCreation(): ChartCreationContext { const range: RangeChartDataSet[] = []; for (const [i, dataSet] of this.dataSets.entries()) { diff --git a/src/helpers/figures/charts/funnel_chart.ts b/src/helpers/figures/charts/funnel_chart.ts index cf8f1a18f4..d0d03f6885 100644 --- a/src/helpers/figures/charts/funnel_chart.ts +++ b/src/helpers/figures/charts/funnel_chart.ts @@ -1,13 +1,10 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -20,7 +17,7 @@ import { RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -38,9 +35,8 @@ export class FunnelChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof FunnelChartDefinition)[] = [ ...AbstractChart.commonKeys, - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "axesDesign", "legendPosition", "horizontal", @@ -61,21 +57,6 @@ export class FunnelChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: FunnelChartDefinition, - applyChange: RangeAdapter - ): FunnelChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: FunnelChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): FunnelChartDefinition { return { background: context.background, diff --git a/src/helpers/figures/charts/geo_chart.ts b/src/helpers/figures/charts/geo_chart.ts index bc71dec2d0..5c4a6bd117 100644 --- a/src/helpers/figures/charts/geo_chart.ts +++ b/src/helpers/figures/charts/geo_chart.ts @@ -1,13 +1,10 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -23,7 +20,7 @@ import { GeoChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/geo_chart"; import { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getChartTitle, getGeoChartData, @@ -41,9 +38,8 @@ export class GeoChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof GeoChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "colorScale", "missingValueColor", "region", @@ -60,21 +56,6 @@ export class GeoChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: GeoChartDefinition, - applyChange: RangeAdapter - ): GeoChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: GeoChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): GeoChartDefinition { return { background: context.background, diff --git a/src/helpers/figures/charts/line_chart.ts b/src/helpers/figures/charts/line_chart.ts index 31141ddda3..9988fc4e4f 100644 --- a/src/helpers/figures/charts/line_chart.ts +++ b/src/helpers/figures/charts/line_chart.ts @@ -1,16 +1,13 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { chartFontColor, - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, getDefinedAxis, shouldRemoveFirstLabel, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -25,7 +22,7 @@ import { import { LineChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart/line_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -45,9 +42,8 @@ export class LineChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof LineChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "labelsAsText", "stacked", "aggregated", @@ -70,21 +66,6 @@ export class LineChart extends AbstractChart { this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange); } - static validateChartDefinition( - validator: Validator, - definition: LineChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - - static transformDefinition( - chartSheetId: UID, - definition: LineChartDefinition, - applyChange: RangeAdapter - ): LineChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): LineChartDefinition { return { background: context.background, diff --git a/src/helpers/figures/charts/pie_chart.ts b/src/helpers/figures/charts/pie_chart.ts index 8e01d37e9d..4e1f592120 100644 --- a/src/helpers/figures/charts/pie_chart.ts +++ b/src/helpers/figures/charts/pie_chart.ts @@ -1,15 +1,12 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { chartFontColor, - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, shouldRemoveFirstLabel, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -25,7 +22,7 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart/pie_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import type { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -44,9 +41,8 @@ export class PieChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof PieChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "aggregated", "isDoughnut", "pieHolePercentage", @@ -64,21 +60,6 @@ export class PieChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: PieChartDefinition, - applyChange: RangeAdapter - ): PieChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: PieChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): PieChartDefinition { return { background: context.background, diff --git a/src/helpers/figures/charts/pyramid_chart.ts b/src/helpers/figures/charts/pyramid_chart.ts index facb008b86..f8e8dddbd2 100644 --- a/src/helpers/figures/charts/pyramid_chart.ts +++ b/src/helpers/figures/charts/pyramid_chart.ts @@ -1,16 +1,13 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { chartFontColor, - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, getDefinedAxis, shouldRemoveFirstLabel, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -27,7 +24,7 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart/pyramid_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getBarChartDatasets, getBarChartLegend, @@ -47,9 +44,8 @@ export class PyramidChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof PyramidChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "showValues", "aggregated", "axesDesign", @@ -69,21 +65,6 @@ export class PyramidChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: PyramidChartDefinition, - applyChange: RangeAdapter - ): PyramidChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: PyramidChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): PyramidChartDefinition { return { background: context.background, diff --git a/src/helpers/figures/charts/radar_chart.ts b/src/helpers/figures/charts/radar_chart.ts index e9711964b5..a26a5dd6d7 100644 --- a/src/helpers/figures/charts/radar_chart.ts +++ b/src/helpers/figures/charts/radar_chart.ts @@ -1,15 +1,12 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { chartFontColor, - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, shouldRemoveFirstLabel, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -26,7 +23,7 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart/radar_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -46,9 +43,8 @@ export class RadarChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof RadarChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "showValues", "aggregated", "stacked", @@ -67,21 +63,6 @@ export class RadarChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: RadarChartDefinition, - applyChange: RangeAdapter - ): RadarChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: RadarChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): RadarChartDefinition { return { background: context.background, diff --git a/src/helpers/figures/charts/scatter_chart.ts b/src/helpers/figures/charts/scatter_chart.ts index 897c3aa0b9..2d48d10c8c 100644 --- a/src/helpers/figures/charts/scatter_chart.ts +++ b/src/helpers/figures/charts/scatter_chart.ts @@ -1,10 +1,8 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { chartFontColor, - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, @@ -12,7 +10,6 @@ import { shouldRemoveFirstLabel, toExcelDataset, toExcelLabelRange, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -30,7 +27,7 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart/scatter_chart"; import { toXlsxHexColor } from "@odoo/o-spreadsheet-engine/xlsx/helpers/colors"; import { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getChartShowValues, getChartTitle, @@ -50,9 +47,8 @@ export class ScatterChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof ScatterChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "showValues", "labelsAsText", "aggregated", @@ -71,21 +67,6 @@ export class ScatterChart extends AbstractChart { this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange); } - static validateChartDefinition( - validator: Validator, - definition: ScatterChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - - static transformDefinition( - chartSheetId: UID, - definition: ScatterChartDefinition, - applyChange: RangeAdapter - ): ScatterChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): ScatterChartDefinition { return { background: context.background, diff --git a/src/helpers/figures/charts/sunburst_chart.ts b/src/helpers/figures/charts/sunburst_chart.ts index 2ce0cb80fd..60ee29733e 100644 --- a/src/helpers/figures/charts/sunburst_chart.ts +++ b/src/helpers/figures/charts/sunburst_chart.ts @@ -1,13 +1,10 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -23,7 +20,7 @@ import { RangeChartDataSet, } from "@odoo/o-spreadsheet-engine/types/chart/chart"; import type { ChartConfiguration, ChartOptions } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getChartTitle, getHierarchalChartData, @@ -42,9 +39,8 @@ export class SunburstChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof SunburstChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "showValues", "showLabels", "valuesDesign", @@ -63,21 +59,6 @@ export class SunburstChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: SunburstChartDefinition, - applyChange: RangeAdapter - ): SunburstChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: SunburstChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): SunburstChartDefinition { const dataSets: RangeChartDataSet[] = []; if (context.hierarchicalRanges?.length) { diff --git a/src/helpers/figures/charts/tree_map_chart.ts b/src/helpers/figures/charts/tree_map_chart.ts index 1d1e58d8bc..1861c47104 100644 --- a/src/helpers/figures/charts/tree_map_chart.ts +++ b/src/helpers/figures/charts/tree_map_chart.ts @@ -1,13 +1,10 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -23,7 +20,7 @@ import { TreeMapChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/tree_map_chart"; import { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getChartTitle, getHierarchalChartData, @@ -47,9 +44,8 @@ export class TreeMapChart extends AbstractChart { static allowedDefinitionKeys: readonly (keyof TreeMapChartDefinition)[] = [ ...AbstractChart.commonKeys, "legendPosition", - "dataSets", - "dataSetsHaveTitle", - "labelRange", + "datasetsDesign", + "dataSource", "showHeaders", "headerDesign", "showLabels", @@ -69,21 +65,6 @@ export class TreeMapChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: TreeMapChartDefinition, - applyChange: RangeAdapter - ): TreeMapChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: TreeMapChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): TreeMapChartDefinition { const dataSets: RangeChartDataSet[] = []; if (context.hierarchicalRanges?.length) { diff --git a/src/helpers/figures/charts/waterfall_chart.ts b/src/helpers/figures/charts/waterfall_chart.ts index 2a5ec41e37..d44eb6933e 100644 --- a/src/helpers/figures/charts/waterfall_chart.ts +++ b/src/helpers/figures/charts/waterfall_chart.ts @@ -1,13 +1,10 @@ -import { CoreGetters, Validator } from "@odoo/o-spreadsheet-engine"; +import { CoreGetters } from "@odoo/o-spreadsheet-engine"; import { BACKGROUND_CHART_COLOR } from "@odoo/o-spreadsheet-engine/constants"; import { AbstractChart } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/abstract_chart"; import { - checkDataset, - checkLabelRange, createDataSets, duplicateDataSetsInDuplicatedSheet, duplicateLabelRangeInDuplicatedSheet, - transformChartDefinitionWithDataSetsWithZone, updateChartRangesWithDataSets, } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { CHART_COMMON_OPTIONS } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_ui_common"; @@ -23,7 +20,7 @@ import { WaterfallChartRuntime, } from "@odoo/o-spreadsheet-engine/types/chart/waterfall_chart"; import type { ChartConfiguration } from "chart.js"; -import { ApplyRangeChange, CommandResult, Getters, Range, RangeAdapter, UID } from "../../../types"; +import { ApplyRangeChange, Getters, Range, UID } from "../../../types"; import { getBarChartData, getChartTitle, @@ -70,21 +67,6 @@ export class WaterfallChart extends AbstractChart { this.labelRange = createValidRange(getters, sheetId, definition.labelRange); } - static transformDefinition( - chartSheetId: UID, - definition: WaterfallChartDefinition, - applyChange: RangeAdapter - ): WaterfallChartDefinition { - return transformChartDefinitionWithDataSetsWithZone(chartSheetId, definition, applyChange); - } - - static validateChartDefinition( - validator: Validator, - definition: WaterfallChartDefinition - ): CommandResult | CommandResult[] { - return validator.checkValidations(definition, checkDataset, checkLabelRange); - } - static getDefinitionFromContextCreation(context: ChartCreationContext): WaterfallChartDefinition { return { background: context.background, diff --git a/src/registries/chart_types.ts b/src/registries/chart_types.ts index 26f1a0feaf..50eb3d59b5 100644 --- a/src/registries/chart_types.ts +++ b/src/registries/chart_types.ts @@ -29,6 +29,8 @@ import { LineChart, PieChart, ScorecardChart, + transformChartDefinitionWithDataSetsWithZone, + validateChartWithDataSource, WaterfallChart, } from "../helpers/figures/charts"; import { ComboChart, createComboChartRuntime } from "../helpers/figures/charts/combo_chart"; @@ -52,8 +54,8 @@ chartRegistry.add("bar", { createChart: (definition, sheetId, getters) => new BarChart(definition as BarChartDefinition, sheetId, getters), getChartRuntime: createBarChartRuntime, - validateChartDefinition: BarChart.validateChartDefinition, - transformDefinition: BarChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: BarChart.getDefinitionFromContextCreation, allowedDefinitionKeys: BarChart.allowedDefinitionKeys, sequence: 10, @@ -63,8 +65,8 @@ chartRegistry.add("combo", { createChart: (definition, sheetId, getters) => new ComboChart(definition as ComboChartDefinition, sheetId, getters), getChartRuntime: createComboChartRuntime, - validateChartDefinition: ComboChart.validateChartDefinition, - transformDefinition: ComboChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: ComboChart.getDefinitionFromContextCreation, allowedDefinitionKeys: ComboChart.allowedDefinitionKeys, sequence: 15, @@ -74,8 +76,8 @@ chartRegistry.add("line", { createChart: (definition, sheetId, getters) => new LineChart(definition as LineChartDefinition, sheetId, getters), getChartRuntime: createLineChartRuntime, - validateChartDefinition: LineChart.validateChartDefinition, - transformDefinition: LineChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: LineChart.getDefinitionFromContextCreation, allowedDefinitionKeys: LineChart.allowedDefinitionKeys, sequence: 20, @@ -85,8 +87,8 @@ chartRegistry.add("pie", { createChart: (definition, sheetId, getters) => new PieChart(definition as PieChartDefinition, sheetId, getters), getChartRuntime: createPieChartRuntime, - validateChartDefinition: PieChart.validateChartDefinition, - transformDefinition: PieChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: PieChart.getDefinitionFromContextCreation, allowedDefinitionKeys: PieChart.allowedDefinitionKeys, sequence: 30, @@ -118,8 +120,8 @@ chartRegistry.add("scatter", { createChart: (definition, sheetId, getters) => new ScatterChart(definition as ScatterChartDefinition, sheetId, getters), getChartRuntime: createScatterChartRuntime, - validateChartDefinition: ScatterChart.validateChartDefinition, - transformDefinition: ScatterChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: ScatterChart.getDefinitionFromContextCreation, allowedDefinitionKeys: ScatterChart.allowedDefinitionKeys, sequence: 60, @@ -129,8 +131,8 @@ chartRegistry.add("waterfall", { createChart: (definition, sheetId, getters) => new WaterfallChart(definition as WaterfallChartDefinition, sheetId, getters), getChartRuntime: createWaterfallChartRuntime, - validateChartDefinition: WaterfallChart.validateChartDefinition, - transformDefinition: WaterfallChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: WaterfallChart.getDefinitionFromContextCreation, allowedDefinitionKeys: WaterfallChart.allowedDefinitionKeys, sequence: 70, @@ -140,8 +142,8 @@ chartRegistry.add("pyramid", { createChart: (definition, sheetId, getters) => new PyramidChart(definition as PyramidChartDefinition, sheetId, getters), getChartRuntime: createPyramidChartRuntime, - validateChartDefinition: PyramidChart.validateChartDefinition, - transformDefinition: PyramidChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: PyramidChart.getDefinitionFromContextCreation, allowedDefinitionKeys: PyramidChart.allowedDefinitionKeys, sequence: 80, @@ -152,8 +154,8 @@ chartRegistry.add("radar", { createChart: (definition, sheetId, getters) => new RadarChart(definition as RadarChartDefinition, sheetId, getters), getChartRuntime: createRadarChartRuntime, - validateChartDefinition: RadarChart.validateChartDefinition, - transformDefinition: RadarChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: RadarChart.getDefinitionFromContextCreation, allowedDefinitionKeys: RadarChart.allowedDefinitionKeys, sequence: 80, @@ -163,8 +165,8 @@ chartRegistry.add("geo", { createChart: (definition, sheetId, getters) => new GeoChart(definition as GeoChartDefinition, sheetId, getters), getChartRuntime: createGeoChartRuntime, - validateChartDefinition: GeoChart.validateChartDefinition, - transformDefinition: GeoChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: GeoChart.getDefinitionFromContextCreation, allowedDefinitionKeys: GeoChart.allowedDefinitionKeys, sequence: 90, @@ -175,8 +177,8 @@ chartRegistry.add("funnel", { createChart: (definition, sheetId, getters) => new FunnelChart(definition as FunnelChartDefinition, sheetId, getters), getChartRuntime: createFunnelChartRuntime, - validateChartDefinition: FunnelChart.validateChartDefinition, - transformDefinition: FunnelChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: FunnelChart.getDefinitionFromContextCreation, allowedDefinitionKeys: FunnelChart.allowedDefinitionKeys, sequence: 100, @@ -187,8 +189,8 @@ chartRegistry.add("sunburst", { createChart: (definition, sheetId, getters) => new SunburstChart(definition as SunburstChartDefinition, sheetId, getters), getChartRuntime: createSunburstChartRuntime, - validateChartDefinition: SunburstChart.validateChartDefinition, - transformDefinition: SunburstChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: SunburstChart.getDefinitionFromContextCreation, allowedDefinitionKeys: SunburstChart.allowedDefinitionKeys, sequence: 30, @@ -198,8 +200,8 @@ chartRegistry.add("treemap", { createChart: (definition, sheetId, getters) => new TreeMapChart(definition as TreeMapChartDefinition, sheetId, getters), getChartRuntime: createTreeMapChartRuntime, - validateChartDefinition: TreeMapChart.validateChartDefinition, - transformDefinition: TreeMapChart.transformDefinition, + validateChartDefinition: validateChartWithDataSource, + transformDefinition: transformChartDefinitionWithDataSetsWithZone, getChartDefinitionFromContextCreation: TreeMapChart.getDefinitionFromContextCreation, allowedDefinitionKeys: TreeMapChart.allowedDefinitionKeys, sequence: 100, From 2cd4c96dceba3a66a0bb50cea7445672e5d5f212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Thu, 20 Nov 2025 11:35:35 +0100 Subject: [PATCH 9/9] m --- .../src/registries/chart_registry.ts | 9 +++- .../src/types/chart/chart.ts | 7 ++- .../charts/runtime/chart_data_extractor.ts | 47 +++++++++++++++---- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/packages/o-spreadsheet-engine/src/registries/chart_registry.ts b/packages/o-spreadsheet-engine/src/registries/chart_registry.ts index f3a10db970..5f1ab1a126 100644 --- a/packages/o-spreadsheet-engine/src/registries/chart_registry.ts +++ b/packages/o-spreadsheet-engine/src/registries/chart_registry.ts @@ -1,5 +1,11 @@ import { AbstractChart } from "../helpers/figures/charts/abstract_chart"; -import { ChartCreationContext, ChartDefinition, ChartRuntime, ChartType } from "../types/chart"; +import { + ChartCreationContext, + ChartData, + ChartDefinition, + ChartRuntime, + ChartType, +} from "../types/chart"; import { CommandResult } from "../types/commands"; import { CoreGetters } from "../types/core_getters"; import { Getters } from "../types/getters"; @@ -15,6 +21,7 @@ export interface ChartBuilder { * Check if this factory should be used */ match: (type: T["type"]) => boolean; + extractData: (definition: T, sheetId: UID, getters: CoreGetters) => ChartData; createChart: (definition: T, sheetId: UID, getters: CoreGetters) => AbstractChart; getChartRuntime: (chart: AbstractChart, getters: Getters) => ChartRuntime; validateChartDefinition(validator: Validator, definition: T): CommandResult | CommandResult[]; diff --git a/packages/o-spreadsheet-engine/src/types/chart/chart.ts b/packages/o-spreadsheet-engine/src/types/chart/chart.ts index f3949e85e6..29275f36ef 100644 --- a/packages/o-spreadsheet-engine/src/types/chart/chart.ts +++ b/packages/o-spreadsheet-engine/src/types/chart/chart.ts @@ -21,6 +21,7 @@ import { } from "./tree_map_chart"; import { WaterfallChartDefinition, WaterfallChartRuntime } from "./waterfall_chart"; +import { EvaluatedCell } from "../cells"; import { Format } from "../format"; import { Locale } from "../locale"; import { Range } from "../range"; @@ -105,7 +106,7 @@ export interface LabelValues { export interface DatasetValues { readonly label?: string; - readonly data: any[]; + readonly data: EvaluatedCell[]; readonly hidden?: boolean; } @@ -241,10 +242,12 @@ export interface ChartCreationContext { export type ChartAxisFormats = { [axisId: string]: Format | undefined } | undefined; -export interface ChartRuntimeGenerationArgs { +export interface ChartData { dataSetsValues: DatasetValues[]; axisFormats: ChartAxisFormats; labels: string[]; +} +export interface ChartRuntimeGenerationArgs extends ChartData { locale: Locale; trendDataSetsValues?: (Point[] | undefined)[]; axisType?: AxisType; diff --git a/src/helpers/figures/charts/runtime/chart_data_extractor.ts b/src/helpers/figures/charts/runtime/chart_data_extractor.ts index c9576f31c4..f13bca3bc3 100644 --- a/src/helpers/figures/charts/runtime/chart_data_extractor.ts +++ b/src/helpers/figures/charts/runtime/chart_data_extractor.ts @@ -8,15 +8,21 @@ import { predictLinearValues, } from "@odoo/o-spreadsheet-engine/functions/helper_statistical"; import { isEvaluationError, toNumber } from "@odoo/o-spreadsheet-engine/functions/helpers"; -import { shouldRemoveFirstLabel } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; +import { + createDataSets, + shouldRemoveFirstLabel, +} from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common"; import { isDateTimeFormat } from "@odoo/o-spreadsheet-engine/helpers/format/format"; import { deepCopy, findNextDefinedValue, range } from "@odoo/o-spreadsheet-engine/helpers/misc"; import { isNumber } from "@odoo/o-spreadsheet-engine/helpers/numbers"; +import { createValidRange } from "@odoo/o-spreadsheet-engine/helpers/range"; import { recomputeZones } from "@odoo/o-spreadsheet-engine/helpers/recompute_zones"; import { positions } from "@odoo/o-spreadsheet-engine/helpers/zones"; import { AxisType, BarChartDefinition, + ChartData, + ChartDataSource, ChartRuntimeGenerationArgs, DataSet, DatasetValues, @@ -34,27 +40,50 @@ import { } from "@odoo/o-spreadsheet-engine/types/chart/geo_chart"; import { RadarChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart/radar_chart"; import { TreeMapChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart/tree_map_chart"; -import { Point } from "chart.js"; import { CellValue, DEFAULT_LOCALE, + EvaluatedCell, Format, GenericDefinition, Getters, Locale, Range, + UID, } from "../../../../types"; import { timeFormatLuxonCompatible } from "../../../chart_date"; +function extractChartData(dataSource: ChartDataSource, sheetId: UID, getters: Getters): ChartData { + switch (dataSource.type) { + case "cells": { + const dataSets = createDataSets( + getters, + dataSource.dataSets, + sheetId, + dataSource.dataSetsHaveTitle + ); + const labelRange = createValidRange(getters, sheetId, dataSource.labelRange); + const labelValues = getChartLabelValues(getters, dataSets, labelRange); + const labels = labelValues.formattedValues; + const dataSetsValues = getChartDatasetValues(getters, dataSets); + return { + dataSetsValues, + axisFormats, + labels, + }; + } + case "pivot": { + throw new Error("Not implemented yet"); + } + } +} + export function getBarChartData( definition: GenericDefinition, dataSets: DataSet[], labelRange: Range | undefined, getters: Getters ): ChartRuntimeGenerationArgs { - const labelValues = getChartLabelValues(getters, dataSets, labelRange); - let labels = labelValues.formattedValues; - let dataSetsValues = getChartDatasetValues(getters, dataSets); if (shouldRemoveFirstLabel(labelRange, dataSets[0], definition.dataSetsHaveTitle || false)) { labels.shift(); } @@ -661,15 +690,17 @@ function fixEmptyLabelsForDateCharts( /** * Get the data from a dataSet */ -export function getData(getters: Getters, ds: DataSet): (CellValue | undefined)[] { +export function getData(getters: Getters, ds: DataSet): (EvaluatedCell | undefined)[] { if (ds.dataRange) { const labelCellZone = ds.labelCell ? [ds.labelCell.zone] : []; const dataZone = recomputeZones([ds.dataRange.zone], labelCellZone)[0]; if (dataZone === undefined) { return []; } - const dataRange = getters.getRangeFromZone(ds.dataRange.sheetId, dataZone); - return getters.getRangeValues(dataRange).map((value) => (value === "" ? undefined : value)); + const { sheetId, zone } = getters.getRangeFromZone(ds.dataRange.sheetId, dataZone); + return getters + .getEvaluatedCellsInZone(sheetId, zone) + .map((cell) => (cell.value === "" ? undefined : cell)); } return []; }