diff --git a/package-lock.json b/package-lock.json index b5541dd45..4dc366d52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "angular-components", - "version": "15.1.7", + "version": "15.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "angular-components", - "version": "15.1.7", + "version": "15.2.0", "license": "MIT", "dependencies": { "@angular/animations": "15.2.9", diff --git a/package.json b/package.json index ae708c4de..d110ced62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-components", - "version": "15.1.7", + "version": "15.2.0", "author": { "name": "UiPath Inc", "url": "https://uipath.com" diff --git a/projects/angular/components/ui-grid/src/models/dataModel.ts b/projects/angular/components/ui-grid/src/models/dataModel.ts index 4405d799c..53bb6eceb 100644 --- a/projects/angular/components/ui-grid/src/models/dataModel.ts +++ b/projects/angular/components/ui-grid/src/models/dataModel.ts @@ -30,4 +30,5 @@ export interface GridOptions { rowSize?: number; resizeStrategy?: ResizeStrategy; selectablePageIndex?: boolean; + hasHighDensity?: boolean; } 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 8a3d0550b..4baa801bb 100644 --- a/projects/angular/components/ui-grid/src/ui-grid.component.html +++ b/projects/angular/components/ui-grid/src/ui-grid.component.html @@ -743,6 +743,7 @@ { }); }); + @Component({ + template: ` + + + + + + + + + + + `, + }) + class TestFixtureGridWithHighDensityModeComponent { + @Input() + hasHighDensity: boolean | null = null; + + data: ITestEntity[] = []; + + @ViewChild(UiGridComponent, { + static: false, + }) + grid!: UiGridComponent; + } + + describe('Scenario: simple grid with high density mode', () => { + let fixture: ComponentFixture; + + afterEach(() => { + fixture.destroy(); + }); + + it('should have the default structure when the high density mode is OFF', () => { + TestBed.configureTestingModule({ + imports: [UiGridModule], + declarations: [TestFixtureGridWithHighDensityModeComponent], + }); + + const data = generateListFactory(generateEntity, TestBed.runInInjectionContext)(1); + fixture = TestBed.createComponent(TestFixtureGridWithHighDensityModeComponent); + fixture.componentInstance.data = data; + fixture.detectChanges(); + + const grid = fixture.componentInstance.grid; + + expect(Object.keys(fixture.debugElement.classes).includes('ui-grid-state-high-density')).toBeFalsy(); + expect(grid.rowSize).toBe(48); + + const contentRow = fixture.debugElement.query(By.css('.ui-grid-row')).nativeElement; + expect(getComputedStyle(contentRow).height).toBe('48px'); + }); + + it('should have the correct structure when the high density mode is set by the provider', () => { + TestBed.configureTestingModule({ + imports: [UiGridModule], + providers: [ + { + provide: UI_GRID_OPTIONS, + useValue: { hasHighDensity: true }, + }, + ], + declarations: [TestFixtureGridWithHighDensityModeComponent], + }); + + const data = generateListFactory(generateEntity, TestBed.runInInjectionContext)(1); + fixture = TestBed.createComponent(TestFixtureGridWithHighDensityModeComponent); + fixture.componentInstance.data = data; + fixture.detectChanges(); + + const grid = fixture.componentInstance.grid; + const gridElement = fixture.debugElement.queryAll(By.css('ui-grid'))[0]; + + expect(Object.keys(gridElement.classes).includes('ui-grid-state-high-density')).toBeTruthy(); + expect(grid.rowSize).toBe(32); + + const headerRow = fixture.debugElement.query(By.css('.ui-grid-header-row')).nativeElement; + expect(getComputedStyle(headerRow).height).toBe('32px'); + const contentRow = fixture.debugElement.query(By.css('.ui-grid-row')).nativeElement; + expect(getComputedStyle(contentRow).height).toBe('32px'); + }); + + it('should have the correct structure when the high density mode is set by input', () => { + TestBed.configureTestingModule({ + imports: [UiGridModule], + providers: [ + { + provide: UI_GRID_OPTIONS, + useValue: { hasHighDensity: true }, + }, + ], + declarations: [TestFixtureGridWithHighDensityModeComponent], + }); + + fixture = TestBed.createComponent(TestFixtureGridWithHighDensityModeComponent); + fixture.componentInstance.hasHighDensity = false; + fixture.detectChanges(); + + const grid = fixture.componentInstance.grid; + const gridElement = fixture.debugElement.queryAll(By.css('ui-grid'))[0]; + + expect(Object.keys(gridElement.classes).includes('ui-grid-state-high-density')).toBeFalsy(); + expect(grid.rowSize).toBe(48); + }); + }); + @Component({ template: ` diff --git a/projects/angular/components/ui-grid/src/ui-grid.component.ts b/projects/angular/components/ui-grid/src/ui-grid.component.ts index 980bbfe27..9c3a5979a 100644 --- a/projects/angular/components/ui-grid/src/ui-grid.component.ts +++ b/projects/angular/components/ui-grid/src/ui-grid.component.ts @@ -1,3 +1,4 @@ +import isArray from 'lodash-es/isArray'; import range from 'lodash-es/range'; import { animationFrameScheduler, @@ -50,6 +51,7 @@ import { NgZone, OnChanges, OnDestroy, + OnInit, Optional, Output, QueryList, @@ -68,7 +70,6 @@ import { ISuggestValueData, } from '@uipath/angular/components/ui-suggest'; -import { isArray } from 'lodash-es'; import { UiGridColumnDirective } from './body/ui-grid-column.directive'; import { UiGridExpandedRowDirective } from './body/ui-grid-expanded-row.directive'; import { UiGridLoadingDirective } from './body/ui-grid-loading.directive'; @@ -112,6 +113,7 @@ const FOCUSABLE_ELEMENTS_QUERY = 'a, button:not([hidden]), input:not([hidden]), const EXCLUDED_ROW_SELECTION_ELEMENTS = ['a', 'button', 'input', 'textarea', 'select']; const REFRESH_WIDTH = 50; const DEFAULT_VIRTUAL_SCROLL_ITEM_SIZE = 48; +const DEFAULT_VIRTUAL_SCROLL_HIGH_DENSITY_ITEM_SIZE = 32; @Component({ selector: 'ui-grid', @@ -158,7 +160,7 @@ const DEFAULT_VIRTUAL_SCROLL_ITEM_SIZE = 48; }) export class UiGridComponent extends ResizableGrid - implements AfterContentInit, OnChanges, OnDestroy { + implements AfterContentInit, OnChanges, OnDestroy, OnInit { /** * The data list that needs to be rendered within the grid. * @@ -190,6 +192,14 @@ export class UiGridComponent @Input() isProjected: boolean; + /** + * Set the grid in high density state. + * + */ + @HostBinding('class.ui-grid-state-high-density') + @Input() + hasHighDensity = false; + /** * Determines if all of the items are currently checked. * @@ -910,7 +920,8 @@ export class UiGridComponent this.disableSelectionByEntry = () => null; this._fetchStrategy = _gridOptions?.fetchStrategy ?? 'onOpen'; - this.rowSize = _gridOptions?.rowSize ?? DEFAULT_VIRTUAL_SCROLL_ITEM_SIZE; + this.rowSize = _gridOptions?.rowSize ?? -1; + this.hasHighDensity = this._gridOptions?.hasHighDensity ?? false; this._collapseFiltersCount$ = new BehaviorSubject( _gridOptions?.collapseFiltersCount ?? (_gridOptions?.collapsibleFilters === true ? 0 : Number.POSITIVE_INFINITY), ); @@ -1021,6 +1032,10 @@ export class UiGridComponent return of(true); }; + ngOnInit(): void { + this._setInitialRowSize(); + } + /** * @ignore */ @@ -1078,7 +1093,6 @@ export class UiGridComponent } const dataChange = changes.data; - if ( dataChange && !dataChange.firstChange && @@ -1380,4 +1394,12 @@ export class UiGridComponent } } } + + private _setInitialRowSize() { + if (this.rowSize === -1) { + this.rowSize = this.hasHighDensity ? + DEFAULT_VIRTUAL_SCROLL_HIGH_DENSITY_ITEM_SIZE : + DEFAULT_VIRTUAL_SCROLL_ITEM_SIZE; + } + } } diff --git a/projects/angular/components/ui-suggest/src/ui-suggest.component.scss b/projects/angular/components/ui-suggest/src/ui-suggest.component.scss index 23e330ae0..8da19e5e7 100644 --- a/projects/angular/components/ui-suggest/src/ui-suggest.component.scss +++ b/projects/angular/components/ui-suggest/src/ui-suggest.component.scss @@ -1,6 +1,5 @@ @import "../../styles/ellipse"; -$height: 40px; $item-height: 32px; $form-control-height: 18px; $display-padding: 15px; @@ -14,6 +13,13 @@ $ui-suggest-focus-transition: background-color 200ms cubic-bezier(0.35, 0, 0.25, $componentName: "ui-suggest"; #{$componentName} { + --ui-suggest-height: 40px; + --ui-suggest-list-item-height: 40px; + + &.ui-suggest-state-high-density { + --ui-suggest-height: 32px; + } + height: 100%; position: relative; display: block; @@ -99,8 +105,8 @@ $componentName: "ui-suggest"; } .display { - height: $height; - line-height: $height; + height: var(--ui-suggest-height); + line-height: var(--ui-suggest-height); transition: $ui-suggest-focus-transition; padding: 0 6px 0 16px; @@ -155,9 +161,9 @@ $componentName: "ui-suggest"; &:not(.is-form-control) { .mat-mdc-list { &-item { - height: $height; + height: var(--ui-suggest-list-item-height); &.text-ellipsis .mdc-list-item__content { - line-height: $height; + line-height: var(--ui-suggest-list-item-height); } &.no-results-text .mdc-list-item__content { font-size: 14px; @@ -193,7 +199,7 @@ $componentName: "ui-suggest"; padding: 0 $field-padding; width: calc(100% - #{$field-padding * 2}) !important; margin: 0 !important; - height: $height; + height: var(--ui-suggest-list-item-height); &-infix { border: 7px solid transparent; border-left: none; diff --git a/projects/angular/components/ui-suggest/src/ui-suggest.component.spec.ts b/projects/angular/components/ui-suggest/src/ui-suggest.component.spec.ts index 2ebdabc37..ecd71aa06 100644 --- a/projects/angular/components/ui-suggest/src/ui-suggest.component.spec.ts +++ b/projects/angular/components/ui-suggest/src/ui-suggest.component.spec.ts @@ -22,6 +22,7 @@ import { Component, DebugElement, Directive, + Input, ViewChild, } from '@angular/core'; import { @@ -3311,4 +3312,52 @@ describe('Component: UiSuggest', () => { }); }); }); + + @Component({ + template: ` + + + + + + `, + }) + class UiSuggestFixtureWithHighDensityComponent extends UiSuggestFixtureDirective { + @Input() + hasHighDensity: boolean | null = null; + } + describe('Scenario: standalone component with high density mode', () => { + it('should have high density mode turned OFF by default', () => { + TestBed.configureTestingModule({ + imports: [UiSuggestModule], + declarations: [UiSuggestFixtureWithHighDensityComponent], + }); + + const fixture = TestBed.createComponent(UiSuggestFixtureWithHighDensityComponent); + fixture.detectChanges(); + + expect(Object.keys(fixture.debugElement.classes).includes('ui-suggest-state-high-density')).toBeFalsy(); + + const container = fixture.debugElement.query(By.css('.ui-suggest-container')).nativeElement; + expect(getComputedStyle(container).height).toBe('40px'); + }); + + it('should generate the correct html in high density mode', () => { + TestBed.configureTestingModule({ + imports: [UiSuggestModule], + declarations: [UiSuggestFixtureWithHighDensityComponent], + }); + + const fixture = TestBed.createComponent(UiSuggestFixtureWithHighDensityComponent); + fixture.componentInstance.hasHighDensity = true; + fixture.detectChanges(); + + const appliedClasses = Object.keys(fixture.debugElement.query(By.css('ui-suggest')).classes); + expect(appliedClasses.includes('ui-suggest-state-high-density')).toBeTruthy(); + + const container = fixture.debugElement.query(By.css('.ui-suggest-container')).nativeElement; + expect(getComputedStyle(container).height).toBe('32px'); + }); + }); }); diff --git a/projects/angular/components/ui-suggest/src/ui-suggest.component.ts b/projects/angular/components/ui-suggest/src/ui-suggest.component.ts index 51c51660d..53a84540c 100644 --- a/projects/angular/components/ui-suggest/src/ui-suggest.component.ts +++ b/projects/angular/components/ui-suggest/src/ui-suggest.component.ts @@ -184,6 +184,14 @@ export class UiSuggestComponent extends UiSuggestMatFormFieldDirective this._cd.detectChanges(); } + /** + * Set the element in high density state. + * + */ + @HostBinding('class.ui-suggest-state-high-density') + @Input() + hasHighDensity = false; + /** * By default the onOpen fetchStrategy prevents additional requests if closed. * This allows you to bypass that check and update even if closed. diff --git a/projects/angular/package.json b/projects/angular/package.json index bc931d368..558e8c21e 100644 --- a/projects/angular/package.json +++ b/projects/angular/package.json @@ -1,6 +1,6 @@ { "name": "@uipath/angular", - "version": "15.1.7", + "version": "15.2.0", "license": "MIT", "author": { "name": "UiPath Inc", 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 5d38b6e70..523ac303c 100644 --- a/projects/playground/src/app/pages/grid/component/grid.component.html +++ b/projects/playground/src/app/pages/grid/component/grid.component.html @@ -2,6 +2,7 @@ [collapsibleFilters]="inputs.collapsibleFilters ?? false" [collapseFiltersCount]="inputs.collapseFiltersCount" [isProjected]="inputs.isProjected" + [hasHighDensity]="inputs.hasHighDensity" [loading]="inputs.loading" [disabled]="inputs.disabled" [selectable]="inputs.selectable" diff --git a/projects/playground/src/app/pages/grid/component/grid.component.ts b/projects/playground/src/app/pages/grid/component/grid.component.ts index 9ad953356..96e4b9d87 100644 --- a/projects/playground/src/app/pages/grid/component/grid.component.ts +++ b/projects/playground/src/app/pages/grid/component/grid.component.ts @@ -91,6 +91,9 @@ export class GridComponent implements OnInit, OnDestroy, AfterViewInit { this.total = this.footer.total; this.filteredData = cloneDeep(this.allData); this.paginateData(this.filteredData, this.pageIndex, this.footer.pageSize); + if (this.inputs.hasHighDensity) { + this.pageSizes = [10, 25, 50, 100]; + } } ngAfterViewInit() { diff --git a/projects/playground/src/app/pages/grid/grid.models.ts b/projects/playground/src/app/pages/grid/grid.models.ts index b434fad09..2dbefea48 100644 --- a/projects/playground/src/app/pages/grid/grid.models.ts +++ b/projects/playground/src/app/pages/grid/grid.models.ts @@ -20,6 +20,7 @@ export interface IInputs { collapsibleFilters?: boolean; loading: boolean; isProjected: boolean; + hasHighDensity: boolean; disabled: boolean; selectable: boolean; singleSelectable: boolean; diff --git a/projects/playground/src/app/pages/grid/grid.page.ts b/projects/playground/src/app/pages/grid/grid.page.ts index 7df0da3e5..4ba5546c7 100644 --- a/projects/playground/src/app/pages/grid/grid.page.ts +++ b/projects/playground/src/app/pages/grid/grid.page.ts @@ -53,6 +53,7 @@ export class GridPageComponent implements AfterViewInit, OnDestroy { 'collapseFiltersCount', 'loading', 'isProjected', + 'hasHighDensity', 'disabled', 'selectable', 'singleSelectable', @@ -119,6 +120,7 @@ export class GridPageComponent implements AfterViewInit, OnDestroy { collapseFiltersCount: [20, [Validators.min(0), Validators.max(500)]], loading: [false], isProjected: [false], + hasHighDensity: [false], disabled: [false], selectable: [true], singleSelectable: [false],