From a3d1a968d8a37442146220a7691acad38b13683b Mon Sep 17 00:00:00 2001 From: John White <750350+johnhwhite@users.noreply.github.com> Date: Tue, 9 Jul 2024 17:00:50 -0400 Subject: [PATCH 1/5] ci: update changelog cherry-pick message (#2451) --- .github/workflows/cherry-pick.yml | 4 +++- package-lock.json | 6 +++--- package.json | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cherry-pick.yml b/.github/workflows/cherry-pick.yml index 091020596a..8737e15e0c 100644 --- a/.github/workflows/cherry-pick.yml +++ b/.github/workflows/cherry-pick.yml @@ -72,6 +72,8 @@ jobs: echo "CHERRY_PICK_RESULT=failed" >> $GITHUB_ENV exit 0 fi + + echo "COMMIT_MESSAGE=$(git log -1 --pretty=%B)" >> $GITHUB_ENV env: GH_TOKEN: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} @@ -91,7 +93,7 @@ jobs: repo: context.repo.repo, head: process.env.CHERRY_PICK_BRANCH, base: process.env.TARGET_BRANCH, - title: `${pr.title} (#${pr.number})`, + title: `${process.env.COMMIT_MESSAGE} (#${pr.number})`, body }).then(result => { console.log(`Created PR #${result.data.number}: ${result.data.html_url}`); diff --git a/package-lock.json b/package-lock.json index 9817f6dc16..99cc66a7bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,7 +75,7 @@ "@ryansonshine/commitizen": "4.2.8", "@ryansonshine/cz-conventional-changelog": "3.3.4", "@schematics/angular": "17.3.2", - "@skyux/dev-infra-private": "github:blackbaud/skyux-dev-infra-private-builds#10.0.0-alpha.5", + "@skyux/dev-infra-private": "github:blackbaud/skyux-dev-infra-private-builds#10.0.0-alpha.7", "@storybook/addon-a11y": "8.1.10", "@storybook/addon-actions": "8.1.10", "@storybook/addon-controls": "8.1.10", @@ -9146,8 +9146,8 @@ } }, "node_modules/@skyux/dev-infra-private": { - "version": "10.0.0-alpha.5", - "resolved": "git+ssh://git@github.com/blackbaud/skyux-dev-infra-private-builds.git#a0b36ddd4de5723ddff68659439e305544f4456e", + "version": "10.0.0-alpha.7", + "resolved": "git+ssh://git@github.com/blackbaud/skyux-dev-infra-private-builds.git#8f26d24cfaee3d0c6eddb1f5d5eecb31f430bb50", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 2a0833d69e..fc4f7b5415 100644 --- a/package.json +++ b/package.json @@ -153,7 +153,7 @@ "@ryansonshine/commitizen": "4.2.8", "@ryansonshine/cz-conventional-changelog": "3.3.4", "@schematics/angular": "17.3.2", - "@skyux/dev-infra-private": "github:blackbaud/skyux-dev-infra-private-builds#10.0.0-alpha.5", + "@skyux/dev-infra-private": "github:blackbaud/skyux-dev-infra-private-builds#10.0.0-alpha.7", "@storybook/addon-a11y": "8.1.10", "@storybook/addon-actions": "8.1.10", "@storybook/addon-controls": "8.1.10", From b228868a59b14715b09dc278c1fcf00829ea674e Mon Sep 17 00:00:00 2001 From: Paul Crowder Date: Wed, 10 Jul 2024 10:03:19 -0400 Subject: [PATCH 2/5] chore(components/indicators): split expansion indicator styles (#2453) --- .../expansion-indicator.component.ts | 5 +- ...xpansion-indicator.default.component.scss} | 47 ++----------- .../expansion-indicator.modern.component.scss | 70 +++++++++++++++++++ 3 files changed, 78 insertions(+), 44 deletions(-) rename libs/components/indicators/src/lib/modules/expansion-indicator/{expansion-indicator.component.scss => expansion-indicator.default.component.scss} (55%) create mode 100644 libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.modern.component.scss diff --git a/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.component.ts b/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.component.ts index 290f311878..de6205e565 100644 --- a/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.component.ts +++ b/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.component.ts @@ -6,7 +6,10 @@ import { Component, Input } from '@angular/core'; */ @Component({ selector: 'sky-expansion-indicator', - styleUrls: ['./expansion-indicator.component.scss'], + styleUrls: [ + './expansion-indicator.default.component.scss', + './expansion-indicator.modern.component.scss', + ], templateUrl: './expansion-indicator.component.html', }) export class SkyExpansionIndicatorComponent { diff --git a/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.component.scss b/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.default.component.scss similarity index 55% rename from libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.component.scss rename to libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.default.component.scss index b794266009..5ef833b1bd 100644 --- a/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.component.scss +++ b/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.default.component.scss @@ -1,7 +1,7 @@ @use 'libs/components/theme/src/lib/styles/mixins' as mixins; @use 'libs/components/theme/src/lib/styles/variables' as *; -.sky-expansion-indicator { +@include mixins.sky-component('default', '.sky-expansion-indicator') { display: inline-block; border: none; background-color: transparent; @@ -14,7 +14,7 @@ vertical-align: top; } -.sky-expansion-indicator-part { +@include mixins.sky-component('default', '.sky-expansion-indicator-part') { border-color: $sky-text-color-icon-borderless; border-style: solid; border-width: 3px 0 0 0; @@ -29,7 +29,7 @@ width: 10px; } -.sky-expansion-indicator-up { +@include mixins.sky-component('default', '.sky-expansion-indicator-up') { .sky-expansion-indicator-left { left: 7px; transform: rotate(-45deg); @@ -41,7 +41,7 @@ } } -.sky-expansion-indicator-down { +@include mixins.sky-component('default', '.sky-expansion-indicator-down') { .sky-expansion-indicator-left { left: 2px; transform: rotate(45deg); @@ -52,42 +52,3 @@ transform: rotate(-45deg); } } - -@include mixins.sky-theme-modern { - .sky-expansion-indicator { - height: 26px; - width: 26px; - } - - .sky-expansion-indicator-part { - background: $sky-theme-modern-font-deemphasized-color; - border: none; - height: 2px; - width: 11px; - top: 13px; - } - - .sky-expansion-indicator-glyph-container { - transform: scale(0.68); - display: inline-block; - position: absolute; - top: 3.5px; - left: 4px; - } - - .sky-expansion-indicator-left { - border-radius: 1px 0 0 1px; - } - - .sky-expansion-indicator-right { - border-radius: 0 1px 1px 0; - } - - .sky-expansion-indicator-left { - left: 4px; - } - - .sky-expansion-indicator-right { - left: 10.5px; - } -} diff --git a/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.modern.component.scss b/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.modern.component.scss new file mode 100644 index 0000000000..03422a184f --- /dev/null +++ b/libs/components/indicators/src/lib/modules/expansion-indicator/expansion-indicator.modern.component.scss @@ -0,0 +1,70 @@ +@use 'libs/components/theme/src/lib/styles/mixins' as mixins; +@use 'libs/components/theme/src/lib/styles/variables' as *; + +@include mixins.sky-component('modern', '.sky-expansion-indicator') { + display: inline-block; + border: none; + background-color: transparent; + flex-shrink: 0; + height: 26px; + margin: 0; + overflow: hidden; + position: relative; + vertical-align: top; + width: 26px; +} + +@include mixins.sky-component('modern', '.sky-expansion-indicator-part') { + background: $sky-theme-modern-font-deemphasized-color; + border: none; + display: inline-block; + height: 2px; + position: absolute; + top: 13px; + transition: + transform $sky-transition-time-medium, + left $sky-transition-time-medium; + vertical-align: top; + width: 11px; +} + +@include mixins.sky-component( + 'modern', + '.sky-expansion-indicator-glyph-container' +) { + left: 4px; + display: inline-block; + position: absolute; + top: 3.5px; + transform: scale(0.68); +} + +@include mixins.sky-component('modern', '.sky-expansion-indicator-left') { + border-radius: 1px 0 0 1px; + left: 4px; +} + +@include mixins.sky-component('modern', '.sky-expansion-indicator-right') { + border-radius: 0 1px 1px 0; + left: 10.5px; +} + +@include mixins.sky-component('modern', '.sky-expansion-indicator-up') { + .sky-expansion-indicator-left { + transform: rotate(-45deg); + } + + .sky-expansion-indicator-right { + transform: rotate(45deg); + } +} + +@include mixins.sky-component('modern', '.sky-expansion-indicator-down') { + .sky-expansion-indicator-left { + transform: rotate(45deg); + } + + .sky-expansion-indicator-right { + transform: rotate(-45deg); + } +} From 73a47639b6349818b42de5c8d4dcbbf402c13884 Mon Sep 17 00:00:00 2001 From: Steve Brush Date: Wed, 10 Jul 2024 10:18:38 -0400 Subject: [PATCH 3/5] fix(code-examples): satisfy ESLint rules for layout, lists, lookup, modals, pages, and others (#2435) --- apps/code-examples/.eslintrc.json | 7 ++ .../infinite-scroll/demo.component.ts | 15 +-- .../layout/box/basic/demo.component.spec.ts | 2 +- .../lists/filter/modal/demo.component.ts | 2 +- .../repeater/demo.component.ts | 15 +-- .../paging/with-content/demo.component.ts | 8 +- .../add-remove/demo.component.spec.ts | 105 +++++++++--------- .../repeater/inline-form/demo.component.ts | 19 ++-- .../lists/sort/basic/demo.component.ts | 2 +- .../autocomplete/advanced/demo.component.ts | 2 +- .../custom-search/demo.component.ts | 2 +- .../country-field/basic/demo.component.html | 2 +- .../country-field/basic/demo.component.ts | 44 ++++---- .../lookup/add-item/demo.component.spec.ts | 2 +- .../lookup/lookup/add-item/demo.component.ts | 14 ++- .../lookup/async/demo.component.spec.ts | 2 +- .../lookup/lookup/async/demo.component.ts | 3 +- .../custom-picker/demo.component.spec.ts | 2 +- .../lookup/custom-picker/demo.component.ts | 4 +- .../custom-picker/picker-modal.component.ts | 9 +- .../lookup/multi-select/demo.component.ts | 2 +- .../result-templates/demo.component.spec.ts | 2 +- .../lookup/result-templates/demo.component.ts | 2 +- .../lookup/single-select/demo.component.ts | 2 +- .../lookup/search/basic/demo.component.ts | 4 +- .../add-item/demo.component.spec.ts | 19 ++-- .../add-item/demo.component.ts | 9 +- .../basic/demo.component.spec.ts | 18 +-- .../demo.component.spec.ts | 12 +- .../basic-with-harness/demo.component.spec.ts | 9 +- .../basic-with-controller/demo.component.ts | 4 +- .../basic-with-harness/demo.component.ts | 3 +- .../modals/modal/with-error/demo.component.ts | 3 +- .../modal/with-error/modal.component.ts | 2 +- .../dashboards-grid-context-menu.component.ts | 6 +- .../demo.component.spec.ts | 2 +- .../page/list-page-list-layout-demo/item.ts | 5 + .../list-page-content.component.ts | 3 +- .../contact-context-menu.component.ts | 6 +- .../list-page-tabs-layout-demo/contact.ts | 5 + .../demo.component.spec.ts | 2 +- .../list-page-content.component.ts | 3 +- .../demo.component.spec.ts | 2 +- .../attachment.ts | 6 + ...attachments-grid-context-menu.component.ts | 6 +- .../demo.component.spec.ts | 2 +- .../record-page-tabs-layout-demo/detail.ts | 4 + .../record-page-attachments-tab.component.ts | 3 +- .../record-page-overview-tab.component.ts | 4 +- .../demo.component.spec.ts | 2 +- .../custom-sky-href-resolver.service.spec.ts | 58 +++++----- .../custom-sky-href-resolver.service.ts | 41 ++++--- .../split-view/basic/demo.component.ts | 26 +++-- .../split-view/page-bound/demo.component.ts | 26 +++-- .../modal/information-form.component.ts | 23 ++-- .../text-editor/text-editor/demo.component.ts | 17 ++- 56 files changed, 350 insertions(+), 254 deletions(-) create mode 100644 apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/item.ts create mode 100644 apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/contact.ts create mode 100644 apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/attachment.ts create mode 100644 apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/detail.ts diff --git a/apps/code-examples/.eslintrc.json b/apps/code-examples/.eslintrc.json index 73af0ebb9d..bb83826810 100644 --- a/apps/code-examples/.eslintrc.json +++ b/apps/code-examples/.eslintrc.json @@ -31,7 +31,14 @@ }, { "files": ["./src/app/code-examples/**/*.ts"], + "extends": ["../../libs/sdk/eslint-config/recommended"], + "parserOptions": { + "project": ["apps/code-examples/tsconfig.editor.json"], + "tsconfigRootDir": "." + }, "rules": { + "no-alert": "warn", + "no-console": "warn", "no-restricted-imports": [ "error", { diff --git a/apps/code-examples/src/app/code-examples/layout/back-to-top/infinite-scroll/demo.component.ts b/apps/code-examples/src/app/code-examples/layout/back-to-top/infinite-scroll/demo.component.ts index 61b9031fbf..5c185fe9ff 100644 --- a/apps/code-examples/src/app/code-examples/layout/back-to-top/infinite-scroll/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/layout/back-to-top/infinite-scroll/demo.component.ts @@ -129,21 +129,18 @@ export class DemoComponent implements OnInit { ]; public ngOnInit(): void { - this.addData(0, 5); + void this.#addData(0, 5); } public onScrollEnd(): void { - this.addData(this.personList.length, 5); + void this.#addData(this.personList.length, 5); } - private addData(start: number, rowSize: number): void { + async #addData(start: number, rowSize: number): Promise { if (this.hasMore) { - this.mockRemote(start, rowSize).then( - (result: { data: Person[]; hasMore: boolean }) => { - this.personList = this.personList.concat(result.data); - this.hasMore = result.hasMore; - }, - ); + const result = await this.mockRemote(start, rowSize); + this.personList = this.personList.concat(result.data); + this.hasMore = result.hasMore; } } diff --git a/apps/code-examples/src/app/code-examples/layout/box/basic/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/layout/box/basic/demo.component.spec.ts index 44bac8fd95..04debb4409 100644 --- a/apps/code-examples/src/app/code-examples/layout/box/basic/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/layout/box/basic/demo.component.spec.ts @@ -4,7 +4,7 @@ import { SkyBoxHarness } from '@skyux/layout/testing'; import { DemoComponent } from './demo.component'; -describe('Basic box', async () => { +describe('Basic box', () => { async function setupTest(): Promise<{ boxHarness: SkyBoxHarness; fixture: ComponentFixture; diff --git a/apps/code-examples/src/app/code-examples/lists/filter/modal/demo.component.ts b/apps/code-examples/src/app/code-examples/lists/filter/modal/demo.component.ts index 03e028b0d2..feb85c9a3a 100644 --- a/apps/code-examples/src/app/code-examples/lists/filter/modal/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lists/filter/modal/demo.component.ts @@ -82,7 +82,7 @@ export class DemoComponent { modalInstance.closed.subscribe((result: SkyModalCloseArgs) => { if (result.reason === 'save') { - this.appliedFilters = result.data.slice(); + this.appliedFilters = (result.data as Filter[]).slice(); this.filteredItems = this.#filterItems(this.items, this.appliedFilters); this.#changeDetectorRef.markForCheck(); } diff --git a/apps/code-examples/src/app/code-examples/lists/infinite-scroll/repeater/demo.component.ts b/apps/code-examples/src/app/code-examples/lists/infinite-scroll/repeater/demo.component.ts index e559918326..ca99fb3f36 100644 --- a/apps/code-examples/src/app/code-examples/lists/infinite-scroll/repeater/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lists/infinite-scroll/repeater/demo.component.ts @@ -17,22 +17,19 @@ export class DemoComponent implements OnInit { protected itemsHaveMore = true; public ngOnInit(): void { - this.#addData(); + void this.#addData(); } protected onScrollEnd(): void { if (this.itemsHaveMore) { - this.#addData(); + void this.#addData(); } } - #addData(): void { - this.#mockRemote().then( - (result: { data: InfiniteScrollDemoItem[]; hasMore: boolean }) => { - this.items = this.items.concat(result.data); - this.itemsHaveMore = result.hasMore; - }, - ); + async #addData(): Promise { + const result = await this.#mockRemote(); + this.items = this.items.concat(result.data); + this.itemsHaveMore = result.hasMore; } #mockRemote(): Promise<{ diff --git a/apps/code-examples/src/app/code-examples/lists/paging/with-content/demo.component.ts b/apps/code-examples/src/app/code-examples/lists/paging/with-content/demo.component.ts index d56b6d4f31..195e2a0f48 100644 --- a/apps/code-examples/src/app/code-examples/lists/paging/with-content/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lists/paging/with-content/demo.component.ts @@ -32,9 +32,11 @@ export class DemoComponent { protected pagedData = this.contentChange.pipe( switchMap((args) => - this.#demoDataSvc - .getPagedData(args.currentPage, this.pageSize) - .pipe(tap(() => args.loadingComplete())), + this.#demoDataSvc.getPagedData(args.currentPage, this.pageSize).pipe( + tap(() => { + args.loadingComplete(); + }), + ), ), shareReplay(1), ); diff --git a/apps/code-examples/src/app/code-examples/lists/repeater/add-remove/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/lists/repeater/add-remove/demo.component.spec.ts index 52cc6a1b12..7b71b1d78d 100644 --- a/apps/code-examples/src/app/code-examples/lists/repeater/add-remove/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/lists/repeater/add-remove/demo.component.spec.ts @@ -1,18 +1,15 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { - SkyRepeaterHarness, - SkyRepeaterItemHarness, -} from '@skyux/lists/testing'; +import { SkyRepeaterHarness } from '@skyux/lists/testing'; import { DemoComponent } from './demo.component'; describe('Repeater add remove demo', () => { async function setupTest(): Promise<{ - repeaterHarness: SkyRepeaterHarness | null; - repeaterItems: SkyRepeaterItemHarness[] | null; + el: HTMLElement; fixture: ComponentFixture; + repeaterHarness: SkyRepeaterHarness; }> { const fixture = TestBed.createComponent(DemoComponent); const loader = TestbedHarnessEnvironment.loader(fixture); @@ -21,9 +18,9 @@ describe('Repeater add remove demo', () => { SkyRepeaterHarness.with({ dataSkyId: 'repeater-demo' }), ); - const repeaterItems = await repeaterHarness.getRepeaterItems(); + const el = fixture.nativeElement as HTMLElement; - return { repeaterHarness, repeaterItems, fixture }; + return { el, fixture, repeaterHarness }; } beforeEach(() => { @@ -33,11 +30,13 @@ describe('Repeater add remove demo', () => { }); it('should allow items to be expanded and collapsed', async () => { - const { repeaterItems } = await setupTest(); + const { repeaterHarness } = await setupTest(); + + const repeaterItems = await repeaterHarness.getRepeaterItems(); let first = true; - for (const item of repeaterItems!) { + for (const item of repeaterItems) { await expectAsync(item.isCollapsible()).toBeResolvedTo(true); // in single expand mode, the first item is expanded by default @@ -75,72 +74,68 @@ describe('Repeater add remove demo', () => { }, ]; - let repeaterItems = await repeaterHarness?.getRepeaterItems(); + let repeaterItems = await repeaterHarness.getRepeaterItems(); expect(repeaterItems).toBeDefined(); - expect(repeaterItems?.length).toBe(expectedContent.length); + expect(repeaterItems.length).toBe(expectedContent.length); - if (repeaterItems) { - for (const item of repeaterItems) { - await expectAsync(item.isReorderable()).toBeResolvedTo(true); - } + for (const item of repeaterItems) { + await expectAsync(item.isReorderable()).toBeResolvedTo(true); + } - await expectAsync(repeaterItems?.[1].getTitleText()).toBeResolvedTo( - expectedContent[1].title, - ); + await expectAsync(repeaterItems[1].getTitleText()).toBeResolvedTo( + expectedContent[1].title, + ); - await repeaterItems?.[1].sendToTop(); - repeaterItems = await repeaterHarness?.getRepeaterItems(); + await repeaterItems[1].sendToTop(); + repeaterItems = await repeaterHarness.getRepeaterItems(); - await expectAsync(repeaterItems?.[1].getTitleText()).toBeResolvedTo( - expectedContent[0].title, - ); - } + await expectAsync(repeaterItems[1].getTitleText()).toBeResolvedTo( + expectedContent[0].title, + ); }); it('should allow items to be added and removed', async () => { - const { repeaterHarness, fixture } = await setupTest(); + const { repeaterHarness, el, fixture } = await setupTest(); - let repeaterItems = await repeaterHarness?.getRepeaterItems(); + let repeaterItems = await repeaterHarness.getRepeaterItems(); expect(repeaterItems).toBeDefined(); - expect(repeaterItems?.length).toBe(4); + expect(repeaterItems.length).toBe(4); - if (repeaterItems) { - for (const item of repeaterItems) { - await expectAsync(item.isSelectable()).toBeResolvedTo(true); - } + for (const item of repeaterItems) { + await expectAsync(item.isSelectable()).toBeResolvedTo(true); + } - const addButton = fixture.nativeElement.querySelector( - '[data-sky-id="add-button"]', - ); + const addButton = el.querySelector( + '[data-sky-id="add-button"]', + ); - const removeButton = fixture.nativeElement.querySelector( - '[data-sky-id="remove-button"]', - ); + const removeButton = el.querySelector( + '[data-sky-id="remove-button"]', + ); - addButton.click(); - fixture.detectChanges(); + addButton?.click(); + fixture.detectChanges(); - repeaterItems = await repeaterHarness?.getRepeaterItems(); - expect(repeaterItems).toBeDefined(); - expect(repeaterItems?.length).toBe(5); + repeaterItems = await repeaterHarness.getRepeaterItems(); + expect(repeaterItems).toBeDefined(); + expect(repeaterItems.length).toBe(5); - await expectAsync(repeaterItems?.[0].isSelected()).toBeResolvedTo(false); - await repeaterItems?.[0].select(); + await expectAsync(repeaterItems[0].isSelected()).toBeResolvedTo(false); + await repeaterItems[0].select(); - await expectAsync(repeaterItems?.[0].isSelected()).toBeResolvedTo(true); - await expectAsync(repeaterItems?.[1].isSelected()).toBeResolvedTo(false); + await expectAsync(repeaterItems[0].isSelected()).toBeResolvedTo(true); + await expectAsync(repeaterItems[1].isSelected()).toBeResolvedTo(false); - await repeaterItems?.[1].select(); - await expectAsync(repeaterItems?.[1].isSelected()).toBeResolvedTo(true); + await repeaterItems[1].select(); + await expectAsync(repeaterItems[1].isSelected()).toBeResolvedTo(true); - removeButton.click(); - fixture.detectChanges(); + removeButton?.click(); + fixture.detectChanges(); - repeaterItems = await repeaterHarness?.getRepeaterItems(); - expect(repeaterItems).toBeDefined(); - expect(repeaterItems?.length).toBe(3); - } + repeaterItems = await repeaterHarness.getRepeaterItems(); + expect(repeaterItems).toBeDefined(); + expect(repeaterItems.length).toBe(3); }); }); diff --git a/apps/code-examples/src/app/code-examples/lists/repeater/inline-form/demo.component.ts b/apps/code-examples/src/app/code-examples/lists/repeater/inline-form/demo.component.ts index 1053b0ca58..c7514e826e 100644 --- a/apps/code-examples/src/app/code-examples/lists/repeater/inline-form/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lists/repeater/inline-form/demo.component.ts @@ -16,6 +16,12 @@ import { } from '@skyux/inline-form'; import { SkyRepeaterModule } from '@skyux/lists'; +interface DemoForm { + id: FormControl; + note: FormControl; + title: FormControl; +} + interface Item { id: string; title: string | undefined; @@ -37,6 +43,7 @@ interface Item { }) export class DemoComponent { protected activeInlineFormId: string | undefined; + protected formGroup: FormGroup; protected inlineFormConfig: SkyInlineFormConfig = { buttonLayout: SkyInlineFormButtonLayout.SaveCancel, @@ -65,13 +72,11 @@ export class DemoComponent { }, ]; - protected formGroup: FormGroup; - constructor() { this.formGroup = inject(FormBuilder).group({ - id: new FormControl(), - title: new FormControl(), - note: new FormControl(), + id: new FormControl('', { nonNullable: true }), + title: new FormControl('', { nonNullable: true }), + note: new FormControl('', { nonNullable: true }), }); } @@ -89,8 +94,8 @@ export class DemoComponent { (item) => item.id === this.activeInlineFormId, ); if (found) { - found.note = this.formGroup.get('note')?.value; - found.title = this.formGroup.get('title')?.value; + found.note = this.formGroup.value.note; + found.title = this.formGroup.value.title; } } diff --git a/apps/code-examples/src/app/code-examples/lists/sort/basic/demo.component.ts b/apps/code-examples/src/app/code-examples/lists/sort/basic/demo.component.ts index c7d9eda81d..0a33ff86c7 100644 --- a/apps/code-examples/src/app/code-examples/lists/sort/basic/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lists/sort/basic/demo.component.ts @@ -102,7 +102,7 @@ export class DemoComponent implements OnInit { } protected sortItems(option: SortOption): void { - this.sortedItems = this.sortedItems.sort(function (a: Item, b: Item) { + this.sortedItems = this.sortedItems.sort((a, b) => { const descending = option.descending ? -1 : 1; const sortProperty: keyof typeof a = option.name; diff --git a/apps/code-examples/src/app/code-examples/lookup/autocomplete/advanced/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/autocomplete/advanced/demo.component.ts index fc7cde552c..f61f04b2cd 100644 --- a/apps/code-examples/src/app/code-examples/lookup/autocomplete/advanced/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/autocomplete/advanced/demo.component.ts @@ -68,6 +68,6 @@ export class DemoComponent { } protected onPlanetSelection(args: SkyAutocompleteSelectionChange): void { - alert(`You selected ${args.selectedItem.name}`); + alert(`You selected ${(args.selectedItem as Planet).name}`); } } diff --git a/apps/code-examples/src/app/code-examples/lookup/autocomplete/custom-search/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/autocomplete/custom-search/demo.component.ts index d12c1be29b..a91d8b8cdc 100644 --- a/apps/code-examples/src/app/code-examples/lookup/autocomplete/custom-search/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/autocomplete/custom-search/demo.component.ts @@ -61,7 +61,7 @@ export class DemoComponent { const results = oceans.filter((ocean: Ocean) => { const val = ocean.title; const isMatch = - val && val.toString().toLowerCase().indexOf(searchTextLower) > -1; + val && val.toString().toLowerCase().includes(searchTextLower); return isMatch; }); diff --git a/apps/code-examples/src/app/code-examples/lookup/country-field/basic/demo.component.html b/apps/code-examples/src/app/code-examples/lookup/country-field/basic/demo.component.html index 54f11adf5d..b7c743d524 100644 --- a/apps/code-examples/src/app/code-examples/lookup/country-field/basic/demo.component.html +++ b/apps/code-examples/src/app/code-examples/lookup/country-field/basic/demo.component.html @@ -4,7 +4,7 @@ labelText="Country" [helpPopoverContent]="helpPopoverContent" > - + ; +} + +function validateCountry( + control: AbstractControl, +): ValidationErrors | null { + return control.value?.name === 'Mexico' ? { invalidCountry: true } : null; +} @Component({ standalone: true, @@ -25,30 +35,26 @@ import { SkyCountryFieldModule } from '@skyux/lookup'; ], }) export class DemoComponent { - protected countryControl: FormControl; - protected countryForm: FormGroup; + protected countryControl: FormControl; + protected countryForm: FormGroup; + protected helpPopoverContent = 'We use the country to validate your passport within 10 business days. You can update it at any time.'; constructor() { - this.countryControl = new FormControl(undefined, { - validators: [this.#validateCountry, Validators.required], - }); - - this.countryControl.setValue({ - name: 'Australia', - iso2: 'au', - }); + this.countryControl = new FormControl( + { + name: 'Australia', + iso2: 'au', + }, + { + nonNullable: true, + validators: [validateCountry, Validators.required], + }, + ); this.countryForm = new FormGroup({ - countryControl: this.countryControl, + country: this.countryControl, }); } - - #validateCountry(control: AbstractControl): ValidationErrors | null { - if (control.value?.name === 'Mexico') { - return { invalidCountry: true }; - } - return null; - } } diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/add-item/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/add-item/demo.component.spec.ts index 7bc096e035..110644bef1 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/add-item/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/add-item/demo.component.spec.ts @@ -31,7 +31,7 @@ describe('Lookup asynchronous search demo', () => { beforeEach(() => { // Create a mock search service. In a real-world application, the search // service would make a web request which should be avoided in unit tests. - mockSvc = jasmine.createSpyObj('DemoService', ['search']); + mockSvc = jasmine.createSpyObj('DemoService', ['search']); TestBed.configureTestingModule({ imports: [DemoComponent, NoopAnimationsModule], diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/add-item/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/add-item/demo.component.ts index dee894089e..0babab6dac 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/add-item/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/add-item/demo.component.ts @@ -16,7 +16,7 @@ import { SkyLookupModule, SkyLookupShowMoreConfig, } from '@skyux/lookup'; -import { SkyModalCloseArgs, SkyModalService } from '@skyux/modals'; +import { SkyModalService } from '@skyux/modals'; import { Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -52,7 +52,6 @@ export class DemoComponent implements OnInit, OnDestroy { #subscriptions = new Subscription(); readonly #svc = inject(DemoService); - readonly #modalSvc = inject(SkyModalService); readonly #waitSvc = inject(SkyWaitService); @@ -96,16 +95,19 @@ export class DemoComponent implements OnInit, OnDestroy { public addClick(args: SkyLookupAddClickEventArgs): void { const modal = this.#modalSvc.open(AddItemModalComponent); + this.#subscriptions.add( - modal.closed.subscribe((close: SkyModalCloseArgs) => { + modal.closed.subscribe((close) => { if (close.reason === 'save') { + const person = close.data as Person; + this.#subscriptions.add( this.#waitSvc - .blockingWrap(this.#svc.addPerson(close.data)) + .blockingWrap(this.#svc.addPerson(person)) .subscribe((data) => { args.itemAdded({ - item: close.data, - data: data, + item: person, + data, }); }), ); diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/async/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/async/demo.component.spec.ts index c7e3d3865d..fc8c35b894 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/async/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/async/demo.component.spec.ts @@ -31,7 +31,7 @@ describe('Lookup asynchronous search demo', () => { beforeEach(() => { // Create a mock search service. In a real-world application, the search // service would make a web request which should be avoided in unit tests. - mockSvc = jasmine.createSpyObj('DemoService', ['search']); + mockSvc = jasmine.createSpyObj('DemoService', ['search']); TestBed.configureTestingModule({ imports: [DemoComponent, NoopAnimationsModule], diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/async/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/async/demo.component.ts index f3b6edf0b7..1fd8d8d5b5 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/async/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/async/demo.component.ts @@ -1,6 +1,7 @@ import { CommonModule } from '@angular/common'; import { Component, OnInit, inject } from '@angular/core'; import { + AbstractControl, FormBuilder, FormControl, FormGroup, @@ -52,7 +53,7 @@ export class DemoComponent implements OnInit { constructor() { const names = new FormControl([{ name: 'Shirley' }], { validators: [ - (control): ValidationErrors => { + (control: AbstractControl): ValidationErrors => { if ( control.value?.some((person: Person) => !person.name.match(/e/i)) ) { diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/demo.component.spec.ts index 9ccbd06f5f..71003017f5 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/demo.component.spec.ts @@ -44,7 +44,7 @@ describe('Lookup custom picker demo', () => { await lookupHarness.enterText('Be'); const allResultHarnesses = await lookupHarness.getSearchResults(); - const firstResultHarness = allResultHarnesses && allResultHarnesses[0]; + const firstResultHarness = allResultHarnesses[0]; if (firstResultHarness) { await firstResultHarness.select(); diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/demo.component.ts index da8b9378fc..62129758b7 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/demo.component.ts @@ -130,7 +130,7 @@ export class DemoComponent implements OnInit { }); this.searchFilters = [ - (_, item): boolean => { + (_, item: Person): boolean => { const names = this.favoritesForm.value.favoriteNames; // Only show people in the search results that have not been chosen already. @@ -154,7 +154,7 @@ export class DemoComponent implements OnInit { instance.closed.subscribe((closeArgs) => { if (closeArgs.reason === 'save') { this.favoritesForm.controls.favoriteNames.setValue( - closeArgs.data, + closeArgs.data as Person[], ); } }); diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/picker-modal.component.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/picker-modal.component.ts index 062aa15812..a6a6bdbebc 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/picker-modal.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/custom-picker/picker-modal.component.ts @@ -42,13 +42,16 @@ export class PickerModalComponent { constructor() { // This list of people will be rendered as selection boxes. - this.people = this.context.items; + this.people = this.context.items as Person[]; // Create a control for each selection box. this.peopleForm = this.#formBuilder.group({ people: this.#formBuilder.array( - this.context.items.map((item) => - this.#formBuilder.control(this.context.initialValue?.includes(item)), + this.context.items.map((item: Person) => + this.#formBuilder.control( + (this.context.initialValue as Person[]).includes(item), + { nonNullable: true }, + ), ), ), }); diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/multi-select/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/multi-select/demo.component.ts index c44f508c12..ca6511965e 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/multi-select/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/multi-select/demo.component.ts @@ -78,7 +78,7 @@ export class DemoComponent implements OnInit { }); this.searchFilters = [ - (_, item, args): boolean => { + (_, item: Person, args): boolean => { // When in the modal view, show all people in the search results, regardless if they have been chosen already. if (args?.context === 'modal') { return true; diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/result-templates/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/result-templates/demo.component.spec.ts index 38ec0724ec..299d95a56e 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/result-templates/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/result-templates/demo.component.spec.ts @@ -77,7 +77,7 @@ describe('Lookup result templates demo', () => { await lookupHarness.enterText('be'); const allResultHarnesses = await lookupHarness.getSearchResults(); - const firstResultHarness = allResultHarnesses && allResultHarnesses[0]; + const firstResultHarness = allResultHarnesses[0]; await firstResultHarness.select(); expect( diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/result-templates/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/result-templates/demo.component.ts index 716229fe6e..e7c0066051 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/result-templates/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/result-templates/demo.component.ts @@ -145,7 +145,7 @@ export class DemoComponent implements OnInit { }); this.searchFilters = [ - (_, item): boolean => { + (_, item: Person): boolean => { const names = this.favoritesForm.value.favoriteNames; // Only show people in the search results that have not been chosen already. diff --git a/apps/code-examples/src/app/code-examples/lookup/lookup/single-select/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/lookup/single-select/demo.component.ts index 8509b8be82..f7796240cd 100644 --- a/apps/code-examples/src/app/code-examples/lookup/lookup/single-select/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/lookup/single-select/demo.component.ts @@ -72,7 +72,7 @@ export class DemoComponent implements OnInit { }); this.searchFilters = [ - (_, item): boolean => { + (_, item: Person): boolean => { const names = this.favoritesForm.value.favoriteName; // Only show people in the search results that have not been chosen already. diff --git a/apps/code-examples/src/app/code-examples/lookup/search/basic/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/search/basic/demo.component.ts index e9e049d4ec..9b55f85c7b 100644 --- a/apps/code-examples/src/app/code-examples/lookup/search/basic/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/search/basic/demo.component.ts @@ -50,7 +50,7 @@ export class DemoComponent { this.searchText = searchText; if (searchText) { - filteredItems = this.items.filter(function (item: Item) { + filteredItems = this.items.filter((item: Item) => { let property: keyof typeof item; for (property in item) { @@ -58,7 +58,7 @@ export class DemoComponent { Object.prototype.hasOwnProperty.call(item, property) && (property === 'title' || property === 'note') ) { - if (item[property].indexOf(searchText) > -1) { + if (item[property].includes(searchText)) { return true; } } diff --git a/apps/code-examples/src/app/code-examples/lookup/selection-modal/add-item/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/lookup/selection-modal/add-item/demo.component.spec.ts index aabdb9599b..7adf078d58 100644 --- a/apps/code-examples/src/app/code-examples/lookup/selection-modal/add-item/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/lookup/selection-modal/add-item/demo.component.spec.ts @@ -13,26 +13,29 @@ describe('Selection modal demo', () => { async function setupTest(): Promise<{ harness: SkySelectionModalHarness; + el: HTMLElement; fixture: ComponentFixture; }> { const fixture = TestBed.createComponent(DemoComponent); - const openBtn = fixture.nativeElement.querySelector( + const el = fixture.nativeElement as HTMLElement; + + const openBtn = el.querySelector( '.selection-modal-demo-show-btn', ); - openBtn.click(); + openBtn?.click(); fixture.detectChanges(); const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture); const harness = await rootLoader.getHarness(SkySelectionModalHarness); - return { harness, fixture }; + return { harness, el, fixture }; } beforeEach(() => { // Create a mock search service. In a real-world application, the search // service would make a web request which should be avoided in unit tests. - mockSvc = jasmine.createSpyObj('DemoService', ['search']); + mockSvc = jasmine.createSpyObj('DemoService', ['search']); mockSvc.search.and.callFake((searchText) => { return of({ @@ -56,7 +59,7 @@ describe('Selection modal demo', () => { }); it('should update the selected items list when an item is selected', async () => { - const { harness, fixture } = await setupTest(); + const { harness, el } = await setupTest(); await harness.enterSearchText('ra'); await harness.selectSearchResult({ @@ -64,7 +67,7 @@ describe('Selection modal demo', () => { }); await harness.saveAndClose(); - const selectedItemEls = fixture.nativeElement.querySelectorAll( + const selectedItemEls = el.querySelectorAll( '.selection-modal-demo-selected li', ); @@ -73,7 +76,7 @@ describe('Selection modal demo', () => { }); it('should not update the selected items list when the user cancels the selection modal', async () => { - const { harness, fixture } = await setupTest(); + const { harness, el } = await setupTest(); await harness.enterSearchText('ra'); await harness.selectSearchResult({ @@ -81,7 +84,7 @@ describe('Selection modal demo', () => { }); await harness.cancel(); - const selectedItemEls = fixture.nativeElement.querySelectorAll( + const selectedItemEls = el.querySelectorAll( '.selection-modal-demo-selected li', ); diff --git a/apps/code-examples/src/app/code-examples/lookup/selection-modal/add-item/demo.component.ts b/apps/code-examples/src/app/code-examples/lookup/selection-modal/add-item/demo.component.ts index eb55ed58b2..043441474d 100644 --- a/apps/code-examples/src/app/code-examples/lookup/selection-modal/add-item/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/lookup/selection-modal/add-item/demo.component.ts @@ -6,7 +6,7 @@ import { SkySelectionModalSearchResult, SkySelectionModalService, } from '@skyux/lookup'; -import { SkyModalCloseArgs, SkyModalService } from '@skyux/modals'; +import { SkyModalService } from '@skyux/modals'; import { Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -55,10 +55,11 @@ export class DemoComponent implements OnDestroy { const modal = this.#modalSvc.open(AddItemModalComponent); this.#subscriptions.add( - modal.closed.subscribe((close: SkyModalCloseArgs) => { + modal.closed.subscribe((close) => { if (close.reason === 'save') { - this.#searchSvc.addItem(close.data); - args.itemAdded({ item: close.data }); + const person = close.data as Person; + this.#searchSvc.addItem(person); + args.itemAdded({ item: person }); } }), ); diff --git a/apps/code-examples/src/app/code-examples/lookup/selection-modal/basic/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/lookup/selection-modal/basic/demo.component.spec.ts index aabdb9599b..028eaacd4d 100644 --- a/apps/code-examples/src/app/code-examples/lookup/selection-modal/basic/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/lookup/selection-modal/basic/demo.component.spec.ts @@ -13,26 +13,28 @@ describe('Selection modal demo', () => { async function setupTest(): Promise<{ harness: SkySelectionModalHarness; + el: HTMLElement; fixture: ComponentFixture; }> { const fixture = TestBed.createComponent(DemoComponent); - const openBtn = fixture.nativeElement.querySelector( + const el = fixture.nativeElement as HTMLElement; + const openBtn = el.querySelector( '.selection-modal-demo-show-btn', ); - openBtn.click(); + openBtn?.click(); fixture.detectChanges(); const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture); const harness = await rootLoader.getHarness(SkySelectionModalHarness); - return { harness, fixture }; + return { harness, el, fixture }; } beforeEach(() => { // Create a mock search service. In a real-world application, the search // service would make a web request which should be avoided in unit tests. - mockSvc = jasmine.createSpyObj('DemoService', ['search']); + mockSvc = jasmine.createSpyObj('DemoService', ['search']); mockSvc.search.and.callFake((searchText) => { return of({ @@ -56,7 +58,7 @@ describe('Selection modal demo', () => { }); it('should update the selected items list when an item is selected', async () => { - const { harness, fixture } = await setupTest(); + const { harness, el } = await setupTest(); await harness.enterSearchText('ra'); await harness.selectSearchResult({ @@ -64,7 +66,7 @@ describe('Selection modal demo', () => { }); await harness.saveAndClose(); - const selectedItemEls = fixture.nativeElement.querySelectorAll( + const selectedItemEls = el.querySelectorAll( '.selection-modal-demo-selected li', ); @@ -73,7 +75,7 @@ describe('Selection modal demo', () => { }); it('should not update the selected items list when the user cancels the selection modal', async () => { - const { harness, fixture } = await setupTest(); + const { harness, el } = await setupTest(); await harness.enterSearchText('ra'); await harness.selectSearchResult({ @@ -81,7 +83,7 @@ describe('Selection modal demo', () => { }); await harness.cancel(); - const selectedItemEls = fixture.nativeElement.querySelectorAll( + const selectedItemEls = el.querySelectorAll( '.selection-modal-demo-selected li', ); diff --git a/apps/code-examples/src/app/code-examples/modals/confirm/basic-with-controller/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/modals/confirm/basic-with-controller/demo.component.spec.ts index 03076fd7e8..db8e5aec46 100644 --- a/apps/code-examples/src/app/code-examples/modals/confirm/basic-with-controller/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/modals/confirm/basic-with-controller/demo.component.spec.ts @@ -7,10 +7,10 @@ import { import { DemoComponent } from './demo.component'; describe('Testing with SkyConfirmTestingController', () => { - async function setupTest(): Promise<{ + function setupTest(): { confirmController: SkyConfirmTestingController; fixture: ComponentFixture; - }> { + } { const confirmController = TestBed.inject(SkyConfirmTestingController); const fixture = TestBed.createComponent(DemoComponent); @@ -23,8 +23,8 @@ describe('Testing with SkyConfirmTestingController', () => { }); }); - it('should click "OK" on a confirmation dialog', async () => { - const { confirmController, fixture } = await setupTest(); + it('should click "OK" on a confirmation dialog', () => { + const { confirmController, fixture } = setupTest(); fixture.componentInstance.launchConfirm(); fixture.detectChanges(); @@ -39,8 +39,8 @@ describe('Testing with SkyConfirmTestingController', () => { expect(fixture.componentInstance.selectedAction).toEqual('ok'); }); - it('should cancel the confirmation dialog', async () => { - const { confirmController, fixture } = await setupTest(); + it('should cancel the confirmation dialog', () => { + const { confirmController, fixture } = setupTest(); fixture.componentInstance.launchConfirm(); fixture.detectChanges(); diff --git a/apps/code-examples/src/app/code-examples/modals/confirm/basic-with-harness/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/modals/confirm/basic-with-harness/demo.component.spec.ts index 4ed2baab77..6bd8c07a54 100644 --- a/apps/code-examples/src/app/code-examples/modals/confirm/basic-with-harness/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/modals/confirm/basic-with-harness/demo.component.spec.ts @@ -10,9 +10,10 @@ describe('Testing with SkyConfirmHarness', () => { fixture: ComponentFixture; }> { const fixture = TestBed.createComponent(DemoComponent); - const openBtn = fixture.nativeElement.querySelector(confirmBtnClass); + const el = fixture.nativeElement as HTMLElement; + const openBtn = el.querySelector(confirmBtnClass); - openBtn.click(); + openBtn?.click(); const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture); const confirmHarness = await rootLoader.getHarness(SkyConfirmHarness); @@ -25,7 +26,9 @@ describe('Testing with SkyConfirmHarness', () => { expectedText: string, ): void { expect( - fixture.nativeElement.querySelector('.displayed-text')?.innerText, + (fixture.nativeElement as HTMLElement).querySelector( + '.displayed-text', + )?.innerText, ).toEqual(expectedText); } diff --git a/apps/code-examples/src/app/code-examples/modals/modal/basic-with-controller/demo.component.ts b/apps/code-examples/src/app/code-examples/modals/modal/basic-with-controller/demo.component.ts index 0423564b6c..7fbbba03dd 100644 --- a/apps/code-examples/src/app/code-examples/modals/modal/basic-with-controller/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/modals/modal/basic-with-controller/demo.component.ts @@ -31,7 +31,9 @@ export class DemoComponent implements OnDestroy { readonly #modalSvc = inject(SkyModalService); public ngOnDestroy(): void { - this.#instances.forEach((i) => i.close()); + this.#instances.forEach((i) => { + i.close(); + }); } public openModal(): void { diff --git a/apps/code-examples/src/app/code-examples/modals/modal/basic-with-harness/demo.component.ts b/apps/code-examples/src/app/code-examples/modals/modal/basic-with-harness/demo.component.ts index bd0a29f0a7..35e62ed1c2 100644 --- a/apps/code-examples/src/app/code-examples/modals/modal/basic-with-harness/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/modals/modal/basic-with-harness/demo.component.ts @@ -54,8 +54,7 @@ export class DemoComponent implements OnDestroy { instance.closed.subscribe((result) => { if (result.reason === 'save') { // Display the updated value. - const data = result.data as ModalDemoData; - this.demoValue = data.value1; + this.demoValue = (result.data as ModalDemoData).value1; } }); }); diff --git a/apps/code-examples/src/app/code-examples/modals/modal/with-error/demo.component.ts b/apps/code-examples/src/app/code-examples/modals/modal/with-error/demo.component.ts index bd0a29f0a7..35e62ed1c2 100644 --- a/apps/code-examples/src/app/code-examples/modals/modal/with-error/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/modals/modal/with-error/demo.component.ts @@ -54,8 +54,7 @@ export class DemoComponent implements OnDestroy { instance.closed.subscribe((result) => { if (result.reason === 'save') { // Display the updated value. - const data = result.data as ModalDemoData; - this.demoValue = data.value1; + this.demoValue = (result.data as ModalDemoData).value1; } }); }); diff --git a/apps/code-examples/src/app/code-examples/modals/modal/with-error/modal.component.ts b/apps/code-examples/src/app/code-examples/modals/modal/with-error/modal.component.ts index 903751a980..2bb207bf53 100644 --- a/apps/code-examples/src/app/code-examples/modals/modal/with-error/modal.component.ts +++ b/apps/code-examples/src/app/code-examples/modals/modal/with-error/modal.component.ts @@ -47,7 +47,7 @@ export class ModalComponent { this.#waitSvc .blockingWrap(this.#dataSvc.save(this.demoForm.value, true)) - .subscribe((data) => { + .subscribe(() => { this.errors = [{ message: 'There was an error saving the form.' }]; }); } diff --git a/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/dashboards-grid-context-menu.component.ts b/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/dashboards-grid-context-menu.component.ts index b4027838b4..638784dd9b 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/dashboards-grid-context-menu.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/dashboards-grid-context-menu.component.ts @@ -4,6 +4,8 @@ import { SkyDropdownModule } from '@skyux/popovers'; import { ICellRendererAngularComp } from 'ag-grid-angular'; import { ICellRendererParams } from 'ag-grid-community'; +import { Item } from './item'; + @Component({ standalone: true, selector: 'app-dashboards-grid-context-menu', @@ -15,8 +17,8 @@ export class DashboardGridContextMenuComponent { protected dashboardName = ''; - public agInit(params: ICellRendererParams): void { - this.dashboardName = params.data && params.data.dashboard; + public agInit(params: ICellRendererParams): void { + this.dashboardName = params.data?.dashboard ?? ''; } public refresh(): boolean { diff --git a/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/demo.component.spec.ts index b4f1823f49..09a41eb22b 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/demo.component.spec.ts @@ -5,7 +5,7 @@ import { SkyPageHarness } from '@skyux/pages/testing'; import { DemoComponent } from './demo.component'; -describe('List page list layout demo', async () => { +describe('List page list layout demo', () => { async function setupTest(): Promise<{ pageHarness: SkyPageHarness; fixture: ComponentFixture; diff --git a/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/item.ts b/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/item.ts new file mode 100644 index 0000000000..fdbea72423 --- /dev/null +++ b/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/item.ts @@ -0,0 +1,5 @@ +export interface Item { + dashboard: string; + name: string; + lastUpdated: string; +} diff --git a/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/list-page-content.component.ts b/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/list-page-content.component.ts index b9c0c42fe1..69b71d2165 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/list-page-content.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/list-page-list-layout-demo/list-page-content.component.ts @@ -12,6 +12,7 @@ import { AgGridModule } from 'ag-grid-angular'; import { ColDef, GridOptions, ICellRendererParams } from 'ag-grid-community'; import { DashboardGridContextMenuComponent } from './dashboards-grid-context-menu.component'; +import { Item } from './item'; @Component({ standalone: true, @@ -27,7 +28,7 @@ import { DashboardGridContextMenuComponent } from './dashboards-grid-context-men ], }) export class ListPageContentComponent implements OnInit { - protected items = [ + protected items: Item[] = [ { dashboard: 'Cash Flow Tracker', name: 'Kanesha Hutto', diff --git a/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/contact-context-menu.component.ts b/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/contact-context-menu.component.ts index 5b60e65779..dc496c7534 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/contact-context-menu.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/contact-context-menu.component.ts @@ -4,6 +4,8 @@ import { SkyDropdownModule } from '@skyux/popovers'; import { ICellRendererAngularComp } from 'ag-grid-angular'; import { ICellRendererParams } from 'ag-grid-community'; +import { Contact } from './contact'; + @Component({ standalone: true, selector: 'app-contacts-grid-context-menu', @@ -13,8 +15,8 @@ import { ICellRendererParams } from 'ag-grid-community'; export class ContactContextMenuComponent implements ICellRendererAngularComp { protected contactName = ''; - public agInit(params: ICellRendererParams): void { - this.contactName = params.data && params.data.name; + public agInit(params: ICellRendererParams): void { + this.contactName = params.data?.name ?? ''; } public refresh(): boolean { diff --git a/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/contact.ts b/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/contact.ts new file mode 100644 index 0000000000..9c2dc362e4 --- /dev/null +++ b/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/contact.ts @@ -0,0 +1,5 @@ +export interface Contact { + name: string; + organization: string; + emailAddress: string; +} diff --git a/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/demo.component.spec.ts index c3a058f9db..ceaa921f10 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/demo.component.spec.ts @@ -6,7 +6,7 @@ import { SkyPageHarness } from '@skyux/pages/testing'; import { DemoComponent } from './demo.component'; -describe('List page tabs layout demo', async () => { +describe('List page tabs layout demo', () => { async function setupTest(): Promise<{ pageHarness: SkyPageHarness; fixture: ComponentFixture; diff --git a/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/list-page-content.component.ts b/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/list-page-content.component.ts index 6196c864e0..88df6191c7 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/list-page-content.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/list-page-tabs-layout-demo/list-page-content.component.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { SkyTabIndex, SkyTabsModule } from '@skyux/tabs'; +import { Contact } from './contact'; import { ListPageContactsGridComponent } from './list-page-contacts-grid.component'; @Component({ @@ -13,7 +14,7 @@ import { ListPageContactsGridComponent } from './list-page-contacts-grid.compone export class ListPageContentComponent { protected activeTabIndex: SkyTabIndex = 0; - protected myContacts = [ + protected myContacts: Contact[] = [ { name: 'Wonda Lumpkin', organization: 'Riverfront College of the Arts', diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-blocks-layout-demo/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-blocks-layout-demo/demo.component.spec.ts index ae5e22d726..5961ebf8c5 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-blocks-layout-demo/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-blocks-layout-demo/demo.component.spec.ts @@ -6,7 +6,7 @@ import { SkyPageHarness } from '@skyux/pages/testing'; import { DemoComponent } from './demo.component'; -describe('Record page blocks layout demo', async () => { +describe('Record page blocks layout demo', () => { async function setupTest(): Promise<{ pageHarness: SkyPageHarness; fixture: ComponentFixture; diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/attachment.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/attachment.ts new file mode 100644 index 0000000000..746fdbb3c4 --- /dev/null +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/attachment.ts @@ -0,0 +1,6 @@ +export interface Attachment { + name: string; + description: string; + size: string; + dateAdded: string; +} diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/attachments-grid-context-menu.component.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/attachments-grid-context-menu.component.ts index 94d173294b..66173da05d 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/attachments-grid-context-menu.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/attachments-grid-context-menu.component.ts @@ -4,6 +4,8 @@ import { SkyDropdownModule } from '@skyux/popovers'; import { ICellRendererAngularComp } from 'ag-grid-angular'; import { ICellRendererParams } from 'ag-grid-community'; +import { Attachment } from './attachment'; + @Component({ standalone: true, selector: 'app-attachments-grid-context-menu', @@ -15,8 +17,8 @@ export class AttachmentsGridContextMenuComponent { protected attachmentName = ''; - public agInit(params: ICellRendererParams): void { - this.attachmentName = params.data && params.data.name; + public agInit(params: ICellRendererParams): void { + this.attachmentName = params.data?.name ?? ''; } public refresh(): boolean { diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/demo.component.spec.ts index 21f5a3240e..709a51bf58 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/demo.component.spec.ts @@ -6,7 +6,7 @@ import { SkyPageHarness } from '@skyux/pages/testing'; import { DemoComponent } from './demo.component'; -describe('Record page tabs layout demo', async () => { +describe('Record page tabs layout demo', () => { async function setupTest(): Promise<{ pageHarness: SkyPageHarness; fixture: ComponentFixture; diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/detail.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/detail.ts new file mode 100644 index 0000000000..158a7675bd --- /dev/null +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/detail.ts @@ -0,0 +1,4 @@ +export interface Detail { + detail: string; + info: string; +} diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-attachments-tab.component.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-attachments-tab.component.ts index 66e165c989..d25b5a8ded 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-attachments-tab.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-attachments-tab.component.ts @@ -12,6 +12,7 @@ import { SkyIconModule, SkyKeyInfoModule } from '@skyux/indicators'; import { AgGridModule } from 'ag-grid-angular'; import { ColDef, GridOptions, ICellRendererParams } from 'ag-grid-community'; +import { Attachment } from './attachment'; import { AttachmentsGridContextMenuComponent } from './attachments-grid-context-menu.component'; @Component({ @@ -29,7 +30,7 @@ import { AttachmentsGridContextMenuComponent } from './attachments-grid-context- ], }) export class RecordPageAttachmentsTabComponent implements OnInit { - protected items = [ + protected items: Attachment[] = [ { name: 'Agreement.pdf', description: 'Cardholder agreement', diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts index a6b272e97e..4a2e01e324 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts @@ -8,6 +8,8 @@ import { } from '@skyux/layout'; import { SkyRepeaterModule } from '@skyux/lists'; +import { Detail } from './detail'; + @Component({ standalone: true, selector: 'app-record-page-overview-tab', @@ -24,7 +26,7 @@ import { SkyRepeaterModule } from '@skyux/lists'; ], }) export class RecordPageOverviewTabComponent { - protected recordDetails = [ + protected recordDetails: Detail[] = [ { detail: 'Designation', info: 'General operating', diff --git a/apps/code-examples/src/app/code-examples/pages/page/split-view-page-fit-layout-demo/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/split-view-page-fit-layout-demo/demo.component.spec.ts index b0174483be..69201f03ba 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/split-view-page-fit-layout-demo/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/split-view-page-fit-layout-demo/demo.component.spec.ts @@ -6,7 +6,7 @@ import { SkyPageHarness } from '@skyux/pages/testing'; import { DemoComponent } from './demo.component'; -describe('Split view page fit layout demo', async () => { +describe('Split view page fit layout demo', () => { async function setupTest(): Promise<{ pageHarness: SkyPageHarness; fixture: ComponentFixture; diff --git a/apps/code-examples/src/app/code-examples/router/href/basic/custom-resolver/custom-sky-href-resolver.service.spec.ts b/apps/code-examples/src/app/code-examples/router/href/basic/custom-resolver/custom-sky-href-resolver.service.spec.ts index 10a29a35fc..700362d7a8 100644 --- a/apps/code-examples/src/app/code-examples/router/href/basic/custom-resolver/custom-sky-href-resolver.service.spec.ts +++ b/apps/code-examples/src/app/code-examples/router/href/basic/custom-resolver/custom-sky-href-resolver.service.spec.ts @@ -14,49 +14,51 @@ describe('CustomSkyHrefResolverService', () => { expect(service).toBeTruthy(); }); - it('should return a link as-is', () => { + it('should return a link as-is', async () => { const url = 'https://www.blackbaud.com'; - const result = service.resolveHref({ url }); - result.then((href) => { - expect(href.url).toEqual(url); - expect(href.userHasAccess).toEqual(true); - }); + const href = await service.resolveHref({ url }); + + expect(href.url).toEqual(url); + expect(href.userHasAccess).toEqual(true); }); - it('should return a link with allow protocol', () => { + it('should return a link with allow protocol', async () => { const url = 'allow://www.blackbaud.com'; - const result = service.resolveHref({ url }); - result.then((href) => { - expect(href.url).toEqual('https://www.blackbaud.com'); - expect(href.userHasAccess).toEqual(true); - }); + const href = await service.resolveHref({ url }); + + expect(href.url).toEqual('https://www.blackbaud.com'); + expect(href.userHasAccess).toEqual(true); }); - it('should return a link with deny protocol', () => { + it('should return a link with deny protocol', async () => { const url = 'deny://www.blackbaud.com'; - const result = service.resolveHref({ url }); - result.then((href) => { - expect(href.url).toEqual(url); - expect(href.userHasAccess).toEqual(false); - }); + const href = await service.resolveHref({ url }); + + expect(href.url).toEqual(url); + expect(href.userHasAccess).toEqual(false); }); it('should return a link with slow protocol', fakeAsync(() => { const url = 'slow://www.blackbaud.com'; const result = service.resolveHref({ url }); - result.then((href) => { - expect(href.url).toEqual('https://www.blackbaud.com'); - expect(href.userHasAccess).toEqual(true); - }); + + result + .then((href) => { + expect(href.url).toEqual('https://www.blackbaud.com'); + expect(href.userHasAccess).toEqual(true); + }) + .catch(() => { + fail('expected test to resolve'); + }); + tick(3000); })); - it('should return a link with unknown protocol', () => { + it('should return a link with unknown protocol', async () => { const url = 'unknown://www.blackbaud.com'; - const result = service.resolveHref({ url }); - result.then((href) => { - expect(href.url).toEqual(url); - expect(href.userHasAccess).toEqual(false); - }); + const href = await service.resolveHref({ url }); + + expect(href.url).toEqual(url); + expect(href.userHasAccess).toEqual(false); }); }); diff --git a/apps/code-examples/src/app/code-examples/router/href/basic/custom-resolver/custom-sky-href-resolver.service.ts b/apps/code-examples/src/app/code-examples/router/href/basic/custom-resolver/custom-sky-href-resolver.service.ts index ba07a6056c..7de7212048 100644 --- a/apps/code-examples/src/app/code-examples/router/href/basic/custom-resolver/custom-sky-href-resolver.service.ts +++ b/apps/code-examples/src/app/code-examples/router/href/basic/custom-resolver/custom-sky-href-resolver.service.ts @@ -12,23 +12,30 @@ import { SkyHref, SkyHrefResolver } from '@skyux/router'; export class CustomSkyHrefResolverService implements SkyHrefResolver { public resolveHref(param: { url: string }): Promise { const url = param.url; + if (url.startsWith('http:') || url.startsWith('https:')) { - return Promise.resolve({ - url: url, + return Promise.resolve({ + url, userHasAccess: true, }); - } else if (url.startsWith('allow:')) { - return Promise.resolve({ + } + + if (url.startsWith('allow:')) { + return Promise.resolve({ url: url.replace('allow:', 'https:'), userHasAccess: true, }); - } else if (url.startsWith('deny:')) { - return Promise.resolve({ - url: url, + } + + if (url.startsWith('deny:')) { + return Promise.resolve({ + url, userHasAccess: false, }); - } else if (url.startsWith('slow:')) { - return new Promise((resolve) => { + } + + if (url.startsWith('slow:')) { + return new Promise((resolve) => { setTimeout(() => { resolve({ url: url.replace('slow:', 'https:'), @@ -36,16 +43,18 @@ export class CustomSkyHrefResolverService implements SkyHrefResolver { }); }, 3000); }); - } else if (url.startsWith('1bb-nav:')) { - return Promise.resolve({ + } + + if (url.startsWith('1bb-nav:')) { + return Promise.resolve({ url: `https://docs.blackbaud.com/engineering-system-docs/learn/spa/spa-navigation/spa-to-spa-navigation`, userHasAccess: true, }); - } else { - return Promise.resolve({ - url: url, - userHasAccess: false, - }); } + + return Promise.resolve({ + url, + userHasAccess: false, + }); } } diff --git a/apps/code-examples/src/app/code-examples/split-view/split-view/basic/demo.component.ts b/apps/code-examples/src/app/code-examples/split-view/split-view/basic/demo.component.ts index 28d8170c28..4340830e04 100644 --- a/apps/code-examples/src/app/code-examples/split-view/split-view/basic/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/split-view/split-view/basic/demo.component.ts @@ -21,6 +21,11 @@ import { Subject } from 'rxjs'; import { Record } from './record'; +interface DemoForm { + approvedAmount: FormControl; + comments: FormControl; +} + @Component({ standalone: true, selector: 'app-demo', @@ -87,7 +92,7 @@ export class DemoComponent { ]; protected activeRecord: Record; - protected splitViewDemoForm: FormGroup; + protected splitViewDemoForm: FormGroup; protected splitViewStream = new Subject(); #_activeIndex = 0; @@ -98,9 +103,14 @@ export class DemoComponent { // Start with the first item selected. this.activeIndex = 0; this.activeRecord = this.items[this.activeIndex]; + this.splitViewDemoForm = new FormGroup({ - approvedAmount: new FormControl(this.activeRecord.approvedAmount), - comments: new FormControl(this.activeRecord.comments), + approvedAmount: new FormControl(this.activeRecord.approvedAmount, { + nonNullable: true, + }), + comments: new FormControl(this.activeRecord.comments, { + nonNullable: true, + }), }); } @@ -124,8 +134,10 @@ export class DemoComponent { #loadFormGroup(record: Record): void { this.splitViewDemoForm = new FormGroup({ - approvedAmount: new FormControl(record.approvedAmount), - comments: new FormControl(record.comments), + approvedAmount: new FormControl(record.approvedAmount, { + nonNullable: true, + }), + comments: new FormControl(record.comments, { nonNullable: true }), }); } @@ -164,9 +176,9 @@ export class DemoComponent { #saveForm(): void { this.activeRecord.approvedAmount = - this.splitViewDemoForm.value.approvedAmount; + this.splitViewDemoForm.value.approvedAmount ?? 0; + this.activeRecord.comments = this.splitViewDemoForm.value.comments ?? ''; - this.activeRecord.comments = this.splitViewDemoForm.value.comments; this.splitViewDemoForm.reset(this.splitViewDemoForm.value); } diff --git a/apps/code-examples/src/app/code-examples/split-view/split-view/page-bound/demo.component.ts b/apps/code-examples/src/app/code-examples/split-view/split-view/page-bound/demo.component.ts index 13e69f47f3..2b1586a1d6 100644 --- a/apps/code-examples/src/app/code-examples/split-view/split-view/page-bound/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/split-view/split-view/page-bound/demo.component.ts @@ -26,6 +26,11 @@ import { Subject } from 'rxjs'; import { Record } from './record'; +interface DemoForm { + approvedAmount: FormControl; + comments: FormControl; +} + @Component({ standalone: true, selector: 'app-demo', @@ -141,7 +146,7 @@ export class DemoComponent { ]; protected activeRecord: Record; - protected splitViewDemoForm: FormGroup; + protected splitViewDemoForm: FormGroup; protected splitViewStream = new Subject(); protected unapprovedTransaction = true; @@ -155,8 +160,12 @@ export class DemoComponent { this.activeRecord = this.items[this.activeIndex]; this.splitViewDemoForm = new FormGroup({ - approvedAmount: new FormControl(this.activeRecord.approvedAmount), - comments: new FormControl(this.activeRecord.comments), + approvedAmount: new FormControl(this.activeRecord.approvedAmount, { + nonNullable: true, + }), + comments: new FormControl(this.activeRecord.comments, { + nonNullable: true, + }), }); } @@ -180,8 +189,10 @@ export class DemoComponent { #loadFormGroup(record: Record): void { this.splitViewDemoForm = new FormGroup({ - approvedAmount: new FormControl(record.approvedAmount), - comments: new FormControl(record.comments), + approvedAmount: new FormControl(record.approvedAmount, { + nonNullable: true, + }), + comments: new FormControl(record.comments, { nonNullable: true }), }); } @@ -220,9 +231,10 @@ export class DemoComponent { #saveForm(): void { this.activeRecord.approvedAmount = parseFloat( - this.splitViewDemoForm.value.approvedAmount, + `${this.splitViewDemoForm.value.approvedAmount ?? 0}`, ); - this.activeRecord.comments = this.splitViewDemoForm.value.comments; + + this.activeRecord.comments = this.splitViewDemoForm.value.comments ?? ''; this.unapprovedTransaction = this.items.findIndex((item) => item.amount !== item.approvedAmount) >= 0; diff --git a/apps/code-examples/src/app/code-examples/tabs/sectioned-form/modal/information-form.component.ts b/apps/code-examples/src/app/code-examples/tabs/sectioned-form/modal/information-form.component.ts index c35d38b205..65a302ed94 100644 --- a/apps/code-examples/src/app/code-examples/tabs/sectioned-form/modal/information-form.component.ts +++ b/apps/code-examples/src/app/code-examples/tabs/sectioned-form/modal/information-form.component.ts @@ -8,6 +8,7 @@ import { } from '@angular/core'; import { FormBuilder, + FormControl, FormGroup, ReactiveFormsModule, Validators, @@ -32,7 +33,11 @@ import { SkySectionedFormService } from '@skyux/tabs'; }) export class InformationFormComponent implements OnInit { protected id = '5324901'; - protected formGroup: FormGroup; + protected formGroup: FormGroup<{ + name: FormControl; + nameRequired: FormControl; + id: FormControl; + }>; protected name = ''; protected nameRequired = false; @@ -41,18 +46,20 @@ export class InformationFormComponent implements OnInit { constructor() { this.formGroup = inject(FormBuilder).group({ - name: [this.name], - nameRequired: [this.nameRequired], - id: [this.id, Validators.pattern('^[0-9]+$')], + name: new FormControl(this.name, { nonNullable: true }), + nameRequired: new FormControl(this.nameRequired, { nonNullable: true }), + id: new FormControl(this.id, { + nonNullable: true, + validators: [Validators.pattern('^[0-9]+$')], + }), }); } public ngOnInit(): void { this.formGroup.valueChanges.subscribe((changes) => { - console.log(changes); - this.id = changes.id; - this.name = changes.name; - this.nameRequired = changes.nameRequired; + this.id = changes.id ?? ''; + this.name = changes.name ?? ''; + this.nameRequired = !!changes.nameRequired; this.#checkValidity(); }); diff --git a/apps/code-examples/src/app/code-examples/text-editor/text-editor/demo.component.ts b/apps/code-examples/src/app/code-examples/text-editor/text-editor/demo.component.ts index 5294a37baa..73302a1100 100644 --- a/apps/code-examples/src/app/code-examples/text-editor/text-editor/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/text-editor/text-editor/demo.component.ts @@ -12,6 +12,12 @@ import { } from '@angular/forms'; import { SkyTextEditorModule } from '@skyux/text-editor'; +function validateText( + control: AbstractControl, +): ValidationErrors | null { + return !control.value?.includes('Blackbaud') ? { companyName: true } : null; +} + @Component({ standalone: true, selector: 'app-demo', @@ -32,18 +38,11 @@ export class DemoComponent { constructor() { this.myText = new FormControl(this.#richText, { nonNullable: true, - validators: [Validators.required, this.#validateText], + validators: [Validators.required, validateText], }); + this.formGroup = inject(FormBuilder).group({ myText: this.myText, }); } - - #validateText(control: AbstractControl): ValidationErrors | null { - if (!control.value || !control.value.includes('Blackbaud')) { - return { companyName: true }; - } else { - return null; - } - } } From 3b3823c61c29ca29863b0a9dcdb0468836fc95f8 Mon Sep 17 00:00:00 2001 From: John White <750350+johnhwhite@users.noreply.github.com> Date: Wed, 10 Jul 2024 10:32:05 -0400 Subject: [PATCH 4/5] ci: fix cherry-pick title (#2455) --- .github/workflows/cherry-pick.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cherry-pick.yml b/.github/workflows/cherry-pick.yml index 8737e15e0c..7f45f66797 100644 --- a/.github/workflows/cherry-pick.yml +++ b/.github/workflows/cherry-pick.yml @@ -93,7 +93,7 @@ jobs: repo: context.repo.repo, head: process.env.CHERRY_PICK_BRANCH, base: process.env.TARGET_BRANCH, - title: `${process.env.COMMIT_MESSAGE} (#${pr.number})`, + title: process.env.COMMIT_MESSAGE, body }).then(result => { console.log(`Created PR #${result.data.number}: ${result.data.html_url}`); From 4d2d70a378d69af7b30370ed44641b036703ce47 Mon Sep 17 00:00:00 2001 From: Steve Brush Date: Wed, 10 Jul 2024 12:16:10 -0400 Subject: [PATCH 5/5] fix(components/datetime): ignore extraneous properties when setting calculator value (#2459) --- .../date-range-picker.component.spec.ts | 9 +++++++++ .../date-range-picker/date-range-picker.component.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libs/components/datetime/src/lib/modules/date-range-picker/date-range-picker.component.spec.ts b/libs/components/datetime/src/lib/modules/date-range-picker/date-range-picker.component.spec.ts index 4ed575401d..a7cd9b70a9 100644 --- a/libs/components/datetime/src/lib/modules/date-range-picker/date-range-picker.component.spec.ts +++ b/libs/components/datetime/src/lib/modules/date-range-picker/date-range-picker.component.spec.ts @@ -714,6 +714,15 @@ describe('Date range picker', function () { ); })); + it('should ignore extraneous properties when setting the value', () => { + component.dateRange?.setValue({ + foo: 'bar', + calculatorId: SkyDateRangeCalculatorId.LastWeek, + }); + + expect(() => fixture.detectChanges()).not.toThrow(); + }); + describe('accessibility', () => { function verifyFormFieldsRequired(expectation: boolean): void { const inputBoxes = diff --git a/libs/components/datetime/src/lib/modules/date-range-picker/date-range-picker.component.ts b/libs/components/datetime/src/lib/modules/date-range-picker/date-range-picker.component.ts index 7a2ab2490a..575f67c8ae 100644 --- a/libs/components/datetime/src/lib/modules/date-range-picker/date-range-picker.component.ts +++ b/libs/components/datetime/src/lib/modules/date-range-picker/date-range-picker.component.ts @@ -604,7 +604,7 @@ export class SkyDateRangePickerComponent } if (options?.emitEvent) { - this.formGroup.setValue(valueOrDefault); + this.formGroup.patchValue(valueOrDefault); } } }