From 2012e50b67ae5ee311532150436e4a3fa8ce0265 Mon Sep 17 00:00:00 2001 From: Catalin Date: Wed, 24 May 2023 15:25:48 +0300 Subject: [PATCH 1/5] feat(grid): add radio btn select --- .../ui-grid/src/ui-grid.component.html | 71 +++++++++++-------- .../ui-grid/src/ui-grid.component.ts | 12 ++++ .../components/ui-grid/src/ui-grid.module.ts | 4 +- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/projects/angular/components/ui-grid/src/ui-grid.component.html b/projects/angular/components/ui-grid/src/ui-grid.component.html index 80ed73326..4559474a6 100644 --- a/projects/angular/components/ui-grid/src/ui-grid.component.html +++ b/projects/angular/components/ui-grid/src/ui-grid.component.html @@ -122,7 +122,7 @@
-
- {{ column.title }}

+ {{ column.title }} +

- -
+
+ +
+
@@ -358,22 +364,26 @@
-
- - + + + + + +
@@ -444,18 +454,17 @@ + let-row="data" + let-expanded="expanded" + let-last="last" + let-index="index">
+ class="ui-grid-card-wrapper" + [ngClass]="rowConfig?.ngClassFn(row) ?? ''" + [tabIndex]="0" + [attr.data-row-index]="index" + (click)="onRowClick($event, row)" + (keyup.enter)="onRowClick($event, row)"> + let-row="data" + let-index="index">
extends ResizableGrid @Input() selectable = true; + /** + * Configure if the grid allows radio button selection its items. + * + */ + @Input() + singleSelectable = true; + /** * Option to select an alternate layout for footer pagination. * @@ -1068,6 +1075,11 @@ export class UiGridComponent extends ResizableGrid activeItem?.focus(); } + rowSelected(row: T) { + this.selectionManager.clear(); + this.selectionManager.select(row); + } + private _announceGridHeaderActions() { this._queuedAnnouncer.enqueue(this.intl.gridHeaderActionsNotice); } diff --git a/projects/angular/components/ui-grid/src/ui-grid.module.ts b/projects/angular/components/ui-grid/src/ui-grid.module.ts index 59bad8556..48680a059 100644 --- a/projects/angular/components/ui-grid/src/ui-grid.module.ts +++ b/projects/angular/components/ui-grid/src/ui-grid.module.ts @@ -8,6 +8,7 @@ import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatRadioModule } from '@angular/material/radio'; import { MatSelectModule } from '@angular/material/select'; import { MatTooltipModule } from '@angular/material/tooltip'; import { UiAutoAccessibleLabelModule } from '@uipath/angular/a11y'; @@ -21,8 +22,8 @@ import { UiGridExpandedRowDirective } from './body/ui-grid-expanded-row.directiv import { UiGridLoadingDirective } from './body/ui-grid-loading.directive'; import { UiGridNoContentDirective } from './body/ui-grid-no-content.directive'; import { UiGridRowActionDirective } from './body/ui-grid-row-action.directive'; -import { UiGridRowConfigDirective } from './body/ui-grid-row-config.directive'; import { UiGridRowCardViewDirective } from './body/ui-grid-row-card-view.directive'; +import { UiGridRowConfigDirective } from './body/ui-grid-row-config.directive'; import { UiGridCustomPaginatorModule } from './components/ui-grid-custom-paginator/ui-grid-custom-paginator.module'; import { UiGridSearchModule } from './components/ui-grid-search/ui-grid-search.module'; import { UiGridToggleColumnsModule } from './components/ui-grid-toggle-columns/ui-grid-toggle-columns.module'; @@ -44,6 +45,7 @@ import { UiGridComponent } from './ui-grid.component'; MatSelectModule, MatTooltipModule, MatProgressBarModule, + MatRadioModule, ScrollingModule, UiGridSearchModule, UiGridToggleColumnsModule, From f8e064e81aefda8a45bc65ab61e59cdfc6d44590 Mon Sep 17 00:00:00 2001 From: Catalin Date: Wed, 24 May 2023 15:26:15 +0300 Subject: [PATCH 2/5] chore(playground): add singleSelectable input --- .../angular/components/ui-grid/src/ui-grid.component.html | 2 +- projects/angular/components/ui-grid/src/ui-grid.component.ts | 4 ++-- .../src/app/pages/grid/component/grid.component.html | 1 + projects/playground/src/app/pages/grid/grid.models.ts | 1 + projects/playground/src/app/pages/grid/grid.page.ts | 2 ++ 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/projects/angular/components/ui-grid/src/ui-grid.component.html b/projects/angular/components/ui-grid/src/ui-grid.component.html index 4559474a6..5644bba9d 100644 --- a/projects/angular/components/ui-grid/src/ui-grid.component.html +++ b/projects/angular/components/ui-grid/src/ui-grid.component.html @@ -350,7 +350,7 @@
- +
extends ResizableGrid selectable = true; /** - * Configure if the grid allows radio button selection its items. + * Configure if the grid allows radio button selection for its items. * */ @Input() - singleSelectable = true; + singleSelectable = false; /** * Option to select an alternate layout for footer pagination. diff --git a/projects/playground/src/app/pages/grid/component/grid.component.html b/projects/playground/src/app/pages/grid/component/grid.component.html index 01675ccc5..6427fb911 100644 --- a/projects/playground/src/app/pages/grid/component/grid.component.html +++ b/projects/playground/src/app/pages/grid/component/grid.component.html @@ -6,6 +6,7 @@ [loading]="inputs.loading" [disabled]="inputs.disabled" [selectable]="inputs.selectable" + [singleSelectable]="inputs.singleSelectable" [toggleColumns]="inputs.toggleColumns" [multiPageSelect]="inputs.multiPageSelect" [refreshable]="inputs.refreshable" diff --git a/projects/playground/src/app/pages/grid/grid.models.ts b/projects/playground/src/app/pages/grid/grid.models.ts index f42b53c0f..835704897 100644 --- a/projects/playground/src/app/pages/grid/grid.models.ts +++ b/projects/playground/src/app/pages/grid/grid.models.ts @@ -23,6 +23,7 @@ export interface IInputs { isProjected: boolean; disabled: boolean; selectable: boolean; + singleSelectable: boolean; toggleColumns: boolean; multiPageSelect: boolean; refreshable: boolean; diff --git a/projects/playground/src/app/pages/grid/grid.page.ts b/projects/playground/src/app/pages/grid/grid.page.ts index 0718c70ce..a20c5a589 100644 --- a/projects/playground/src/app/pages/grid/grid.page.ts +++ b/projects/playground/src/app/pages/grid/grid.page.ts @@ -46,6 +46,7 @@ export class GridPageComponent implements AfterViewInit { 'isProjected', 'disabled', 'selectable', + 'singleSelectable', 'toggleColumns', 'multiPageSelect', 'refreshable', @@ -102,6 +103,7 @@ export class GridPageComponent implements AfterViewInit { isProjected: [false], disabled: [false], selectable: [true], + singleSelectable: [false], toggleColumns: [false], multiPageSelect: [false], refreshable: [true], From 52d2a12d7883bb742f073647bc9d0f96eeeddc73 Mon Sep 17 00:00:00 2001 From: Catalin Date: Thu, 25 May 2023 11:54:06 +0300 Subject: [PATCH 3/5] chore(grid): add tests for radio selection --- .../ui-grid/src/ui-grid.component.spec.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/projects/angular/components/ui-grid/src/ui-grid.component.spec.ts b/projects/angular/components/ui-grid/src/ui-grid.component.spec.ts index a490bc12c..60c3756aa 100644 --- a/projects/angular/components/ui-grid/src/ui-grid.component.spec.ts +++ b/projects/angular/components/ui-grid/src/ui-grid.component.spec.ts @@ -70,6 +70,7 @@ describe('Component: UiGrid', () => { [disableSelectionByEntry]="disableSelectionByEntry" [refreshable]="refreshable" [selectable]="selectable" + [singleSelectable]="singleSelectable" [showHeaderRow]="showHeaderRow" [virtualScroll]="virtualScroll"> { isColumnVisible = true; isFilterVisible = true; selectable?: boolean; + singleSelectable?: boolean; refreshable?: boolean; showHeaderRow = true; virtualScroll = false; @@ -483,6 +485,40 @@ describe('Component: UiGrid', () => { }); }); + describe('Feature: radio button selection', () => { + beforeEach(() => { + component.selectable = false; + component.singleSelectable = true; + fixture.detectChanges(); + }); + + it('should have correct selection', () => { + const radioBtns = fixture.debugElement.queryAll(By.css('.mat-radio-label')); + expect(radioBtns.length).toEqual(50); + + const firstRadioBtn = radioBtns[0]; + firstRadioBtn.nativeElement.dispatchEvent(EventGenerator.click); + fixture.detectChanges(); + + expect(component.grid.selectionManager.selected[0].id).toEqual(component.data[0].id); + }); + + it('should have only one selection', () => { + const radioBtns = fixture.debugElement.queryAll(By.css('.mat-radio-label')); + + const firstRadioBtn = radioBtns[0]; + firstRadioBtn.nativeElement.dispatchEvent(EventGenerator.click); + fixture.detectChanges(); + + const secondRadioBtn = radioBtns[1]; + secondRadioBtn.nativeElement.dispatchEvent(EventGenerator.click); + fixture.detectChanges(); + + expect(component.grid.selectionManager.selected[0].id).toEqual(component.data[1].id); + expect(component.grid.selectionManager.selected.length).toEqual(1); + }); + }); + describe('Feature: checkbox', () => { it('should have ariaLabel set correctly for toggle selection', () => { const checkboxHeader = fixture.debugElement.query(By.css('.ui-grid-header-cell.ui-grid-checkbox-cell')); From 5117a279d3da1debfe5fd39fc3c7755bc7de2e56 Mon Sep 17 00:00:00 2001 From: Catalin Date: Fri, 26 May 2023 17:58:31 +0300 Subject: [PATCH 4/5] feat(grid): add tooltips & disable state for radio selection --- .../ui-grid/src/ui-grid.component.html | 84 ++++++++++--------- .../ui-grid/src/ui-grid.component.spec.ts | 53 +++++++++++- 2 files changed, 96 insertions(+), 41 deletions(-) diff --git a/projects/angular/components/ui-grid/src/ui-grid.component.html b/projects/angular/components/ui-grid/src/ui-grid.component.html index 5644bba9d..49458f6a3 100644 --- a/projects/angular/components/ui-grid/src/ui-grid.component.html +++ b/projects/angular/components/ui-grid/src/ui-grid.component.html @@ -166,7 +166,7 @@ [attr.aria-label]="column.title + (column.description ? ('. ' + column.description) : '') + (column.sortable && intl.sortableMessage ? '. ' + intl.sortableMessage : '')" matTooltipClass="preserve-whitespace"> {{ column.title }} -

+

-
- - -
-
- -
- + +
+ + +
+
+ +
+
@@ -367,23 +371,27 @@
- - - - - - + + + + + + +
diff --git a/projects/angular/components/ui-grid/src/ui-grid.component.spec.ts b/projects/angular/components/ui-grid/src/ui-grid.component.spec.ts index 60c3756aa..7fcf5f6f0 100644 --- a/projects/angular/components/ui-grid/src/ui-grid.component.spec.ts +++ b/projects/angular/components/ui-grid/src/ui-grid.component.spec.ts @@ -517,6 +517,55 @@ describe('Component: UiGrid', () => { expect(component.grid.selectionManager.selected[0].id).toEqual(component.data[1].id); expect(component.grid.selectionManager.selected.length).toEqual(1); }); + + it('should have preselected option displayed', () => { + const randomIdx = faker.random.number({ max: 49 }); + grid.selectionManager.select(data[randomIdx]); + fixture.detectChanges(); + const radioBtns = fixture.debugElement.queryAll(By.css('[role="gridcell"] mat-radio-button')); + const checkedRadioBtn = radioBtns[randomIdx]; + expect(checkedRadioBtn.nativeElement.classList.contains('mat-radio-checked')).toBeTruthy(); + }); + + it('should display Select / Deselect according to button state', () => { + const checkedBtnIdx = faker.random.number({ max: 25 }); + const uncheckedBtnIdx = faker.random.number({ + min: 26, + max: 49, + }); + grid.selectionManager.select(data[checkedBtnIdx]); + fixture.detectChanges(); + const radioBtns = fixture.debugElement.queryAll(By.css('[role="gridcell"] mat-radio-button')); + const checkedRadioBtn = radioBtns[checkedBtnIdx].nativeElement; + const uncheckedRadioBtn = radioBtns[uncheckedBtnIdx].nativeElement; + expect(checkedRadioBtn.getAttribute('ng-reflect-message')).toEqual(`Deselect row ${checkedBtnIdx}`); + expect(uncheckedRadioBtn.getAttribute('ng-reflect-message')).toEqual(`Select row ${uncheckedBtnIdx}`); + }); + + it('should disable radio btn according to disableSelectionByEntry', () => { + const selectableBtnIdx = faker.random.number({ max: 25 }); + const disabledBtnIdx = faker.random.number({ + min: 26, + max: 49, + }); + const disableSelectionByEntry = (entry?: ITestEntity) => entry && entry.id === data[disabledBtnIdx].id + ? 'unselectable' + : null; + + component.disableSelectionByEntry = disableSelectionByEntry; + grid.selectionManager.disableSelectionByEntry = disableSelectionByEntry; + fixture.detectChanges(); + + const radioBtns = fixture.debugElement.queryAll(By.css('[role="gridcell"] mat-radio-button')); + const selectableRadioBtn = radioBtns[selectableBtnIdx].nativeElement; + const disabledRadioBtn = radioBtns[disabledBtnIdx].nativeElement; + + expect(selectableRadioBtn.getAttribute('ng-reflect-message')).toEqual(`Select row ${selectableBtnIdx}`); + expect(selectableRadioBtn.classList.contains('mat-radio-disabled')).toBeFalsy(); + + expect(disabledRadioBtn.getAttribute('ng-reflect-message')).toEqual(`unselectable`); + expect(disabledRadioBtn.classList.contains('mat-radio-disabled')).toBeTruthy(); + }); }); describe('Feature: checkbox', () => { @@ -831,7 +880,7 @@ describe('Component: UiGrid', () => { expect(matCheckbox.checked).toEqual(false); }); - it('should unselect heade checkbox if all grid rows are unselected', () => { + it('should unselect header checkbox if all grid rows are unselected', () => { const disableSelectionByEntry = (entry?: ITestEntity) => entry && entry.id % 2 === 1 ? 'unselectable' : null; component.disableSelectionByEntry = disableSelectionByEntry; @@ -4374,10 +4423,8 @@ describe('Component: UiGrid', () => { }); it('should render provided card template', () => { - const cardContainer = fixture.debugElement.query(By.css('.expanded-row')); - console.log(cardContainer); expect(cardContainer).toBeDefined(); expect(cardContainer.nativeElement.querySelector('[data-property="myNumber"]')).toBeDefined(); expect(cardContainer.nativeElement.querySelector('[data-property="myBool"]')).toBeDefined(); From ef3c5c5cffae72cd41b4ddae70aa9939829021b4 Mon Sep 17 00:00:00 2001 From: Catalin Date: Mon, 29 May 2023 12:43:18 +0300 Subject: [PATCH 5/5] chore: bump version --- CHANGELOG.md | 6 ++++++ package-lock.json | 4 ++-- package.json | 2 +- projects/angular/package.json | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a23e10978..d6eb2cac1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v14.8.1 (2023-05-29) +* **grid** add tooltips & disable state for radio selection +* **grid** add tests for radio selection +* **grid** add singleSelectable input +* **grid** add radio btn select + # v14.8.0 (2023-05-29) * **suggest** changed in EventEmitter * **suggest** added item selected output diff --git a/package-lock.json b/package-lock.json index 96a8f8ad1..4ce34c199 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "angular-components", - "version": "14.8.0", + "version": "14.8.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "angular-components", - "version": "14.8.0", + "version": "14.8.1", "license": "MIT", "dependencies": { "@angular/animations": "14.2.12", diff --git a/package.json b/package.json index 5d63b8857..73c0185cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-components", - "version": "14.8.0", + "version": "14.8.1", "author": { "name": "UiPath Inc", "url": "https://uipath.com" diff --git a/projects/angular/package.json b/projects/angular/package.json index a7b0e9013..028e4a9fc 100644 --- a/projects/angular/package.json +++ b/projects/angular/package.json @@ -1,6 +1,6 @@ { "name": "@uipath/angular", - "version": "14.8.0", + "version": "14.8.1", "license": "MIT", "author": { "name": "UiPath Inc",