Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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.53.0",
"version": "7.54.0",
"description": "Components, models, actions, and utility functions for LabKey applications and pages",
"sideEffects": false,
"files": [
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ import {
import { QueryFormInputs } from './internal/components/forms/QueryFormInputs';
import { LookupSelectInput } from './internal/components/forms/input/LookupSelectInput';
import { SelectInput } from './internal/components/forms/input/SelectInput';
import { RequiredSymbol } from './internal/components/forms/input/RequiredSymbol';
import { dividedOptionsRenderer, filterDividedOptions } from './internal/components/forms/input/DividedOptionsRenderer';
import { DatePickerInput } from './internal/components/forms/input/DatePickerInput';
import { FileInput } from './internal/components/forms/input/FileInput';
Expand Down Expand Up @@ -1651,6 +1652,7 @@ export {
ReportItemModal,
ReportList,
request,
RequiredSymbol,
RequiresPermission,
resolveDetailFieldValue,
resolveDetailRenderer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { AddRowsControl, AddRowsControlProps, PlacementType } from './Controls';
import { CellMessage, EditableColumnMetadata, EditorModel, EditorModelProps, ValueDescriptor } from './models';
import { computeRangeChange, genCellKey, getValidatedEditableGridValue, parseCellKey } from './utils';
import { RemoveColumnMenuItem } from './RemoveColumnMenuItem';
import { RequiredSymbol } from '../forms/input/RequiredSymbol';

function anyCell(values: List<ValueDescriptor>): boolean {
return true;
Expand Down Expand Up @@ -694,7 +695,10 @@ export class EditableGrid extends PureComponent<EditableGridProps, EditableGridS
changesMade = true;
const col = columnMap.get(parseCellKey(cellKey).fieldKey);
const isMultiChoiceCol = col?.isMultiChoice;
const { message } = getValidatedEditableGridValue(isMultiChoiceCol ? newValues : newValues[0].display, column ?? col);
const { message } = getValidatedEditableGridValue(
isMultiChoiceCol ? newValues : newValues[0].display,
column ?? col
);
changes.cellMessages = cellMessages.set(cellKey, message);
} else if (mod === MODIFICATION_TYPES.REMOVE) {
let values: List<ValueDescriptor> = editorModel.getIn(keyPath);
Expand Down Expand Up @@ -880,7 +884,7 @@ export class EditableGrid extends PureComponent<EditableGridProps, EditableGridS
{!showLabelOverlay && (
<>
{label}
{req && <span className="required-symbol"> *</span>}
<RequiredSymbol required={req} />
</>
)}
{showOverlayFromMetadata && (
Expand Down Expand Up @@ -1023,6 +1027,22 @@ export class EditableGrid extends PureComponent<EditableGridProps, EditableGridS
let selectionType: SELECTION_TYPES = isShift ? SELECTION_TYPES.AREA_CHANGE : undefined;

switch (event.key) {
case Key.ARROW_DOWN: {
const predicate = isMeta ? not(isCellEmpty) : anyCell;
const found = editorModel.findNextCell(
colIdx,
rowIdx,
predicate,
moveDown,
hideReadonlyRows,
readonlyRows
);
if (found) {
nextCol = found.colIdx;
nextRow = found.rowIdx;
}
break;
}
case Key.ARROW_LEFT: {
if (isMeta) {
const found = editorModel.findNextCell(
Expand All @@ -1046,22 +1066,6 @@ export class EditableGrid extends PureComponent<EditableGridProps, EditableGridS
}
break;
}
case Key.ARROW_UP: {
const predicate = isMeta ? not(isCellEmpty) : anyCell;
const found = editorModel.findNextCell(
colIdx,
rowIdx,
predicate,
moveUp,
hideReadonlyRows,
readonlyRows
);
if (found) {
nextCol = found.colIdx;
nextRow = found.rowIdx;
}
break;
}
case Key.ARROW_RIGHT: {
if (isMeta) {
const found = editorModel.findNextCell(
Expand All @@ -1085,13 +1089,13 @@ export class EditableGrid extends PureComponent<EditableGridProps, EditableGridS
}
break;
}
case Key.ARROW_DOWN: {
case Key.ARROW_UP: {
const predicate = isMeta ? not(isCellEmpty) : anyCell;
const found = editorModel.findNextCell(
colIdx,
rowIdx,
predicate,
moveDown,
moveUp,
hideReadonlyRows,
readonlyRows
);
Expand All @@ -1101,15 +1105,15 @@ export class EditableGrid extends PureComponent<EditableGridProps, EditableGridS
}
break;
}
case Key.HOME: {
nextCol = 0;
case Key.END: {
nextCol = editorModel.orderedColumns.size - 1;
nextRow = rowIdx;
// Issue 51421
if (isShift) selectionType = SELECTION_TYPES.AREA;
break;
}
case Key.END: {
nextCol = editorModel.orderedColumns.size - 1;
case Key.HOME: {
nextCol = 0;
nextRow = rowIdx;
// Issue 51421
if (isShift) selectionType = SELECTION_TYPES.AREA;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { QueryColumn } from '../../../public/QueryColumn';

import { Formsy } from './formsy';
import { FieldLabel } from './FieldLabel';
import { LabelOverlayProps } from './LabelOverlay';
import { INPUT_LABEL_CLASS_NAME_WITH_TOGGLE } from './constants';

const queryColumn = new QueryColumn({
name: 'testColumn',
Expand All @@ -21,20 +23,20 @@ describe('FieldLabel', () => {
});

test("don't show label", () => {
render(<FieldLabel showLabel={false} label="Label" />);
expect(document.body.textContent).toBe('');
render(<FieldLabel label="Label" showLabel={false} />);
expect(document.body).toHaveTextContent('');
});

test('without overlay, with label', () => {
const label = <span className="label-span">This is the label</span>;
render(<FieldLabel withLabelOverlay={false} label={label} />);
expect(document.querySelector('span.label-span').textContent).toBe('This is the label');
render(<FieldLabel label={label} withLabelOverlay={false} />);
expect(document.querySelector('span.label-span')).toHaveTextContent('This is the label');
expect(document.querySelectorAll('.overlay-trigger')).toHaveLength(0);
});

test('without overlay, with column', () => {
render(<FieldLabel withLabelOverlay={false} column={queryColumn} />);
expect(document.body.textContent).toBe(queryColumn.caption);
render(<FieldLabel column={queryColumn} withLabelOverlay={false} />);
expect(document.body).toHaveTextContent(queryColumn.caption);
expect(document.querySelectorAll('.span.label-span')).toHaveLength(0);
expect(document.querySelectorAll('.overlay-trigger')).toHaveLength(0);
});
Expand All @@ -57,13 +59,25 @@ describe('FieldLabel', () => {
test('showToggle', () => {
render(
<Formsy>
<FieldLabel id="test" column={queryColumn} showToggle />
<FieldLabel column={queryColumn} id="test" showToggle />
</Formsy>
);
expect(document.querySelectorAll('.toggle')).toHaveLength(1);
expect(document.querySelectorAll('.overlay-trigger')).toHaveLength(1);
});

test('showToggle requires a column or an id and fieldName', () => {
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => undefined);

expect(() => render(<FieldLabel showToggle />)).toThrow(
'FieldLabel: when showing the toggle, either a column or an id and fieldName must be provided.'
);
expect(() => render(<FieldLabel fieldName="test" showToggle />)).toThrow();
expect(() => render(<FieldLabel id="test" showToggle />)).toThrow();

consoleError.mockRestore();
});

test('showToggle, with labelOverlayProps, not formsy', () => {
const label = 'This is the label';
const props = {
Expand All @@ -72,14 +86,61 @@ describe('FieldLabel', () => {
};
render(
<Formsy>
<FieldLabel id="test" column={queryColumn} showToggle labelOverlayProps={props} />
<FieldLabel column={queryColumn} id="test" labelOverlayProps={props} showToggle />
</Formsy>
);
expect(document.querySelectorAll('.toggle')).toHaveLength(1);
expect(document.querySelectorAll('.control-label-toggle-input')).toHaveLength(1);
expect(document.querySelectorAll('.overlay-trigger')).toHaveLength(1);
});

test('showToggle, with labelOverlayProps, not formsy, sizes the label and toggle columns', () => {
const props: LabelOverlayProps = { isFormsy: false, label: 'This is the label' };
const { rerender } = render(
<Formsy>
<FieldLabel column={queryColumn} id="test" labelOverlayProps={props} showToggle />
</Formsy>
);

const expectToggleColumns = (): void => {
expect(document.querySelector('.control-label')).toHaveClass(INPUT_LABEL_CLASS_NAME_WITH_TOGGLE);
expect(document.querySelector('.control-label-toggle-input')).toHaveClass(
'control-label-toggle-input-size-fixed'
);
expect(document.querySelector('.control-label-toggle-input').parentElement).toHaveClass('col-xs-1');
};

expectToggleColumns();

// The labelOverlayProps supplied by the caller are not modified, so the columns are sized
// consistently no matter how many times the same props object is rendered.
expect(props.labelClass).toBeUndefined();

rerender(
<Formsy>
<FieldLabel column={queryColumn} id="test" labelOverlayProps={props} showToggle />
</Formsy>
);

expectToggleColumns();
});

test('showToggle, with labelOverlayProps, not formsy, respects a supplied labelClass', () => {
const props: LabelOverlayProps = { isFormsy: false, label: 'This is the label', labelClass: 'custom-label' };
render(
<Formsy>
<FieldLabel column={queryColumn} id="test" labelOverlayProps={props} showToggle />
</Formsy>
);

expect(document.querySelector('.custom-label')).toBeInTheDocument();
expect(document.querySelector('.custom-label')).not.toHaveClass(INPUT_LABEL_CLASS_NAME_WITH_TOGGLE);
expect(document.querySelector('.control-label-toggle-input')).not.toHaveClass(
'control-label-toggle-input-size-fixed'
);
expect(document.querySelector('.control-label-toggle-input').parentElement).not.toHaveClass('col-xs-1');
});

test('showToggle, with labelOverlayProps, formsy', () => {
const label = 'This is the label';
const props = {
Expand All @@ -88,7 +149,7 @@ describe('FieldLabel', () => {
};
render(
<Formsy>
<FieldLabel id="test" column={queryColumn} showToggle labelOverlayProps={props} />
<FieldLabel column={queryColumn} id="test" labelOverlayProps={props} showToggle />
</Formsy>
);
expect(document.querySelectorAll('.toggle')).toHaveLength(1);
Expand All @@ -105,10 +166,10 @@ describe('FieldLabel', () => {
render(
<Formsy>
<FieldLabel
id="test"
column={queryColumn}
showToggle
id="test"
labelOverlayProps={props}
showToggle
toggleClassName="toggle-wrapper"
/>
</Formsy>
Expand All @@ -127,10 +188,10 @@ describe('FieldLabel', () => {
render(
<Formsy>
<FieldLabel
id="test"
column={queryColumn}
showToggle
id="test"
labelOverlayProps={props}
showToggle
toggleClassName="toggle-wrapper"
/>
</Formsy>
Expand All @@ -143,7 +204,7 @@ describe('FieldLabel', () => {
test('showToggle, toggleProps disabled', () => {
render(
<Formsy>
<FieldLabel id="test" column={queryColumn} showToggle toggleProps={{ toolTip: 'This is a tooltip' }} />
<FieldLabel column={queryColumn} id="test" showToggle toggleProps={{ toolTip: 'This is a tooltip' }} />
</Formsy>
);
expect(document.querySelectorAll('.toggle')).toHaveLength(1);
Expand All @@ -154,7 +215,7 @@ describe('FieldLabel', () => {
test('showToggle, toggleProps not disabled', () => {
render(
<Formsy>
<FieldLabel id="test" column={queryColumn} showToggle toggleProps={{ onClick: jest.fn() }} />
<FieldLabel column={queryColumn} id="test" showToggle toggleProps={{ onClick: jest.fn() }} />
</Formsy>
);
expect(document.querySelectorAll('.toggle')).toHaveLength(1);
Expand Down
Loading