Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
92db0d3
- Chart builder updates for series color scale options
cnathe Dec 4, 2025
e87c864
- ColorPickerInput update to support fixed position
cnathe Dec 4, 2025
b3639fe
7.1.0-chartColorScale.0
cnathe Dec 4, 2025
b920b0b
jest fix for existing test
cnathe Dec 4, 2025
9eeb271
ColorPickerInput to use fixedPosition by default
cnathe Dec 4, 2025
07caba7
Reset chartConfig.measuresOptions.series when series measure changes …
cnathe Dec 4, 2025
68da304
Series shape input removal to match color picker remove styling
cnathe Dec 4, 2025
d533494
Add LetterIcon for use with "Auto" set series values
cnathe Dec 4, 2025
475126c
release notes update
cnathe Dec 4, 2025
77334fd
new DEFAULT_COLORS constant
cnathe Dec 4, 2025
3d27c0f
7.1.0-chartColorScale.1
cnathe Dec 4, 2025
b66f59c
Color option layout updates - set left color to 1/4 of modal width, w…
cnathe Dec 5, 2025
c7d2d8c
7.1.0-chartColorScale.2
cnathe Dec 5, 2025
38650b2
jest test for ColorPickerInput noValueText prop
cnathe Dec 5, 2025
d15284e
jest test for ColorPickerInputs
cnathe Dec 5, 2025
d4feea1
ColorPickerInput.tsx data-name attr for test locator
cnathe Dec 8, 2025
23e396b
7.1.0-chartColorScale.3
cnathe Dec 8, 2025
3e6dd2e
jest update
cnathe Dec 8, 2025
041b329
SeriesLineStyleInput distinct values to account for non-string values…
cnathe Dec 8, 2025
024fd98
7.1.0-chartColorScale.4
cnathe Dec 8, 2025
7409d03
ColorPickerInput.tsx data-name attr for test locator
cnathe Dec 8, 2025
d3fa609
7.1.0-chartColorScale.5
cnathe Dec 8, 2025
a1474a4
Merge branch 'develop' into fb_chartColorScale
cnathe Dec 9, 2025
f8d4eea
7.1.1-chartColorScale.0
cnathe Dec 9, 2025
25dd021
CR feedback - COLOR_OPTIONS enum, ColorPickerInput placeholder param …
cnathe Dec 9, 2025
4433d95
7.1.1-chartColorScale.1
cnathe Dec 9, 2025
b792a5f
jest snapshot updates
cnathe Dec 9, 2025
3d8f436
fix for error display on ChartSettingsPanel.tsx
cnathe Dec 9, 2025
568d3b8
[Blank] -> n/a
cnathe Dec 9, 2025
c7c9088
npm run lint-branch-fix
cnathe Dec 9, 2025
1c0652d
Update release notes with version number and release date
cnathe Dec 9, 2025
eb5ac59
7.2.0
cnathe Dec 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/components/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@labkey/components",
"version": "7.1.1",
"version": "7.2.0",
"description": "Components, models, actions, and utility functions for LabKey applications and pages",
"sideEffects": false,
"files": [
Expand Down
9 changes: 9 additions & 0 deletions packages/components/releaseNotes/components.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# @labkey/components
Components, models, actions, and utility functions for LabKey applications and pages

### version 7.2.0
*Released*: 9 December 2025
- Chart builder updates for series color scale options
- ChartColorInputs for single color geomOptions and series specific color and shape value map
- ChartConfig measuresOptions to store per series mapping object
- Hide and show color options based on selected chart type and measures
- ColorPickerInput update to use fixed position by default and new DEFAULT_COLORS constant
- Add LetterIcon for use with "Auto" set series values

### version 7.1.1
*Released*: 8 December 2025
- Sample Amount/Units polish: part 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,9 @@ describe('ChartBuilderModal', () => {
expect(document.querySelectorAll('.chart-settings')).toHaveLength(1);
expect(document.querySelectorAll('.chart-builder-modal__chart-preview')).toHaveLength(1);
expect(document.querySelector('.modal-title').textContent).toBe(isNew ? 'Create Chart' : 'Edit Chart');
expect(document.querySelectorAll('.btn')).toHaveLength(canDelete ? 3 : 2);
expect(document.querySelectorAll('.btn:not(.color-picker__button)')).toHaveLength(canDelete ? 3 : 2);
expect(document.querySelectorAll('.alert')).toHaveLength(0);

// TODO update this part of jest test
// hidden chart types are filtered out
// const chartTypeItems = document.querySelectorAll('.chart-builder-type');
// expect(chartTypeItems).toHaveLength(3);
// expect(chartTypeItems[0].textContent).toBe('Bar');
// expect(chartTypeItems[1].textContent).toBe('Scatter');
// expect(chartTypeItems[2].textContent).toBe('Line');
expect(document.querySelectorAll('.chart-settings__chart-type')).toHaveLength(isNew ? 1 : 0);

expect(document.querySelectorAll('input[name="name"]')).toHaveLength(1);
expect(document.querySelectorAll('input[name="shared"]')).toHaveLength(canShare ? 1 : 0);
Expand Down Expand Up @@ -291,7 +284,7 @@ describe('ChartBuilderModal', () => {

// click delete button and verify confirm text / buttons
await userEvent.click(document.querySelector('.btn-danger'));
const btnItems = document.querySelectorAll('.btn');
const btnItems = document.querySelectorAll('.btn:not(.color-picker__button)');
expect(btnItems).toHaveLength(2);
expect(btnItems[0].textContent).toBe('Cancel');
expect(btnItems[1].textContent).toBe('Delete');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { RequiresModelAndActions } from '../../../public/QueryModel/withQueryMod
import { useServerContext } from '../base/ServerContext';
import { hasPermissions } from '../base/models/User';

import { Alert } from '../base/Alert';
import { FormButtons } from '../../FormButtons';

import { getContainerFilterForFolder } from '../../query/api';
Expand Down Expand Up @@ -354,13 +353,13 @@ export const ChartBuilderModal: FC<ChartBuilderModalProps> = memo(({ actions, mo
onCancel={onCancel}
title={savedChartModel ? 'Edit Chart' : 'Create Chart'}
>
{error && <Alert>{error}</Alert>}
<ChartSettingsPanel
allowInherit={allowInherit}
canShare={canShare}
chartConfig={chartConfig}
chartModel={chartModel}
chartType={selectedType}
error={error}
isNew={savedChartModel !== undefined}
model={model}
setChartConfig={setChartConfig}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
import React from 'react';
import { render } from '@testing-library/react';
import { ChartConfig } from './models';
import { LABKEY_VIS } from '../../constants';

import { ChartColorInputs, SeriesOptionRenderer, ShapeOptionRenderer, showColorOption } from './ChartColorInputs';
import { makeTestQueryModel } from '../../../public/QueryModel/testUtils';
import { SchemaQuery } from '../../../public/SchemaQuery';

LABKEY_VIS = {
Scale: {
ShapeMap: { circle: jest.fn },
},
};

describe('showColorOption', () => {
test('boxFillColor', () => {
expect(showColorOption({ renderType: 'bar_chart' } as ChartConfig, 'boxFillColor')).toBe(true);
expect(showColorOption({ renderType: 'box_plot' } as ChartConfig, 'boxFillColor')).toBe(true);
expect(showColorOption({ renderType: 'line_plot' } as ChartConfig, 'boxFillColor')).toBe(false);
expect(showColorOption({ renderType: 'scatter_plot' } as ChartConfig, 'boxFillColor')).toBe(false);
expect(showColorOption({ renderType: 'pie_chart' } as ChartConfig, 'boxFillColor')).toBe(false);

expect(
showColorOption(
{ renderType: 'bar_chart', measures: { xSub: { name: 'test' } } } as ChartConfig,
'boxFillColor'
)
).toBe(false);
});

test('colorPaletteScale', () => {
expect(showColorOption({ renderType: 'bar_chart' } as ChartConfig, 'colorPaletteScale')).toBe(false);
expect(showColorOption({ renderType: 'box_plot' } as ChartConfig, 'colorPaletteScale')).toBe(false);
expect(showColorOption({ renderType: 'line_plot' } as ChartConfig, 'colorPaletteScale')).toBe(false);
expect(showColorOption({ renderType: 'scatter_plot' } as ChartConfig, 'colorPaletteScale')).toBe(false);
expect(showColorOption({ renderType: 'pie_chart' } as ChartConfig, 'colorPaletteScale')).toBe(true);

expect(
showColorOption(
{ renderType: 'line_plot', measures: { series: { name: 'test' } } } as ChartConfig,
'colorPaletteScale'
)
).toBe(true);
expect(
showColorOption(
{ renderType: 'bar_chart', measures: { xSub: { name: 'test' } } } as ChartConfig,
'colorPaletteScale'
)
).toBe(true);
expect(
showColorOption(
{ renderType: 'box_plot', measures: { color: { name: 'test' } } } as ChartConfig,
'colorPaletteScale'
)
).toBe(true);
expect(
showColorOption(
{ renderType: 'scatter_plot', measures: { color: { name: 'test' } } } as ChartConfig,
'colorPaletteScale'
)
).toBe(true);
});

test('lineColor', () => {
expect(showColorOption({ renderType: 'bar_chart' } as ChartConfig, 'lineColor')).toBe(true);
expect(showColorOption({ renderType: 'box_plot' } as ChartConfig, 'lineColor')).toBe(true);
expect(showColorOption({ renderType: 'line_plot' } as ChartConfig, 'lineColor')).toBe(false);
expect(showColorOption({ renderType: 'scatter_plot' } as ChartConfig, 'lineColor')).toBe(false);
expect(showColorOption({ renderType: 'pie_chart' } as ChartConfig, 'lineColor')).toBe(false);

expect(
showColorOption(
{ renderType: 'bar_chart', measures: { xSub: { name: 'test' } } } as ChartConfig,
'lineColor'
)
).toBe(false);
});

test('pointFillColor', () => {
expect(showColorOption({ renderType: 'bar_chart' } as ChartConfig, 'pointFillColor')).toBe(false);
expect(showColorOption({ renderType: 'box_plot' } as ChartConfig, 'pointFillColor')).toBe(true);
expect(showColorOption({ renderType: 'line_plot' } as ChartConfig, 'pointFillColor')).toBe(true);
expect(showColorOption({ renderType: 'scatter_plot' } as ChartConfig, 'pointFillColor')).toBe(true);
expect(showColorOption({ renderType: 'pie_chart' } as ChartConfig, 'pointFillColor')).toBe(false);

expect(
showColorOption(
{ renderType: 'line_plot', measures: { series: { name: 'test' } } } as ChartConfig,
'pointFillColor'
)
).toBe(false);
expect(
showColorOption(
{ renderType: 'box_plot', measures: { color: { name: 'test' } } } as ChartConfig,
'pointFillColor'
)
).toBe(false);
expect(
showColorOption(
{ renderType: 'scatter_plot', measures: { color: { name: 'test' } } } as ChartConfig,
'pointFillColor'
)
).toBe(false);
});
});

describe('ShapeOptionRenderer', () => {
test('isValueRenderer false', () => {
render(<ShapeOptionRenderer isValueRenderer={false} name="circle" />);
expect(document.querySelectorAll('.chart-builder-type-option')).toHaveLength(1);
expect(document.querySelectorAll('.chart-builder-type-option--value')).toHaveLength(0);
});

test('isValueRenderer true', () => {
render(<ShapeOptionRenderer isValueRenderer name="circle" />);
expect(document.querySelectorAll('.chart-builder-type-option')).toHaveLength(1);
expect(document.querySelectorAll('.chart-builder-type-option--value')).toHaveLength(1);
});
});

describe('SeriesOptionRenderer', () => {
test('isValueRenderer false', () => {
render(<SeriesOptionRenderer isValueRenderer={false} name="series1" seriesOptionMap={{}} />);
expect(document.querySelectorAll('.chart-builder-type-option')).toHaveLength(1);
expect(document.querySelectorAll('.chart-builder-type-option--value')).toHaveLength(0);
});

test('isValueRenderer true', () => {
render(<SeriesOptionRenderer isValueRenderer name="series1" seriesOptionMap={{}} />);
expect(document.querySelectorAll('.chart-builder-type-option')).toHaveLength(1);
expect(document.querySelectorAll('.chart-builder-type-option--value')).toHaveLength(1);
});

test('without seriesOptionMap value', () => {
render(<SeriesOptionRenderer isValueRenderer name="series1" seriesOptionMap={{}} />);
expect(document.querySelector('.chart-builder-type-option').textContent).toBe('A series1');
expect(document.querySelectorAll('.color-icon__chip-small')).toHaveLength(0);
expect(document.querySelectorAll('i')).toHaveLength(0);
expect(document.querySelectorAll('.letter-icon')).toHaveLength(1);
});

test('with seriesOptionMap value', () => {
render(<SeriesOptionRenderer isValueRenderer name="series1" seriesOptionMap={{ series1: { color: 'red' } }} />);
expect(document.querySelector('.chart-builder-type-option').textContent).toBe(' series1');
expect(document.querySelectorAll('.color-icon__chip-small')).toHaveLength(1);
expect(document.querySelectorAll('i')).toHaveLength(1);
expect(document.querySelector('i').getAttribute('style')).toBe('background-color: red;');
expect(document.querySelectorAll('.letter-icon')).toHaveLength(0);
});
});

describe('ChartColorInputs', () => {
const model = makeTestQueryModel(new SchemaQuery('schema', 'query'), undefined, [], 0);

test('default bar chart', () => {
render(
<ChartColorInputs
chartConfig={{ renderType: 'bar_chart', geomOptions: {} } as ChartConfig}
model={model}
setChartConfig={jest.fn()}
/>
);
expect(document.querySelectorAll('.row')).toHaveLength(1);
expect(document.querySelectorAll('.color-picker')).toHaveLength(2);
expect(document.querySelectorAll('.select-input')).toHaveLength(0);
});

test('default pie chart', () => {
render(
<ChartColorInputs
chartConfig={{ renderType: 'pie_chart', geomOptions: {} } as ChartConfig}
model={model}
setChartConfig={jest.fn()}
/>
);
expect(document.querySelectorAll('.row')).toHaveLength(2);
expect(document.querySelectorAll('.color-picker')).toHaveLength(0);
expect(document.querySelectorAll('.select-input')).toHaveLength(1);
});

test('default box plot', () => {
render(
<ChartColorInputs
chartConfig={{ renderType: 'box_plot', geomOptions: {} } as ChartConfig}
model={model}
setChartConfig={jest.fn()}
/>
);
expect(document.querySelectorAll('.row')).toHaveLength(1);
expect(document.querySelectorAll('.color-picker')).toHaveLength(3);
expect(document.querySelectorAll('.select-input')).toHaveLength(0);
});

test('default scatter plot', () => {
render(
<ChartColorInputs
chartConfig={{ renderType: 'scatter_plot', geomOptions: {} } as ChartConfig}
model={model}
setChartConfig={jest.fn()}
/>
);
expect(document.querySelectorAll('.row')).toHaveLength(1);
expect(document.querySelectorAll('.color-picker')).toHaveLength(1);
expect(document.querySelectorAll('.select-input')).toHaveLength(0);
});

test('scatter plot with color', () => {
render(
<ChartColorInputs
chartConfig={
{
renderType: 'scatter_plot',
geomOptions: {},
measures: { color: { name: 'test' } },
} as ChartConfig
}
model={model}
setChartConfig={jest.fn()}
/>
);
expect(document.querySelectorAll('.row')).toHaveLength(2);
expect(document.querySelectorAll('.color-picker')).toHaveLength(0);
expect(document.querySelectorAll('.select-input')).toHaveLength(1);
});

test('default line plot', () => {
render(
<ChartColorInputs
chartConfig={{ renderType: 'line_plot', geomOptions: {} } as ChartConfig}
model={model}
setChartConfig={jest.fn()}
/>
);
expect(document.querySelectorAll('.row')).toHaveLength(1);
expect(document.querySelectorAll('.color-picker')).toHaveLength(1);
expect(document.querySelectorAll('.select-input')).toHaveLength(0);
});

test('line plot with series', () => {
render(
<ChartColorInputs
chartConfig={
{
renderType: 'line_plot',
geomOptions: {},
measures: { series: { name: 'test' } },
} as ChartConfig
}
model={model}
setChartConfig={jest.fn()}
/>
);
expect(document.querySelectorAll('.row')).toHaveLength(2);
expect(document.querySelectorAll('.color-picker')).toHaveLength(0);
expect(document.querySelectorAll('.select-input')).toHaveLength(1);
});
});
Loading