From d4ca92e5d7044d8be7b26ccbc52b91747663bfe2 Mon Sep 17 00:00:00 2001 From: mollykreis <20542556+mollykreis@users.noreply.github.com> Date: Thu, 29 Feb 2024 10:03:03 -0600 Subject: [PATCH 1/2] Empty icon mapping (#1874) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## ๐Ÿคจ Rationale Grouping on an icon value isn't ideal if any of the cells don't have an icon. Specifically, the group row doesn't have a value associated with it and renders only a row count. It would be nice if we could allow a client to leave a cell blank for certain field values but still have the group rows have a value associated with them. For example, have a column that shows either a spinner or nothing based on whether a task is in progress. When grouping, it would be nice to show a string, such as "Idle", associated with the records that have nothing in progress without cluttering the table with extra icons in cells. This is the Future Work described in #1869 ## ๐Ÿ‘ฉโ€๐Ÿ’ป Implementation Updated the icon column to allow a `nimble-mapping-icon` to have an `undefined` icon. In that case, the cell renders nothing but the group row renders only the text associated with the mapping. ## ๐Ÿงช Testing Manually tested in storybook. Added new unit tests for having an `undefined` icon Updated storybook/matrix tests ## โœ… Checklist - [ ] I have updated the project documentation to reflect my changes or determined no changes are needed. --------- Co-authored-by: Milan Raj --- ...-106d0846-d742-466e-8fef-552c0a156055.json | 7 ++++ .../icon/tests/mapping-icon.stories.ts | 2 +- .../enum-base/models/mapping-icon-config.ts | 35 +++++++++++++------ .../src/table-column/icon/index.ts | 3 -- .../models/table-column-icon-validator.ts | 9 ++++- .../tests/table-column-icon-matrix.stories.ts | 9 ++++- .../icon/tests/table-column-icon.spec.ts | 33 ++++++++++++++++- .../icon/tests/table-column-icon.stories.ts | 7 ++++ 8 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 change/@ni-nimble-components-106d0846-d742-466e-8fef-552c0a156055.json diff --git a/change/@ni-nimble-components-106d0846-d742-466e-8fef-552c0a156055.json b/change/@ni-nimble-components-106d0846-d742-466e-8fef-552c0a156055.json new file mode 100644 index 0000000000..fe5e24efcc --- /dev/null +++ b/change/@ni-nimble-components-106d0846-d742-466e-8fef-552c0a156055.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Allow icon mappings to specify an undefined icon", + "packageName": "@ni/nimble-components", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/nimble-components/src/mapping/icon/tests/mapping-icon.stories.ts b/packages/nimble-components/src/mapping/icon/tests/mapping-icon.stories.ts index e08a89c130..94da976544 100644 --- a/packages/nimble-components/src/mapping/icon/tests/mapping-icon.stories.ts +++ b/packages/nimble-components/src/mapping/icon/tests/mapping-icon.stories.ts @@ -28,7 +28,7 @@ export const iconMapping: StoryObj = { icon: { control: { type: 'none' }, description: - 'The tag name of the Nimble icon to render, e.g. `nimble-icon-check`.' + 'The tag name of the Nimble icon to render, e.g. `nimble-icon-check`. Alternatively, set `icon` to `undefined` to render no icon for the mapping while still providing a label to be used when grouping.' }, severity: { description: diff --git a/packages/nimble-components/src/table-column/enum-base/models/mapping-icon-config.ts b/packages/nimble-components/src/table-column/enum-base/models/mapping-icon-config.ts index bdebf2a8e3..be49a89f2b 100644 --- a/packages/nimble-components/src/table-column/enum-base/models/mapping-icon-config.ts +++ b/packages/nimble-components/src/table-column/enum-base/models/mapping-icon-config.ts @@ -6,15 +6,30 @@ export interface IconView { severity: IconSeverity; text?: string; } -const createIconTemplate = (icon: string): ViewTemplate => html` - <${icon} - title="${x => x.text}" - role="img" - aria-label="${x => x.text}" - severity="${x => x.severity}" - class="no-shrink" - > - `; + +// Create an empty template containing only a space because creating a ViewTemplate +// with an empty string throws an exception at runtime. +// prettier-ignore +const emptyTemplate = html` `; + +const createIconTemplate = ( + icon: string | undefined +): ViewTemplate => { + if (icon === undefined) { + return emptyTemplate; + } + + return html` + <${icon} + title="${x => x.text}" + role="img" + aria-label="${x => x.text}" + severity="${x => x.severity}" + class="no-shrink" + > + + `; +}; /** * Mapping configuration corresponding to a icon mapping @@ -22,7 +37,7 @@ const createIconTemplate = (icon: string): ViewTemplate => html` export class MappingIconConfig extends MappingConfig { public readonly iconTemplate: ViewTemplate; public constructor( - resolvedIcon: string, + resolvedIcon: string | undefined, public readonly severity: IconSeverity, text: string | undefined ) { diff --git a/packages/nimble-components/src/table-column/icon/index.ts b/packages/nimble-components/src/table-column/icon/index.ts index 18f3631aa9..d692e3d88a 100644 --- a/packages/nimble-components/src/table-column/icon/index.ts +++ b/packages/nimble-components/src/table-column/icon/index.ts @@ -65,9 +65,6 @@ export class TableColumnIcon extends mixinGroupableColumnAPI( protected createMappingConfig(mapping: Mapping): MappingConfig { if (mapping instanceof MappingIcon) { - if (!mapping.resolvedIcon) { - throw Error('Unresolved icon'); - } return new MappingIconConfig( mapping.resolvedIcon, mapping.severity, diff --git a/packages/nimble-components/src/table-column/icon/models/table-column-icon-validator.ts b/packages/nimble-components/src/table-column/icon/models/table-column-icon-validator.ts index 636f22dc8f..303484951b 100644 --- a/packages/nimble-components/src/table-column/icon/models/table-column-icon-validator.ts +++ b/packages/nimble-components/src/table-column/icon/models/table-column-icon-validator.ts @@ -39,6 +39,13 @@ export class TableColumnIconValidator extends TableColumnEnumBaseValidator< ); } + private static hasUnresolvedIcon(mappingIcon: MappingIcon): boolean { + return ( + typeof mappingIcon.icon === 'string' + && mappingIcon.resolvedIcon === undefined + ); + } + public override validate( mappings: Mapping[], keyType: MappingKeyType @@ -52,7 +59,7 @@ export class TableColumnIconValidator extends TableColumnEnumBaseValidator< private validateIconNames(mappings: Mapping[]): void { const invalid = mappings .filter(TableColumnIconValidator.isIconMappingElement) - .some(mappingIcon => mappingIcon.resolvedIcon === undefined); + .some(TableColumnIconValidator.hasUnresolvedIcon); this.setConditionValue('invalidIconName', invalid); } diff --git a/packages/nimble-components/src/table-column/icon/tests/table-column-icon-matrix.stories.ts b/packages/nimble-components/src/table-column/icon/tests/table-column-icon-matrix.stories.ts index 10c6577db8..547560da86 100644 --- a/packages/nimble-components/src/table-column/icon/tests/table-column-icon-matrix.stories.ts +++ b/packages/nimble-components/src/table-column/icon/tests/table-column-icon-matrix.stories.ts @@ -32,18 +32,23 @@ const data = [ { id: '2', code: 2 + }, + { + id: '3', + code: -1 } ] as const; // prettier-ignore const component = (): ViewTemplate => html` - <${tableTag} id-field-name="id" style="height: 250px; ${isChromatic() ? '--ni-private-spinner-animation-play-state:paused' : ''}"> + <${tableTag} id-field-name="id" style="height: 320px; ${isChromatic() ? '--ni-private-spinner-animation-play-state:paused' : ''}"> <${tableColumnIconTag} field-name="code" key-type="number" group-index="0" > Column 1 + <${mappingIconTag} key="-1" text="Unknown value"> <${mappingIconTag} key="0" text="Zero" icon="${iconCheckTag}"> <${mappingSpinnerTag} key="1" text="One"> @@ -52,6 +57,7 @@ const component = (): ViewTemplate => html` key-type="number" > Column 2 + <${mappingIconTag} key="-1" text="Unknown value"> <${mappingIconTag} key="0" text="Zero" icon="${iconCheckTag}" severity="success"> <${mappingIconTag} key="1" text="One" icon="${iconCheckTag}" severity="warning"> <${mappingIconTag} key="2" text="Two" icon="${iconCheckTag}" severity="error"> @@ -61,6 +67,7 @@ const component = (): ViewTemplate => html` key-type="number" > Column 3 + <${mappingIconTag} key="-1" text="Unknown value"> <${mappingIconTag} key="0" text="Zero" icon="${iconCheckTag}" severity="information"> diff --git a/packages/nimble-components/src/table-column/icon/tests/table-column-icon.spec.ts b/packages/nimble-components/src/table-column/icon/tests/table-column-icon.spec.ts index 0bf1885e18..daabf451aa 100644 --- a/packages/nimble-components/src/table-column/icon/tests/table-column-icon.spec.ts +++ b/packages/nimble-components/src/table-column/icon/tests/table-column-icon.spec.ts @@ -25,7 +25,7 @@ interface SimpleTableRecord extends TableRecord { interface BasicIconMapping { key?: MappingKey; text?: string; - icon: string; + icon?: string; } interface BasicSpinnerMapping { @@ -154,6 +154,20 @@ describe('TableColumnIcon', () => { expect(() => pageObject.getRenderedIconColumnCellIconTagName(0, 0)).toThrowError(); }); + it('displays blank when no icon specified for mapping', async () => { + ({ element, connect, disconnect, model } = await setup({ + keyType: MappingKeyType.string, + iconMappings: [{ key: 'a', text: 'alpha', icon: undefined }], + spinnerMappings: [] + })); + pageObject = new TablePageObject(element); + await element.setData([{ field1: 'a' }]); + await connect(); + await waitForUpdatesAsync(); + + expect(() => pageObject.getRenderedIconColumnCellIconTagName(0, 0)).toThrowError(); + }); + it('changing fieldName updates display', async () => { ({ element, connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, @@ -308,6 +322,23 @@ describe('TableColumnIcon', () => { expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe(''); }); + it('sets group header text label and no icon when icon is undefined', async () => { + ({ element, connect, disconnect, model } = await setup({ + keyType: MappingKeyType.string, + iconMappings: [{ key: 'b', text: 'bravo', icon: undefined }], + spinnerMappings: [] + })); + pageObject = new TablePageObject(element); + await element.setData([{ field1: 'b' }]); + await connect(); + await waitForUpdatesAsync(); + model.col1.groupIndex = 0; + await waitForUpdatesAsync(); + + expect(() => pageObject.getRenderedIconColumnGroupHeaderIconTagName(0)).toThrowError(); + expect(pageObject.getRenderedGroupHeaderTextContent(0)).toBe('bravo'); + }); + it('clears cell when mappings removed', async () => { ({ element, connect, disconnect, model } = await setup({ keyType: MappingKeyType.string, diff --git a/packages/nimble-components/src/table-column/icon/tests/table-column-icon.stories.ts b/packages/nimble-components/src/table-column/icon/tests/table-column-icon.stories.ts index 542f8f3599..b8dd9743c0 100644 --- a/packages/nimble-components/src/table-column/icon/tests/table-column-icon.stories.ts +++ b/packages/nimble-components/src/table-column/icon/tests/table-column-icon.stories.ts @@ -40,6 +40,12 @@ const simpleData = [ lastName: 'Simpson', status: 'success', isChild: true + }, + { + firstName: 'Abbey', + lastName: '?', + status: 'unknown', + isChild: false } ] as const; @@ -77,6 +83,7 @@ export const iconColumn: StoryObj = { <${mappingIconTag} key="fail" icon="${iconXmarkTag}" severity="error" text="Not a Simpson"> <${mappingIconTag} key="success" icon="${iconCheckLargeTag}" severity="success" text="Is a Simpson"> <${mappingSpinnerTag} key="calculating" text="Calculating"> + <${mappingIconTag} key="unknown" text="Unknown"> <${tableColumnIconTag} field-name="isChild" key-type="boolean"> Is Child From 2de9eecfe3a441833e2648c4a2effd3c9548d9a0 Mon Sep 17 00:00:00 2001 From: rajsite Date: Thu, 29 Feb 2024 16:22:43 +0000 Subject: [PATCH 2/2] applying package updates [skip ci] --- .../projects/ni/nimble-angular/CHANGELOG.json | 15 +++++++++++++++ .../projects/ni/nimble-angular/CHANGELOG.md | 10 +++++++++- .../projects/ni/nimble-angular/package.json | 4 ++-- ...ents-106d0846-d742-466e-8fef-552c0a156055.json | 7 ------- package-lock.json | 8 ++++---- packages/nimble-blazor/package.json | 2 +- packages/nimble-components/CHANGELOG.json | 15 +++++++++++++++ packages/nimble-components/CHANGELOG.md | 10 +++++++++- packages/nimble-components/package.json | 2 +- 9 files changed, 56 insertions(+), 17 deletions(-) delete mode 100644 change/@ni-nimble-components-106d0846-d742-466e-8fef-552c0a156055.json diff --git a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json index 81fa7d8153..410aba2bee 100644 --- a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json +++ b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-angular", "entries": [ + { + "date": "Thu, 29 Feb 2024 16:22:43 GMT", + "version": "20.2.15", + "tag": "@ni/nimble-angular_v20.2.15", + "comments": { + "patch": [ + { + "author": "beachball", + "package": "@ni/nimble-angular", + "comment": "Bump @ni/nimble-components to v21.8.0", + "commit": "not available" + } + ] + } + }, { "date": "Wed, 28 Feb 2024 21:22:49 GMT", "version": "20.2.13", diff --git a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md index db79e75155..02248d4630 100644 --- a/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md +++ b/angular-workspace/projects/ni/nimble-angular/CHANGELOG.md @@ -1,9 +1,17 @@ # Change Log - @ni/nimble-angular -This log was last generated on Wed, 28 Feb 2024 21:22:49 GMT and should not be manually modified. +This log was last generated on Thu, 29 Feb 2024 16:22:43 GMT and should not be manually modified. +## 20.2.15 + +Thu, 29 Feb 2024 16:22:43 GMT + +### Patches + +- Bump @ni/nimble-components to v21.8.0 + ## 20.2.13 Wed, 28 Feb 2024 21:22:49 GMT diff --git a/angular-workspace/projects/ni/nimble-angular/package.json b/angular-workspace/projects/ni/nimble-angular/package.json index 438051c040..14541f260f 100644 --- a/angular-workspace/projects/ni/nimble-angular/package.json +++ b/angular-workspace/projects/ni/nimble-angular/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-angular", - "version": "20.2.14", + "version": "20.2.15", "description": "Angular components for the NI Nimble Design System", "scripts": { "invoke-publish": "cd ../../../ && npm run build:library && cd dist/ni/nimble-angular && npm publish" @@ -31,7 +31,7 @@ "@angular/forms": "^15.2.10", "@angular/localize": "^15.2.10", "@angular/router": "^15.2.10", - "@ni/nimble-components": "^21.7.1" + "@ni/nimble-components": "^21.8.0" }, "dependencies": { "tslib": "^2.2.0" diff --git a/change/@ni-nimble-components-106d0846-d742-466e-8fef-552c0a156055.json b/change/@ni-nimble-components-106d0846-d742-466e-8fef-552c0a156055.json deleted file mode 100644 index fe5e24efcc..0000000000 --- a/change/@ni-nimble-components-106d0846-d742-466e-8fef-552c0a156055.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "minor", - "comment": "Allow icon mappings to specify an undefined icon", - "packageName": "@ni/nimble-components", - "email": "20542556+mollykreis@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/package-lock.json b/package-lock.json index 7be2da96f0..b8191d6030 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,7 +83,7 @@ }, "angular-workspace/projects/ni/nimble-angular": { "name": "@ni/nimble-angular", - "version": "20.2.14", + "version": "20.2.15", "license": "MIT", "dependencies": { "tslib": "^2.2.0" @@ -94,7 +94,7 @@ "@angular/forms": "^15.2.10", "@angular/localize": "^15.2.10", "@angular/router": "^15.2.10", - "@ni/nimble-components": "^21.7.1" + "@ni/nimble-components": "^21.8.0" } }, "node_modules/@11ty/dependency-tree": { @@ -33897,7 +33897,7 @@ }, "packages/nimble-blazor": { "name": "@ni/nimble-blazor", - "version": "14.3.11", + "version": "14.3.12", "hasInstallScript": true, "license": "MIT", "devDependencies": { @@ -34019,7 +34019,7 @@ }, "packages/nimble-components": { "name": "@ni/nimble-components", - "version": "21.7.1", + "version": "21.8.0", "license": "MIT", "dependencies": { "@microsoft/fast-colors": "^5.3.1", diff --git a/packages/nimble-blazor/package.json b/packages/nimble-blazor/package.json index 5f3cbd59ce..2c308cc466 100644 --- a/packages/nimble-blazor/package.json +++ b/packages/nimble-blazor/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-blazor", - "version": "14.3.11", + "version": "14.3.12", "description": "Blazor components for the NI Nimble Design System", "scripts": { "postinstall": "node build/generate-playwright-version-properties/source/index.js", diff --git a/packages/nimble-components/CHANGELOG.json b/packages/nimble-components/CHANGELOG.json index 1ff68783f9..89646d7668 100644 --- a/packages/nimble-components/CHANGELOG.json +++ b/packages/nimble-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@ni/nimble-components", "entries": [ + { + "date": "Thu, 29 Feb 2024 16:22:43 GMT", + "version": "21.8.0", + "tag": "@ni/nimble-components_v21.8.0", + "comments": { + "minor": [ + { + "author": "20542556+mollykreis@users.noreply.github.com", + "package": "@ni/nimble-components", + "commit": "d4ca92e5d7044d8be7b26ccbc52b91747663bfe2", + "comment": "Allow icon mappings to specify an undefined icon" + } + ] + } + }, { "date": "Thu, 29 Feb 2024 07:48:58 GMT", "version": "21.7.1", diff --git a/packages/nimble-components/CHANGELOG.md b/packages/nimble-components/CHANGELOG.md index e8f7ddece4..893eba37e9 100644 --- a/packages/nimble-components/CHANGELOG.md +++ b/packages/nimble-components/CHANGELOG.md @@ -1,9 +1,17 @@ # Change Log - @ni/nimble-components -This log was last generated on Wed, 28 Feb 2024 21:22:49 GMT and should not be manually modified. +This log was last generated on Thu, 29 Feb 2024 16:22:43 GMT and should not be manually modified. +## 21.8.0 + +Thu, 29 Feb 2024 16:22:43 GMT + +### Minor changes + +- Allow icon mappings to specify an undefined icon ([ni/nimble@d4ca92e](https://github.com/ni/nimble/commit/d4ca92e5d7044d8be7b26ccbc52b91747663bfe2)) + ## 21.7.1 Wed, 28 Feb 2024 21:22:49 GMT diff --git a/packages/nimble-components/package.json b/packages/nimble-components/package.json index 23208164f4..0594e123e6 100644 --- a/packages/nimble-components/package.json +++ b/packages/nimble-components/package.json @@ -1,6 +1,6 @@ { "name": "@ni/nimble-components", - "version": "21.7.1", + "version": "21.8.0", "description": "Styled web components for the NI Nimble Design System", "scripts": { "build": "npm run generate-icons && npm run generate-workers && npm run build-components && npm run bundle-components && npm run generate-scss && npm run build-storybook",