mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Chart builder: discoverable entry points — Build Chart door, dataset picker, no-datasets state
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
calculatedFieldNames,
|
||||
effectiveColumns,
|
||||
pruneEncodings,
|
||||
rebaseBuilderConfig,
|
||||
type BuilderCalculate,
|
||||
type BuilderColumns,
|
||||
type BuilderConfig,
|
||||
@@ -1290,3 +1291,91 @@ describe('pruneEncodings', () => {
|
||||
expect(pruneEncodings(config, columns)).toBe(config);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rebaseBuilderConfig (dataset switch)', () => {
|
||||
// The new dataset shares `category` but lacks `value`/`when`/`flag`.
|
||||
const newColumns: BuilderColumns = {
|
||||
columns: ['category', 'profit'],
|
||||
columnTypes: [
|
||||
{ name: 'category', type: 'string' },
|
||||
{ name: 'profit', type: 'number' },
|
||||
],
|
||||
};
|
||||
|
||||
it('keeps chart-level intent and same-name bindings, re-pointing the dataset', () => {
|
||||
const config: BuilderConfig = {
|
||||
datasetName: 'Old',
|
||||
mark: 'bar',
|
||||
title: 'Revenue by region',
|
||||
subtitle: 'FY26',
|
||||
width: 400,
|
||||
height: 200,
|
||||
sort: 'descending',
|
||||
stack: 'normalize',
|
||||
encodings: { x: { field: 'category', type: 'nominal' } },
|
||||
};
|
||||
const out = rebaseBuilderConfig(config, 'New', newColumns);
|
||||
expect(out.datasetName).toBe('New');
|
||||
expect(out.mark).toBe('bar');
|
||||
expect(out.title).toBe('Revenue by region');
|
||||
expect(out.subtitle).toBe('FY26');
|
||||
expect(out.width).toBe(400);
|
||||
expect(out.height).toBe(200);
|
||||
expect(out.sort).toBe('descending');
|
||||
expect(out.stack).toBe('normalize');
|
||||
expect(out.encodings.x).toEqual({ field: 'category', type: 'nominal' });
|
||||
});
|
||||
|
||||
it('sheds encodings and predicate filters bound to columns the new dataset lacks', () => {
|
||||
const config: BuilderConfig = {
|
||||
datasetName: 'Old',
|
||||
mark: 'bar',
|
||||
encodings: {
|
||||
x: { field: 'category', type: 'nominal' },
|
||||
y: { field: 'value', type: 'quantitative' },
|
||||
},
|
||||
filters: [
|
||||
filter({ id: 'f1', field: 'value', fieldType: 'quantitative', op: 'gt', value: '0' }),
|
||||
filter({ id: 'f2', field: 'category', fieldType: 'nominal', op: 'equal', value: 'A' }),
|
||||
],
|
||||
};
|
||||
const out = rebaseBuilderConfig(config, 'New', newColumns);
|
||||
expect(out.encodings.x).toEqual({ field: 'category', type: 'nominal' });
|
||||
expect(out.encodings.y).toBeNull();
|
||||
expect(out.filters?.map((f) => f.id)).toEqual(['f2']);
|
||||
});
|
||||
|
||||
it('keeps expression filters, constants, count mappings, and calculated-field bindings', () => {
|
||||
const config: BuilderConfig = {
|
||||
datasetName: 'Old',
|
||||
mark: 'bar',
|
||||
encodings: {
|
||||
x: { field: 'ratio', type: 'quantitative' }, // a calculated field travels along
|
||||
y: { type: 'quantitative', aggregate: 'count' }, // field-less count
|
||||
color: { value: '#ff0000', type: 'nominal' }, // constant — no column binding
|
||||
},
|
||||
calculates: [calc({ as: 'ratio', expr: 'datum.profit * 2' })],
|
||||
filters: [filter({ id: 'fx', mode: 'expression', expr: 'datum.value > 0' })],
|
||||
};
|
||||
const out = rebaseBuilderConfig(config, 'New', newColumns);
|
||||
expect(out.encodings.x).toEqual({ field: 'ratio', type: 'quantitative' });
|
||||
expect(out.encodings.y).toEqual({ type: 'quantitative', aggregate: 'count' });
|
||||
expect(out.encodings.color).toEqual({ value: '#ff0000', type: 'nominal' });
|
||||
expect(out.calculates).toEqual(config.calculates);
|
||||
expect(out.filters).toEqual(config.filters);
|
||||
});
|
||||
|
||||
it('a same-schema dataset keeps the whole config (only the name changes)', () => {
|
||||
const config: BuilderConfig = {
|
||||
datasetName: 'Old',
|
||||
mark: 'line',
|
||||
encodings: {
|
||||
x: { field: 'when', type: 'temporal' },
|
||||
y: { field: 'value', type: 'quantitative', aggregate: 'sum' },
|
||||
},
|
||||
filters: [filter({ field: 'category', fieldType: 'nominal', op: 'equal', value: 'A' })],
|
||||
};
|
||||
const out = rebaseBuilderConfig(config, 'New', columns);
|
||||
expect(out).toEqual({ ...config, datasetName: 'New' });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user