diff --git a/src/components/side_panel/chart/chart_with_axis/design_panel.ts b/src/components/side_panel/chart/chart_with_axis/design_panel.ts index b6b24053a3..0108a87533 100644 --- a/src/components/side_panel/chart/chart_with_axis/design_panel.ts +++ b/src/components/side_panel/chart/chart_with_axis/design_panel.ts @@ -29,7 +29,10 @@ interface Props { updateChart: (figureId: UID, definition: Partial) => DispatchResult; } -export class ChartWithAxisDesignPanel extends Component { +export class ChartWithAxisDesignPanel

extends Component< + P, + SpreadsheetChildEnv +> { static template = "o-spreadsheet-ChartWithAxisDesignPanel"; static components = { GeneralDesignEditor, @@ -49,7 +52,7 @@ export class ChartWithAxisDesignPanel extends Component) => DispatchResult; + updateChart: (figureId: UID, definition: Partial) => DispatchResult; +} + +export class ComboChartDesignPanel extends ChartWithAxisDesignPanel { + static template = "o-spreadsheet-ComboChartDesignPanel"; + seriesTypeChoices = [ + { value: "bar", label: _t("Bar") }, + { value: "line", label: _t("Line") }, + ]; + + updateDataSeriesType(type: "bar" | "line") { + const dataSets = [...this.props.definition.dataSets]; + if (!dataSets?.[this.state.index]) { + return; + } + dataSets[this.state.index] = { + ...dataSets[this.state.index], + type, + }; + this.props.updateChart(this.props.figureId, { dataSets }); + } + + getDataSeriesType() { + const dataSets = this.props.definition.dataSets; + if (!dataSets?.[this.state.index]) { + return "bar"; + } + return dataSets[this.state.index].type ?? "line"; + } +} diff --git a/src/components/side_panel/chart/combo_chart/combo_chart_design_panel.xml b/src/components/side_panel/chart/combo_chart/combo_chart_design_panel.xml new file mode 100644 index 0000000000..c41ab4adb4 --- /dev/null +++ b/src/components/side_panel/chart/combo_chart/combo_chart_design_panel.xml @@ -0,0 +1,147 @@ + + + + +

+ Legend position + +
+
+ Values + +
+ + + + Data series + +
+ +
+
+ Series color + +
+
+
+ Vertical axis + +
+
+ Serie type + +
+
+ Series name + +
+
+ Trend line + Show trend line + + + +
+
+
+ Type + +
+
+ Degree + +
+
+
+ Trend line color + +
+
+
+
+
+
+ + Axes + + + + + + diff --git a/src/components/side_panel/chart/index.ts b/src/components/side_panel/chart/index.ts index bfe1bf829c..4c29b031d8 100644 --- a/src/components/side_panel/chart/index.ts +++ b/src/components/side_panel/chart/index.ts @@ -3,6 +3,7 @@ import { Registry } from "../../../registries/registry"; import { BarConfigPanel } from "./bar_chart/bar_chart_config_panel"; import { GenericChartConfigPanel } from "./building_blocks/generic_side_panel/config_panel"; import { ChartWithAxisDesignPanel } from "./chart_with_axis/design_panel"; +import { ComboChartDesignPanel } from "./combo_chart/combo_chart_design_panel"; import { GaugeChartConfigPanel } from "./gauge_chart_panel/gauge_chart_config_panel"; import { GaugeChartDesignPanel } from "./gauge_chart_panel/gauge_chart_design_panel"; import { LineConfigPanel } from "./line_chart/line_chart_config_panel"; @@ -43,7 +44,7 @@ chartSidePanelComponentRegistry }) .add("combo", { configuration: GenericChartConfigPanel, - design: ChartWithAxisDesignPanel, + design: ComboChartDesignPanel, }) .add("pie", { configuration: GenericChartConfigPanel, diff --git a/src/helpers/figures/charts/combo_chart.ts b/src/helpers/figures/charts/combo_chart.ts index 6c271114d5..2034bb6c40 100644 --- a/src/helpers/figures/charts/combo_chart.ts +++ b/src/helpers/figures/charts/combo_chart.ts @@ -18,11 +18,14 @@ import { import { AxesDesign, CustomizedDataSet, - DatasetDesign, ExcelChartDataset, LegendPosition, } from "../../../types/chart"; -import { ComboChartDefinition, ComboChartRuntime } from "../../../types/chart/combo_chart"; +import { + ComboChartDataSet, + ComboChartDefinition, + ComboChartRuntime, +} from "../../../types/chart/combo_chart"; import { CellErrorType } from "../../../types/errors"; import { Validator } from "../../../types/validator"; import { toXlsxHexColor } from "../../../xlsx/helpers/colors"; @@ -64,7 +67,7 @@ export class ComboChart extends AbstractChart { readonly legendPosition: LegendPosition; readonly aggregated?: boolean; readonly dataSetsHaveTitle: boolean; - readonly dataSetDesign?: DatasetDesign[]; + readonly dataSetDesign?: ComboChartDataSet[]; readonly axesDesign?: AxesDesign; readonly type = "combo"; readonly showValues?: boolean; @@ -127,11 +130,12 @@ export class ComboChart extends AbstractChart { labelRange: Range | undefined, targetSheetId?: UID ): ComboChartDefinition { - const ranges: CustomizedDataSet[] = []; + const ranges: ComboChartDataSet[] = []; for (const [i, dataSet] of dataSets.entries()) { ranges.push({ ...this.dataSetDesign?.[i], dataRange: this.getters.getRangeString(dataSet.dataRange, targetSheetId || this.sheetId), + type: this.dataSetDesign?.[i]?.type ?? (i ? "line" : "bar"), }); } return { @@ -189,9 +193,13 @@ export class ComboChart extends AbstractChart { } static getDefinitionFromContextCreation(context: ChartCreationContext): ComboChartDefinition { + const dataSets: ComboChartDataSet[] = (context.range ?? []).map((ds, index) => ({ + ...ds, + type: index ? "line" : "bar", + })); return { background: context.background, - dataSets: context.range ?? [], + dataSets, dataSetsHaveTitle: context.dataSetsHaveTitle ?? false, aggregated: context.aggregated, legendPosition: context.legendPosition ?? "top", @@ -249,7 +257,6 @@ export function createComboChartRuntime(chart: ComboChart, getters: Getters): Co const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat); const legend: DeepPartial> = { labels: { color: fontColor }, - reverse: true, }; if (chart.legendPosition === "none") { legend.display = false; @@ -320,14 +327,15 @@ export function createComboChartRuntime(chart: ComboChart, getters: Getters): Co for (let [index, { label, data }] of dataSetsValues.entries()) { const design = definition.dataSets[index]; const color = colors.next(); + const type = design?.type ?? "line"; const dataset: ChartDataset<"bar" | "line", number[]> = { label: design?.label ?? label, data, borderColor: color, backgroundColor: color, yAxisID: design?.yAxisId ?? "y", - type: index === 0 ? "bar" : "line", - order: -index, + type, + order: type === "bar" ? dataSetsValues.length + index : index, }; config.data.datasets.push(dataset); diff --git a/src/types/chart/combo_chart.ts b/src/types/chart/combo_chart.ts index 815b633b4c..14f67ed156 100644 --- a/src/types/chart/combo_chart.ts +++ b/src/types/chart/combo_chart.ts @@ -1,11 +1,15 @@ import { ChartConfiguration } from "chart.js"; import { Color } from "../misc"; +import { CustomizedDataSet } from "./chart"; import { ComboBarChartDefinition } from "./common_bar_combo"; export interface ComboChartDefinition extends ComboBarChartDefinition { + readonly dataSets: ComboChartDataSet[]; readonly type: "combo"; } +export type ComboChartDataSet = CustomizedDataSet & { type?: "bar" | "line" }; + export type ComboChartRuntime = { chartJsConfig: ChartConfiguration; background: Color; diff --git a/tests/figures/chart/chart_plugin.test.ts b/tests/figures/chart/chart_plugin.test.ts index 4cb61953be..8207e2c350 100644 --- a/tests/figures/chart/chart_plugin.test.ts +++ b/tests/figures/chart/chart_plugin.test.ts @@ -1635,7 +1635,7 @@ describe("Chart without labels", () => { expect(getChartConfiguration(model, "44").data?.labels).toEqual(["B1", "B2"]); }); - test("Combo chart has both line and bar", () => { + test("Combo chart has bar if the type is set to bar and line else", () => { setCellContent(model, "A1", "1"); setCellContent(model, "A2", "2"); setCellContent(model, "A3", "3"); @@ -1645,7 +1645,13 @@ describe("Chart without labels", () => { createComboChart( model, - { dataSets: [{ dataRange: "A1:A2" }, { dataRange: "A3:A4" }, { dataRange: "A5:A6" }] }, + { + dataSets: [ + { dataRange: "A1:A2", type: "bar" }, + { dataRange: "A3:A4" }, + { dataRange: "A5:A6" }, + ], + }, "43" ); const dataSets = getChartConfiguration(model, "43").data.datasets; diff --git a/tests/figures/chart/charts_component.test.ts b/tests/figures/chart/charts_component.test.ts index e6696882c2..4910e9f87e 100644 --- a/tests/figures/chart/charts_component.test.ts +++ b/tests/figures/chart/charts_component.test.ts @@ -13,7 +13,11 @@ import { } from "../../../src/types"; import { BarChartDefinition, BarChartRuntime } from "../../../src/types/chart/bar_chart"; import { LineChartDefinition } from "../../../src/types/chart/line_chart"; -import { getChartConfiguration } from "../../test_helpers/chart_helpers"; +import { + getChartConfiguration, + openChartConfigSidePanel, + openChartDesignSidePanel, +} from "../../test_helpers/chart_helpers"; import { copy, createChart, @@ -79,19 +83,6 @@ function errorMessages(): string[] { return textContentAll(".o-validation-error"); } -async function openChartConfigSidePanel(id = chartId) { - model.dispatch("SELECT_FIGURE", { id }); - env.openSidePanel("ChartPanel"); - await nextTick(); -} - -async function openChartDesignSidePanel(id = chartId) { - if (!fixture.querySelector(".o-chart")) { - await openChartConfigSidePanel(id); - } - await simulateClick(".o-panel-element.inactive"); -} - async function changeChartType(type: string) { triggerMouseEvent(".o-type-selector", "pointerdown"); await nextTick(); @@ -152,7 +143,7 @@ describe("charts", () => { test.each(CHART_TYPES)("Can open a chart sidePanel", async (chartType) => { await mountSpreadsheet(); createTestChart(chartType); - await openChartConfigSidePanel(); + await openChartConfigSidePanel(model, env, chartId); expect(fixture.querySelector(".o-figure")).toBeTruthy(); }); @@ -323,7 +314,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); const color_menu = fixture.querySelectorAll( ".o-chart-title-designer > .o-color-picker-widget > .o-color-picker-button" @@ -351,7 +342,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); const alignment_menu = fixture.querySelectorAll( ".o-chart-title-designer > .o-menu-item-button[title='Horizontal alignment']" )[0]; @@ -377,7 +368,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); const bold_element = fixture.querySelectorAll( ".o-chart-title-designer > .o-menu-item-button[title='Bold']" @@ -410,7 +401,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); const color_menu = fixture.querySelectorAll( ".o-chart-title-designer > .o-color-picker-widget > .o-color-picker-button" @@ -440,7 +431,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); const alignment_menu = fixture.querySelectorAll( ".o-chart-title-designer > .o-menu-item-button[title='Horizontal alignment']" )[1]; @@ -468,7 +459,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); const bold_element = fixture.querySelectorAll( ".o-chart-title-designer > .o-menu-item-button[title='Bold']" @@ -506,7 +497,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); const bold_element = fixture.querySelectorAll( ".o-chart-title-designer > .o-menu-item-button[title='Bold']" @@ -553,7 +544,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); let color_menu = fixture.querySelectorAll(".o-round-color-picker-button")[1]; @@ -604,7 +595,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); await click(fixture, ".o-vertical-axis-selection input[value=right]"); //@ts-ignore @@ -627,7 +618,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); setInputValueAndTrigger(".o-serie-label-editor", "coucou"); //@ts-ignore @@ -646,7 +637,7 @@ describe("charts", () => { chartId ); await mountChartSidePanel(chartId); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); expect(1).toBe(1); }); @@ -672,7 +663,7 @@ describe("charts", () => { "2" ); await mountSpreadsheet(); - await openChartDesignSidePanel("1"); + await openChartDesignSidePanel(model, env, fixture, "1"); await simulateClick(".o-chart-title input"); setInputValueAndTrigger(".o-chart-title input", "first_title", "onlyInput"); @@ -705,7 +696,7 @@ describe("charts", () => { "2" ); await mountSpreadsheet(); - await openChartDesignSidePanel("1"); + await openChartDesignSidePanel(model, env, fixture, "1"); const figures = fixture.querySelectorAll(".o-figure"); await simulateClick(figures[1] as HTMLElement); @@ -721,7 +712,7 @@ describe("charts", () => { async (chartType) => { createTestChart(chartType); await mountSpreadsheet(); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); await simulateClick(".o-chart-title input"); const chartTitle = document.querySelector(".o-chart-title input") as HTMLInputElement; @@ -738,7 +729,7 @@ describe("charts", () => { createTestChart(chartType); await mountSpreadsheet(); const dispatch = spyModelDispatch(model); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); expect(fixture.querySelector(".o-chart")).toBeTruthy(); await simulateClick(".o-round-color-picker-button"); @@ -770,7 +761,7 @@ describe("charts", () => { async (chartType) => { createTestChart(chartType); await mountChartSidePanel(); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); await simulateClick(".o-color-picker-widget .o-color-picker-button"); expect(fixture.querySelector(".o-color-picker")).toBeTruthy(); @@ -804,7 +795,7 @@ describe("charts", () => { test("drawing of chart will receive new data after update", async () => { createTestChart("basicChart"); await mountSpreadsheet(); - await openChartConfigSidePanel(); + await openChartConfigSidePanel(model, env, chartId); const dataSeries = fixture.querySelectorAll(".o-chart .o-data-series")[0] as HTMLInputElement; const dataSeriesValues = dataSeries.querySelector("input"); @@ -863,7 +854,7 @@ describe("charts", () => { test("Deleting a chart with active selection input does not produce a traceback", async () => { createTestChart("basicChart"); await mountSpreadsheet(); - await openChartConfigSidePanel(); + await openChartConfigSidePanel(model, env, chartId); await simulateClick(".o-data-series .o-add-selection"); const element = document.querySelectorAll(".o-data-series input")[0]; @@ -877,7 +868,7 @@ describe("charts", () => { test("Undo a chart insertion will close the chart side panel", async () => { createTestChart("basicChart"); await mountSpreadsheet(); - await openChartConfigSidePanel(); + await openChartConfigSidePanel(model, env, chartId); undo(model); await nextTick(); expect(fixture.querySelector(".o-chart")).toBeFalsy(); @@ -910,7 +901,7 @@ describe("charts", () => { "secondChartId" ); await mountSpreadsheet(); - await openChartConfigSidePanel(); + await openChartConfigSidePanel(model, env, chartId); expect(fixture.querySelector(".o-chart")).toBeTruthy(); const figures = fixture.querySelectorAll(".o-figure"); @@ -1134,7 +1125,7 @@ describe("charts", () => { beforeEach(async () => { createTestChart("gauge"); await mountChartSidePanel(); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); }); test("empty rangeMin", async () => { @@ -1291,7 +1282,7 @@ describe("charts", () => { createTestChart(chartType); updateChart(model, chartId, { keyValue: undefined, dataRange: undefined, dataSets: [] }); await mountSpreadsheet(); - await openChartConfigSidePanel(); + await openChartConfigSidePanel(model, env, chartId); const input = fixture.querySelector(".o-selection input"); await simulateClick(input); @@ -1304,7 +1295,7 @@ describe("charts", () => { createTestChart("scorecard"); const dispatch = spyModelDispatch(model); await mountChartSidePanel(); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); // Change color of "up" value of baseline const colorpickerUpButton = fixture.querySelectorAll( @@ -1507,7 +1498,7 @@ describe("charts", () => { dataSets: [{ dataRange: "B2:B4" }], }); await mountChartSidePanel(); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); expect( (model.getters.getChartDefinition(chartId) as LineChartDefinition).showValues @@ -1611,7 +1602,7 @@ describe("charts", () => { sheetId ); await mountChartSidePanel(chartId); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); const checkbox = document.querySelector("input[name='showTrendLine']") as HTMLInputElement; expect(checkbox.checked).toBe(false); @@ -1657,7 +1648,7 @@ describe("charts", () => { sheetId ); await mountChartSidePanel(chartId); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); let definition = model.getters.getChartDefinition(chartId) as ChartWithAxisDefinition; expect(definition.dataSets[0].trend).toEqual({ @@ -1696,7 +1687,7 @@ describe("charts", () => { sheetId ); await mountChartSidePanel(chartId); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); let definition = model.getters.getChartDefinition(chartId) as ChartWithAxisDefinition; expect(definition.dataSets[0].trend).toEqual({ @@ -1732,7 +1723,7 @@ describe("charts", () => { sheetId ); await mountChartSidePanel(chartId); - await openChartDesignSidePanel(chartId); + await openChartDesignSidePanel(model, env, fixture, chartId); let runtime = model.getters.getChartRuntime(chartId) as BarChartRuntime; expect(runtime.chartJsConfig.data.datasets[1].backgroundColor).toBe("#FF8080"); @@ -1800,7 +1791,7 @@ describe("charts", () => { test("Cannot change series axis on horizontal bar chart", async () => { createChart(model, { type: "bar", horizontal: true }, chartId); await mountChartSidePanel(); - await openChartDesignSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); expect(fixture.querySelector(".o-vertical-axis-selection ")).toBeNull(); }); }); diff --git a/tests/figures/chart/combo_chart_component.test.ts b/tests/figures/chart/combo_chart_component.test.ts new file mode 100644 index 0000000000..c5f1240ce9 --- /dev/null +++ b/tests/figures/chart/combo_chart_component.test.ts @@ -0,0 +1,78 @@ +import { Model } from "../../../src"; +import { ChartPanel } from "../../../src/components/side_panel/chart/main_chart_panel/main_chart_panel"; +import { SpreadsheetChildEnv } from "../../../src/types"; +import { openChartDesignSidePanel } from "../../test_helpers/chart_helpers"; +import { createChart } from "../../test_helpers/commands_helpers"; +import { click } from "../../test_helpers/dom_helper"; +import { mountComponentWithPortalTarget } from "../../test_helpers/helpers"; + +async function mountChartSidePanel(figureId = chartId) { + const props = { figureId, onCloseSidePanel: () => {} }; + ({ fixture, env } = await mountComponentWithPortalTarget(ChartPanel, { props, model })); +} + +let fixture: HTMLElement; +let model: Model; +const chartId = "someuuid"; +let sheetId: string; + +let env: SpreadsheetChildEnv; + +describe("combo charts", () => { + beforeEach(async () => { + sheetId = "Sheet1"; + const data = { + sheets: [ + { + name: sheetId, + colNumber: 10, + rowNumber: 10, + rows: {}, + cells: { + B1: { content: "first column dataset" }, + C1: { content: "second column dataset" }, + B2: { content: "10" }, + B3: { content: "11" }, + B4: { content: "12" }, + B5: { content: "13" }, + C2: { content: "20" }, + C3: { content: "19" }, + C4: { content: "18" }, + A2: { content: "P1" }, + A3: { content: "P2" }, + A4: { content: "P3" }, + A5: { content: "P4" }, + }, + }, + ], + }; + model = new Model(data); + }); + + test("can edit chart data series type", async () => { + createChart( + model, + { + dataSets: [{ dataRange: "B1:B4" }, { dataRange: "C1:C4", type: "bar" }], + labelRange: "A2:A4", + type: "combo", + }, + chartId + ); + await mountChartSidePanel(); + await openChartDesignSidePanel(model, env, fixture, chartId); + await click(fixture, ".o-series-type-selection input[value=bar]"); + //@ts-ignore + expect(model.getters.getChartDefinition(chartId).dataSets[0]).toEqual({ + dataRange: "B1:B4", + type: "bar", + }); + + await click(fixture, ".o-series-type-selection input[value=line]"); + //@ts-ignore + expect(model.getters.getChartDefinition(chartId).dataSets[0]).toEqual({ + dataRange: "B1:B4", + type: "line", + }); + }); +}); diff --git a/tests/figures/chart/combo_chart_plugin.test.ts b/tests/figures/chart/combo_chart_plugin.test.ts index 6033e5df11..a8a10e932d 100644 --- a/tests/figures/chart/combo_chart_plugin.test.ts +++ b/tests/figures/chart/combo_chart_plugin.test.ts @@ -1,6 +1,11 @@ import { ChartCreationContext, Model } from "../../../src"; import { ComboChartRuntime } from "../../../src/types/chart/combo_chart"; -import { createChart, setCellContent, setCellFormat } from "../../test_helpers/commands_helpers"; +import { + createChart, + setCellContent, + setCellFormat, + updateChart, +} from "../../test_helpers/commands_helpers"; import { ComboChart } from "./../../../src/helpers/figures/charts/combo_chart"; describe("combo chart", () => { @@ -28,7 +33,7 @@ describe("combo chart", () => { type: "combo", background: "#123456", title: { text: "hello there" }, - dataSets: [{ dataRange: "Sheet1!B1:B4", yAxisId: "y1" }], + dataSets: [{ dataRange: "Sheet1!B1:B4", yAxisId: "y1", type: "bar" }], labelRange: "Sheet1!A1:A4", legendPosition: "bottom", dataSetsHaveTitle: true, @@ -78,4 +83,33 @@ describe("combo chart", () => { runtime.chartJsConfig.options?.scales?.y1?.ticks?.callback?.apply(null, [1, index, ticks]) ).toBe("1.00$"); }); + + test("Can edit the type of the series", () => { + const model = new Model(); + + setCellContent(model, "A1", "Alice"); + setCellContent(model, "A2", "Bob"); + setCellContent(model, "B1", "1"); + setCellContent(model, "B2", "2"); + setCellContent(model, "C1", "10"); + setCellContent(model, "C2", "20"); + + createChart( + model, + { + type: "combo", + labelRange: "A1:A2", + dataSets: [{ dataRange: "B1:B2" }, { dataRange: "C1:C2" }], + dataSetsHaveTitle: false, + }, + "1" + ); + let runtime = model.getters.getChartRuntime("1") as ComboChartRuntime; + expect(runtime.chartJsConfig.data?.datasets?.[1].type).toBe("line"); + updateChart(model, "1", { + dataSets: [{ dataRange: "B1:B2" }, { dataRange: "C1:C2", type: "bar" }], + }); + runtime = model.getters.getChartRuntime("1") as ComboChartRuntime; + expect(runtime.chartJsConfig.data?.datasets?.[1].type).toBe("bar"); + }); }); diff --git a/tests/figures/chart/waterfall/waterfall_panel_component.test.ts b/tests/figures/chart/waterfall/waterfall_panel_component.test.ts index dba8b85165..6000d15ab3 100644 --- a/tests/figures/chart/waterfall/waterfall_panel_component.test.ts +++ b/tests/figures/chart/waterfall/waterfall_panel_component.test.ts @@ -12,18 +12,13 @@ import { setInputValueAndTrigger, simulateClick, } from "../../../test_helpers"; -import { mountComponentWithPortalTarget, nextTick } from "../../../test_helpers/helpers"; +import { openChartConfigSidePanel } from "../../../test_helpers/chart_helpers"; +import { mountComponentWithPortalTarget } from "../../../test_helpers/helpers"; let model: Model; let fixture: HTMLElement; let env: SpreadsheetChildEnv; -async function openChartConfigSidePanel(chartId: UID) { - model.dispatch("SELECT_FIGURE", { id: chartId }); - env.openSidePanel("ChartPanel"); - await nextTick(); -} - function getWaterfallDefinition(chartId: UID): WaterfallChartDefinition { return model.getters.getChartDefinition(chartId) as WaterfallChartDefinition; } @@ -58,7 +53,7 @@ describe("Waterfall chart side panel", () => { dataSetsHaveTitle: true, aggregated: true, }); - await openChartConfigSidePanel(chartId); + await openChartConfigSidePanel(model, env, chartId); expect(getHTMLInputValue(".o-data-series input")).toEqual("A1:A3"); expect(getHTMLInputValue(".o-data-labels input")).toEqual("B1:B3"); @@ -73,7 +68,7 @@ describe("Waterfall chart side panel", () => { dataSetsHaveTitle: true, aggregated: true, }); - await openChartConfigSidePanel(chartId); + await openChartConfigSidePanel(model, env, chartId); await setInputValueAndTrigger(".o-data-labels input", "C1:C3"); await simulateClick(".o-data-labels .o-selection-ok"); @@ -105,7 +100,7 @@ describe("Waterfall chart side panel", () => { background: "#00FF00", firstValueAsSubtotal: true, }); - await openChartConfigSidePanel(chartId); + await openChartConfigSidePanel(model, env, chartId); await click(fixture, ".o-panel-design"); expect(getHTMLInputValue(".o-chart-title input")).toEqual("My Waterfall chart"); @@ -123,7 +118,7 @@ describe("Waterfall chart side panel", () => { test("Can change basic chart options", async () => { const chartId = createWaterfallChart(model, {}); - await openChartConfigSidePanel(chartId); + await openChartConfigSidePanel(model, env, chartId); await click(fixture, ".o-panel-design"); await setInputValueAndTrigger(".o-chart-title input", "My Waterfall chart"); @@ -143,7 +138,7 @@ describe("Waterfall chart side panel", () => { showConnectorLines: true, firstValueAsSubtotal: true, }); - await openChartConfigSidePanel(chartId); + await openChartConfigSidePanel(model, env, chartId); await click(fixture, ".o-panel-design"); await simulateClick('input[name="showSubTotals"]'); @@ -157,7 +152,7 @@ describe("Waterfall chart side panel", () => { test("Can change waterfall chart colors", async () => { const chartId = createWaterfallChart(model); - await openChartConfigSidePanel(chartId); + await openChartConfigSidePanel(model, env, chartId); await click(fixture, ".o-panel-design"); await changeChartColor(".o-chart-background-color", "#A64D79"); diff --git a/tests/test_helpers/chart_helpers.ts b/tests/test_helpers/chart_helpers.ts index e819987679..b971fb94c4 100644 --- a/tests/test_helpers/chart_helpers.ts +++ b/tests/test_helpers/chart_helpers.ts @@ -1,4 +1,6 @@ -import { Model, UID } from "../../src"; +import { Model, SpreadsheetChildEnv, UID } from "../../src"; +import { simulateClick } from "./dom_helper"; +import { nextTick } from "./helpers"; export function isChartAxisStacked(model: Model, chartId: UID, axis: "x" | "y"): boolean { return getChartConfiguration(model, chartId).options?.scales?.[axis]?.stacked; @@ -8,3 +10,21 @@ export function getChartConfiguration(model: Model, chartId: UID) { const runtime = model.getters.getChartRuntime(chartId) as any; return runtime.chartJsConfig; } + +export async function openChartConfigSidePanel(model: Model, env: SpreadsheetChildEnv, id: UID) { + model.dispatch("SELECT_FIGURE", { id }); + env.openSidePanel("ChartPanel"); + await nextTick(); +} + +export async function openChartDesignSidePanel( + model: Model, + env: SpreadsheetChildEnv, + fixture: HTMLElement, + id: UID +) { + if (!fixture.querySelector(".o-chart")) { + await openChartConfigSidePanel(model, env, id); + } + await simulateClick(".o-panel-element.inactive"); +}