From 669fcf9d3e007dcb86212f0681157b761afbd28d Mon Sep 17 00:00:00 2001 From: Gage Date: Fri, 9 Jun 2023 11:52:40 -0700 Subject: [PATCH] v1.16.0 (#916) * Update go-button.component.scss Changes for split button option text not to wrap and grow towards left. * GOP-877-BUG-minimum_height_for_textarea Fixed GOP-876 uniform card margins, GOP-877 set minimum_height_for_textarea and GOP-847 file uploading component bug fix. * Changes_bugfix_chore_task * alignment corrected for icon button css changes for button padding * codeclimate issue fix * Codeclimate fix * remove extra padding * Initial components and module interaction * Accordion_style changes Accordion styles Default Slim Dark * Changed dark theme * Changes [CHORE] 868 max height for toast Max height for the toast notification will not have an overflow unless specified. * Changes [CHORE] 767 action sheet design changes #767 1. Handled appearance of scrollbar on accordion's expansion by adjusting the height. 2. Font style changes for the shell area. 3. Fixed the colour issue for the danger action sheet. * Update _forms.scss * Changes [CHORE] 767 action sheet design changes #891 Code review suggestion changes * Determinate and indeterminate progress bar * style update * Changes [CHORE] 868 max height for toast #890 1. Code review suggested changes. 2. Change in the code's header part in the documentation. * UT * safari styling fix * Fixing code climate issues * Changes [CHORE] 868 max height for toast #890 Code review suggested changes. * Changes [CHORE] 767 action sheet design changes #891 Code review suggestion changes * comment line message * clear code climate issues * code climate fix * dark theme color changes done * issue fixed * removed white spaces * BUGFIX_TIME_PICKER_ALIGNMENT-CHORE_BACKGROUND_COLOR_CHANGE * ALIGNMENT AND NAMING CHANGES * Fix for duplicate modal and offcanvas content * ALIGNMENT_CHANGES * removing whitespace * Re-run Checks * Re-run Checks * Increasing test coverage * Update github src * GOP-807 empty checkin to trigger build * Fix select all filtered list (#914) * bug fixes for select all filtered list * single item, add remove handled * handling controls initial value incase of typeahead provided * changes in handling controls initial value * small condition fix * test cases updated and condition change in init control value * formatting changes * formatting changes * edge case handled while removing selected item * formatting changes * adding count to select all * adding count to select all * linting errors fixed * typo fixed * refactored code for better understanding * refactoring * lint fix * indentation changes, private methods and variables grouped, minor ux changes * renaming methods * karma config thresold changes --------- Co-authored-by: Vishal Shah * v1.16.0 (#915) * Incrementing minor version Changes were made to upgrade "select all filter list" * Fixing patch version to be 0 Forgot to do this before... --------- Co-authored-by: sudheepdivakargithub Co-authored-by: adhiyan-tangoe Co-authored-by: Saravanan Muralidharan Co-authored-by: Pooja-kj <104506177+Pooja-kj@users.noreply.github.com> Co-authored-by: Vijeta7 Co-authored-by: jay.kravetz@tangoe.com Co-authored-by: RonMichaud <89989734+RonMichaud@users.noreply.github.com> Co-authored-by: Vishal Shah --- projects/go-lib/karma.conf.js | 2 +- projects/go-lib/package.json | 2 +- .../go-accordion-panel.component.scss | 18 ++- .../go-action-sheet.component.scss | 6 +- .../go-panel/go-panel.component.scss | 8 +- .../go-badge/go-badge.component.spec.ts | 38 +++++ .../go-button/go-button.component.scss | 21 ++- .../components/go-card/go-card.component.scss | 1 - .../go-file-upload.component.ts | 4 +- .../components/go-hint/go-hint.component.scss | 6 +- .../go-modal/go-modal.component.scss | 2 +- .../components/go-modal/go-modal.component.ts | 2 +- .../go-off-canvas.component.scss | 2 +- .../go-off-canvas/go-off-canvas.component.ts | 1 + .../go-progress-bar.component.html | 35 ++++ .../go-progress-bar.component.scss | 125 +++++++++++++++ .../go-progress-bar.component.spec.ts | 49 ++++++ .../go-progress-bar.component.ts | 23 +++ .../go-progress-bar/go-progress-bar.module.ts | 16 ++ .../go-select/go-select.component.html | 22 ++- .../go-select/go-select.component.spec.ts | 108 ++++++++++++- .../go-select/go-select.component.ts | 151 +++++++++++++++++- .../go-side-nav/go-side-nav.component.html | 1 + .../go-side-nav/go-side-nav.component.scss | 6 + .../go-text-area/go-text-area.component.html | 2 +- .../go-timepicker/go-time.component.html | 4 +- .../go-timepicker/go-time.component.scss | 5 + .../go-toast/go-toast.component.html | 2 +- .../components/go-toast/go-toast.component.ts | 2 +- projects/go-lib/src/lib/go-shared.module.ts | 7 +- projects/go-lib/src/public_api.ts | 4 + projects/go-lib/styles/_forms.scss | 23 +-- projects/go-lib/styles/_hints.scss | 5 +- projects/go-lib/styles/_typography.scss | 4 + projects/go-lib/styles/_variables.scss | 1 + .../go-style-guide/src/app/app.component.html | 2 + .../go-style-guide/src/app/app.component.scss | 6 + .../go-style-guide/src/app/app.component.ts | 1 + .../progress-bar-docs.component.html | 139 ++++++++++++++++ .../progress-bar-docs.component.ts | 35 ++++ .../toast-docs/toast-docs.component.html | 10 +- .../toast-docs/toast-docs.component.ts | 8 +- .../ui-kit/routes/ui-kit-routing.module.ts | 4 +- .../src/app/features/ui-kit/ui-kit.module.ts | 6 +- 44 files changed, 842 insertions(+), 77 deletions(-) create mode 100644 projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.html create mode 100644 projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.scss create mode 100644 projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.spec.ts create mode 100644 projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.ts create mode 100644 projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.module.ts create mode 100644 projects/go-style-guide/src/app/features/ui-kit/components/progress-bar-docs/progress-bar-docs.component.html create mode 100644 projects/go-style-guide/src/app/features/ui-kit/components/progress-bar-docs/progress-bar-docs.component.ts diff --git a/projects/go-lib/karma.conf.js b/projects/go-lib/karma.conf.js index fb859c3ea..0e00ef2b4 100644 --- a/projects/go-lib/karma.conf.js +++ b/projects/go-lib/karma.conf.js @@ -22,7 +22,7 @@ module.exports = function (config) { thresholds: { statements: 93, lines: 92, - branches: 79, + branches: 75, functions: 88, }, }, diff --git a/projects/go-lib/package.json b/projects/go-lib/package.json index d91b40538..c8aebcebd 100644 --- a/projects/go-lib/package.json +++ b/projects/go-lib/package.json @@ -1,6 +1,6 @@ { "name": "@tangoe/goponents", - "version": "1.15.1", + "version": "1.16.0", "repository": { "type": "git", "url": "git+https://github.com/mobi/goponents.git" diff --git a/projects/go-lib/src/lib/components/go-accordion/go-accordion-panel.component.scss b/projects/go-lib/src/lib/components/go-accordion/go-accordion-panel.component.scss index 045702975..e86f43ccc 100644 --- a/projects/go-lib/src/lib/components/go-accordion/go-accordion-panel.component.scss +++ b/projects/go-lib/src/lib/components/go-accordion/go-accordion-panel.component.scss @@ -67,7 +67,7 @@ cursor: pointer; display: flex; - font-size: 1.2rem; + font-size: 1.125rem; padding: 1.2rem 1rem; position: relative; @@ -76,10 +76,10 @@ } &--dark { - background-color: darken($base-dark-secondary, 7%); + background-color: $base-dark; &:hover { - background-color: darken($base-dark-secondary, 3.5%); + background-color: darken($base-dark, 3.5%); } } @@ -88,13 +88,17 @@ // scss-lint:disable SelectorFormat &.go-accordion-panel__header--dark { + background-color: darken($base-dark-secondary, 3.5%); + } + + &.go-accordion-panel__header--dark:hover { background-color: darken($base-dark-secondary, 7%); } } &--slim { - font-size: 1rem; - padding: 1rem; + font-size: 0.875rem; + padding: 0.625rem 1rem; } } @@ -132,9 +136,11 @@ } &__content { - padding: 1.5rem 1rem; + font-size: 0.875rem; + padding: 1rem; &--slim { + font-size: 0.875rem; padding: 1rem; } diff --git a/projects/go-lib/src/lib/components/go-action-sheet/go-action-sheet.component.scss b/projects/go-lib/src/lib/components/go-action-sheet/go-action-sheet.component.scss index 830d1914e..d4182ab0f 100644 --- a/projects/go-lib/src/lib/components/go-action-sheet/go-action-sheet.component.scss +++ b/projects/go-lib/src/lib/components/go-action-sheet/go-action-sheet.component.scss @@ -10,13 +10,13 @@ $as-before-box-diag-width: 21.21px; position: relative; &__scroll-container { - max-height: 375px; - overflow: auto; + overflow: hidden; } &__content { border-radius: $global-radius; - overflow: hidden; + max-height: 375px; + overflow: auto; } &__content-container { diff --git a/projects/go-lib/src/lib/components/go-action-sheet/go-panel/go-panel.component.scss b/projects/go-lib/src/lib/components/go-action-sheet/go-panel/go-panel.component.scss index 6c3c5f678..45fdb42fe 100644 --- a/projects/go-lib/src/lib/components/go-action-sheet/go-panel/go-panel.component.scss +++ b/projects/go-lib/src/lib/components/go-action-sheet/go-panel/go-panel.component.scss @@ -61,12 +61,8 @@ $theme-light-transparentized: rgba($theme-light-color, .5); color: $ui-color-negative; } - .go-panel { - &__title { - & &-text { - color: $ui-color-negative; - } - } + .go-panel__title-text { + color: $ui-color-negative; } } diff --git a/projects/go-lib/src/lib/components/go-badge/go-badge.component.spec.ts b/projects/go-lib/src/lib/components/go-badge/go-badge.component.spec.ts index 4d3dab15a..a160ce377 100644 --- a/projects/go-lib/src/lib/components/go-badge/go-badge.component.spec.ts +++ b/projects/go-lib/src/lib/components/go-badge/go-badge.component.spec.ts @@ -22,4 +22,42 @@ describe('GoBadgeComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + describe("badgeClasses()", () => { + beforeEach(() => { + component.badgeStyles = {}; + }); + + it("returns an object that sets go-badge--positive to true based on type", () => { + expect(component.badgeStyles["go-badge--positive"]).toBeFalsy(); + + component.badgeColor = "positive"; + component.ngOnChanges(); + expect(component.badgeStyles["go-badge--positive"]).toBe(true); + }); + + it("returns an object that set go-badge--negative to true based on type", () => { + expect(component.badgeStyles["go-badge--negative"]).toBeFalsy(); + + component.badgeColor = "negative"; + component.ngOnChanges(); + expect(component.badgeStyles["go-badge--negative"]).toBe(true); + }); + + it("returns an object that set go-badge--neutral to true based on type", () => { + expect(component.badgeStyles["go-badge--neutral"]).toBeFalsy(); + + component.badgeColor = "neutral"; + component.ngOnChanges(); + expect(component.badgeStyles["go-badge--neutral"]).toBe(true); + }); + + it("returns an object that set go-badge--dot to true based on type", () => { + expect(component.badgeStyles["go-badge--dot"]).toBeFalsy(); + + component.displayData = false; + component.ngOnChanges(); + expect(component.badgeStyles["go-badge--dot"]).toBe(true); + }); + }); }); diff --git a/projects/go-lib/src/lib/components/go-button/go-button.component.scss b/projects/go-lib/src/lib/components/go-button/go-button.component.scss index a5194aa35..2ab1ba75e 100644 --- a/projects/go-lib/src/lib/components/go-button/go-button.component.scss +++ b/projects/go-lib/src/lib/components/go-button/go-button.component.scss @@ -54,7 +54,7 @@ $button-shadow-secondary-active: 0 0 0 3px transparentize($theme-light-bg-hover, } &--icon-only { - padding: calc(.625rem - 2px) .625rem; + padding: calc(.625rem - 2px) 1rem; } &__icon ~ &__text:not(:empty) { @@ -142,22 +142,21 @@ $button-shadow-secondary-active: 0 0 0 3px transparentize($theme-light-bg-hover, } &:disabled:not(.go-button--loading) { - border: 1px solid $theme-light-bg-active; + @include disabled-states($theme-light-bg-active, 'dark'); + border: 1px solid $base-light-tertiary; &:hover, &:focus { - border: 1px solid $theme-light-bg-active; + @include disabled-states($theme-light-bg-active, 'dark'); + border: 1px solid $base-light-tertiary; + box-shadow: none; } } } - &--tertiary { - border: 1px solid $theme-light-bg; - } - - &--secondary, &--tertiary { background: $theme-light-bg; + border: 1px solid $theme-light-bg; color: $theme-light-color; &:hover, @@ -442,13 +441,13 @@ $button-shadow-secondary-active: 0 0 0 3px transparentize($theme-light-bg-hover, } &:disabled:not(.go-button--loading) { - border: 1px solid $theme-light-bg-active; + border: 1px solid $base-light-tertiary; border-left: 0; &:hover, &:focus { background: $theme-light-bg-hover; - border: 1px solid $theme-light-bg-active; + border: 1px solid $base-light-tertiary; border-left: 0; box-shadow: none; } @@ -468,6 +467,7 @@ $button-shadow-secondary-active: 0 0 0 3px transparentize($theme-light-bg-hover, right: 0; top: calc(2rem + 2px); visibility: hidden; + white-space: nowrap; &--active { opacity: 1; @@ -482,7 +482,6 @@ $button-shadow-secondary-active: 0 0 0 3px transparentize($theme-light-bg-hover, cursor: pointer; font-size: .875rem; font-weight: normal; - max-width: 10rem; padding: .75rem; &:hover { diff --git a/projects/go-lib/src/lib/components/go-card/go-card.component.scss b/projects/go-lib/src/lib/components/go-card/go-card.component.scss index d3c6215c2..1bd465b06 100644 --- a/projects/go-lib/src/lib/components/go-card/go-card.component.scss +++ b/projects/go-lib/src/lib/components/go-card/go-card.component.scss @@ -12,7 +12,6 @@ &__header { display: flex; justify-content: space-between; - padding-bottom: 1rem; } &__action-list { diff --git a/projects/go-lib/src/lib/components/go-file-upload/go-file-upload.component.ts b/projects/go-lib/src/lib/components/go-file-upload/go-file-upload.component.ts index 6f40606e5..526f0e810 100644 --- a/projects/go-lib/src/lib/components/go-file-upload/go-file-upload.component.ts +++ b/projects/go-lib/src/lib/components/go-file-upload/go-file-upload.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { AbstractControl, FormArray, FormBuilder, FormGroup } from '@angular/forms'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -20,6 +20,7 @@ export class GoFileUploadComponent extends GoFormBaseComponent implements OnInit @Input() isLoading: boolean = false; @Input() multiple: boolean = false; @Input() state: 'selecting' | 'selected' = 'selecting'; + @ViewChild('filePicker') filePicker: any; ngOnInit(): void { this.fb = new FormBuilder(); @@ -51,6 +52,7 @@ export class GoFileUploadComponent extends GoFormBaseComponent implements OnInit this.filePreview.push(file.name); }); } + this.filePicker.nativeElement.value = ''; } removeFile(index: number): void { diff --git a/projects/go-lib/src/lib/components/go-hint/go-hint.component.scss b/projects/go-lib/src/lib/components/go-hint/go-hint.component.scss index fd1f58fd3..e3dd4b9ac 100644 --- a/projects/go-lib/src/lib/components/go-hint/go-hint.component.scss +++ b/projects/go-lib/src/lib/components/go-hint/go-hint.component.scss @@ -1,7 +1,8 @@ @import '../../../../styles/variables'; .go-hint { - font-size: .875rem; + font-size: .75rem; + font-style: italic; letter-spacing: $base-letter-spacing; line-height: 1rem; margin: $column-gutter--quarter 0; @@ -43,7 +44,8 @@ &__label { display: block; - font-size: .75rem; + font-size: 9px; + font-style: initial; font-weight: $weight-regular; margin-bottom: $column-gutter--quarter; text-transform: uppercase; diff --git a/projects/go-lib/src/lib/components/go-modal/go-modal.component.scss b/projects/go-lib/src/lib/components/go-modal/go-modal.component.scss index 6ccf6200b..922d08f0e 100644 --- a/projects/go-lib/src/lib/components/go-modal/go-modal.component.scss +++ b/projects/go-lib/src/lib/components/go-modal/go-modal.component.scss @@ -6,7 +6,7 @@ @include z-index(modal); align-items: center; - background: transparentize($base-dark, .1); + background: rgba($base-color, .5); display: flex; height: 100%; justify-content: center; diff --git a/projects/go-lib/src/lib/components/go-modal/go-modal.component.ts b/projects/go-lib/src/lib/components/go-modal/go-modal.component.ts index a2eb4655a..981266409 100644 --- a/projects/go-lib/src/lib/components/go-modal/go-modal.component.ts +++ b/projects/go-lib/src/lib/components/go-modal/go-modal.component.ts @@ -65,7 +65,7 @@ export class GoModalComponent extends GoModalOptions implements OnInit, OnDestro loadComponent(): void { const componentFactory: ComponentFactory<{}> = this.componentFactoryResolver.resolveComponentFactory(this.currentComponent.component); const viewContainerRef: ViewContainerRef = this.goModalHost.viewContainerRef; - + viewContainerRef.clear(); const componentRef: ComponentRef<{}> = viewContainerRef.createComponent(componentFactory); Object.keys(this.currentComponent.bindings).forEach((key: string) => { diff --git a/projects/go-lib/src/lib/components/go-off-canvas/go-off-canvas.component.scss b/projects/go-lib/src/lib/components/go-off-canvas/go-off-canvas.component.scss index d2c5bb76d..01e94d4f7 100644 --- a/projects/go-lib/src/lib/components/go-off-canvas/go-off-canvas.component.scss +++ b/projects/go-lib/src/lib/components/go-off-canvas/go-off-canvas.component.scss @@ -4,7 +4,7 @@ .go-off-canvas-backdrop { @include z-index(off-canvas); - background: rgba($base-dark, .5); + background: rgba($base-color, .5); height: 100vh; left: 0; position: fixed; diff --git a/projects/go-lib/src/lib/components/go-off-canvas/go-off-canvas.component.ts b/projects/go-lib/src/lib/components/go-off-canvas/go-off-canvas.component.ts index 838a71cc6..9cf8b18ff 100644 --- a/projects/go-lib/src/lib/components/go-off-canvas/go-off-canvas.component.ts +++ b/projects/go-lib/src/lib/components/go-off-canvas/go-off-canvas.component.ts @@ -93,6 +93,7 @@ export class GoOffCanvasComponent extends GoOffCanvasOptions implements OnInit, this.currentOffCanvasItem.component ); const viewContainerRef: ViewContainerRef = this.goOffCanvasHost.viewContainerRef; + viewContainerRef.clear(); const componentRef: ComponentRef = viewContainerRef.createComponent(componentFactory); Object.keys(this.currentOffCanvasItem.bindings).forEach((key: string) => { diff --git a/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.html b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.html new file mode 100644 index 000000000..6324e35f9 --- /dev/null +++ b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.html @@ -0,0 +1,35 @@ +
+ + +
+ + +
+ + {{ leftLabel }} +
+
+
+ {{ + rightLabel + }} +
+
+ + +
+
+
+
+
+
diff --git a/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.scss b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.scss new file mode 100644 index 000000000..ddb970614 --- /dev/null +++ b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.scss @@ -0,0 +1,125 @@ +@import '../../../../styles/variables'; +@import '../../../../styles/mixins'; + +@mixin label-style($float, $padding) { + float: $float; + padding: $padding; + font-weight: $weight-regular; + white-space: nowrap; +} + +@mixin determinate-elem($width, $background-color) { + width: $width; + height: 10px; + background-color: $background-color; +} + +@mixin indeterminate-elem($background-color) { + height: 100%; + position: absolute; + width: 100%; + background-color: $background-color; +} + +.go-progress-bar { + &__determinate { + align-items: center; + display: flex; + flex-direction: row; + justify-content: center; + position: relative; + width: 100%; + + &__left-label { + @include label-style(left, 0 8px 0 0); + } + + &__right-label { + @include label-style(right, 0 0 0 8px); + } + + &--track { + @include determinate-elem(100%, $theme-light-app-bg); + border-radius: 5px; + overflow: hidden; + } + + &--indicator { + @include determinate-elem(0%, $ui-color-primary); + transition: width 2s ease-in; + transition-timing-function: ease-in; + } + } + + &__indeterminate { + backface-visibility: hidden; + border-radius: 5px; + height: 10px; + overflow: hidden; + position: relative; + transform: translate3d(0, 0, 0); + width: 100%; + + &--track { + @include indeterminate-elem($theme-light-app-bg); + } + + &--indicator { + @include indeterminate-elem($ui-color-primary); + backface-visibility: hidden; + transform-origin: top left; + transition: transform 250ms ease; + } + + &--primary-indicator { + animation: primary-indeterminate-translate 2000ms infinite linear; + left: -99.166611%; + } + + &--secondary-indicator { + animation: secondary-indeterminate-translate 2000ms infinite linear; + left: 0; + } + } +} + +@keyframes primary-indeterminate-translate { + 0% { + transform: translateX(0) scaleX(0.4); + } + + 20% { + animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819); + transform: translateX(20%) scaleX(0.2); + } + + 60% { + animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352); + transform: translateX(80%) scaleX(0.9); + } + + 100% { + transform: translateX(200%) scaleX(0.2); + } +} + +@keyframes secondary-indeterminate-translate { + 0% { + animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685); + transform: translateX(0) scaleX(0); + } + + 25% { + animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712); + transform: translateX(25%) scaleX(0.5); + } + + 60.35% { + animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026); + transform: translateX(100%) scaleX(0.8); + } + + 100% { + transform: translateX(200%); + } +} diff --git a/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.spec.ts b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.spec.ts new file mode 100644 index 000000000..e294b0453 --- /dev/null +++ b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.spec.ts @@ -0,0 +1,49 @@ +import { SimpleChange, SimpleChanges } from "@angular/core"; +import { + async, + ComponentFixture, + fakeAsync, + TestBed, + tick, +} from "@angular/core/testing"; + +import { GoProgressBarComponent } from "./go-progress-bar.component"; + +describe("GoProgressBarComponent", () => { + let component: GoProgressBarComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [GoProgressBarComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(GoProgressBarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component).toBeTruthy(); + }); + + describe("ngOnChanges()", () => { + it("should test when value is undefined", fakeAsync(() => { + component.ngOnChanges({ + value: new SimpleChange(undefined, undefined, false), + }); + + tick(500); + expect(component.indicatorWidth).toBe(undefined); + })); + + it("should test when value is defined", fakeAsync(() => { + component.ngOnChanges({ value: new SimpleChange(undefined, 40, true) }); + + tick(501); + expect(component.indicatorWidth).toEqual(40); + })); + }); +}); diff --git a/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.ts b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.ts new file mode 100644 index 000000000..8b1871b5a --- /dev/null +++ b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.component.ts @@ -0,0 +1,23 @@ +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; + +@Component({ + selector: 'go-progress-bar', + templateUrl: './go-progress-bar.component.html', + styleUrls: ['./go-progress-bar.component.scss'], +}) +export class GoProgressBarComponent implements OnChanges { + @Input() mode: 'determinate' | 'indeterminate' = 'determinate'; + @Input() value: number; + @Input() leftLabel?: string; + @Input() rightLabel?: string; + + indicatorWidth: number; + + ngOnChanges(changes: SimpleChanges): void { + if ('value' in changes) { + setTimeout(() => { + this.indicatorWidth = changes.value.currentValue; + }, 500); + } + } +} diff --git a/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.module.ts b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.module.ts new file mode 100644 index 000000000..6f0717d5c --- /dev/null +++ b/projects/go-lib/src/lib/components/go-progress-bar/go-progress-bar.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { GoProgressBarComponent } from './go-progress-bar.component'; + + + +@NgModule({ + declarations: [GoProgressBarComponent], + imports: [ + CommonModule + ], + exports: [ + GoProgressBarComponent + ] +}) +export class GoProgressBarModule { } diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.html b/projects/go-lib/src/lib/components/go-select/go-select.component.html index 355136a30..c3ac2862b 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.html +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.html @@ -6,10 +6,11 @@ {{ label }} - + (close)="onClose()" + (scroll)="onScroll($event)" + #select +> + ng-header-tmp + > + @@ -78,4 +86,4 @@ [theme]="theme"> - \ No newline at end of file + diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts index 0192a663c..ab68c1bb9 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts @@ -7,6 +7,7 @@ import { GoFormErrorsModule } from '../go-form-errors/go-form-errors.module'; import { GoHintModule } from '../go-hint/go-hint.module'; import { GoRequiredTextModule } from '../go-required-text/go-required-text.module'; import { GoSelectComponent } from './go-select.component'; +import { Subject } from 'rxjs'; describe('GoSelectComponent', () => { let component: GoSelectComponent; @@ -25,8 +26,7 @@ describe('GoSelectComponent', () => { FormsModule, ReactiveFormsModule ] - }) - .compileComponents(); + }).compileComponents(); })); beforeEach(() => { @@ -41,6 +41,11 @@ describe('GoSelectComponent', () => { }); describe('onSelectAll()', () => { + + beforeEach(() => { + component.multiple = true; + }); + it('adds all of the available items to the form control value', () => { component.bindValue = undefined; component.items = [ @@ -66,15 +71,111 @@ describe('GoSelectComponent', () => { expect(component.control.value).toEqual([1, 2, 3]); }); + + it('should select only filtered list, when filtered and selectAll', () => { + component.bindValue = 'id'; + component.items = [ + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' } + ]; + const filteredItems: any[] = [ + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' } + ]; + component.ngSelect.searchTerm = 'apple'; + component.handleInput({ items: filteredItems, term: 'apple' }); + component.onSelectAll(); + expect(component.control.value).toEqual([2, 3]); + }); + + it('should select filtered list with existing items in control value, when filtered and selectAll', () => { + component.bindValue = 'id'; + component.control.patchValue([4]); + component.items = [ + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, + { id: 4, label: 'grapes' } + ]; + const filteredItems: any[] = [ + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' } + ]; + component.ngSelect.searchTerm = 'apple'; + component.handleInput({ items: filteredItems, term: 'apple' }); + component.onSelectAll(); + expect(component.control.value.length).toEqual(3); + }); + }); + + describe('onSelectAll() with typeahead', () => { + beforeEach(() => { + component.typeahead = new Subject(); + component.multiple = true; + }); + + it('should store items in previousSelectedItems', () => { + const initialItems: any[] = [ + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + ]; + component.items = initialItems; + component['handleTypeAheadSelectAll'](); + expect(component['previousSelectedItems']).toEqual(initialItems); + }); + + it('should add items in previousSelectedItems', () => { + component.handleItemAdd({ id: 1, label: 'banana' }); + expect(component['previousSelectedItems']).toEqual([ + { id: 1, label: 'banana' }, + ]); + }); + + it('should remove items from previousSelectedItems', () => { + component['previousSelectedItems'] = [{ id: 1, label: 'banana' }]; + component.handleItemRemove({ value: { id: 1, label: 'banana' } }); + expect(component['previousSelectedItems']).toEqual([]); + }); + + it('handleControlInitialValue(), should assign previousSelectedItems', () => { + component.control.patchValue([1]); + component.bindValue = 'id'; + component.items = [ + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + ]; + component['handleControlInitialValue'](); + expect(component['previousSelectedItems']).toEqual([ + { id: 1, label: 'banana' }, + ]); + }); + }); + + describe('processSelectAll', () => { + it('process select all and patch value in form', () => { + component.bindValue = 'id'; + const items: any[] = [ + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, + { id: 4, label: 'grapes' }, + ]; + + component['processSelectAll'](items); + + expect(component.control.value).toEqual([1, 2, 3, 4]); + }); }); describe('onRemoveAll', () => { it('uses removed the selected values', () => { component.bindValue = 'id'; + spyOn(component, 'resetTypeAheadItems'); component.items = [ { id: 1, label: 'Label 1' }, { id: 2, label: 'Label 2' }, - { id: 3, label: 'Label 3' } + { id: 3, label: 'Label 3' }, ]; component.onSelectAll(); @@ -82,6 +183,7 @@ describe('GoSelectComponent', () => { component.onRemoveAll(); expect(component.control.value).toBeNull(); + expect(component['resetTypeAheadItems']).toHaveBeenCalled(); }); }); }); diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index 9cb67b68a..6de5341bb 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -1,6 +1,18 @@ -import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef, ViewEncapsulation } from '@angular/core'; -import { Subject } from 'rxjs'; +import { + Component, + ContentChild, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { Subject, Subscription } from 'rxjs'; import { GoFormBaseComponent } from '../go-form-base/go-form-base.component'; +import { NgSelectComponent } from '@ng-select/ng-select'; @Component({ encapsulation: ViewEncapsulation.None, @@ -8,7 +20,8 @@ import { GoFormBaseComponent } from '../go-form-base/go-form-base.component'; templateUrl: './go-select.component.html', styleUrls: ['./go-select.component.scss'] }) -export class GoSelectComponent extends GoFormBaseComponent implements OnInit { +export class GoSelectComponent extends GoFormBaseComponent implements OnInit, OnDestroy { + @ViewChild(NgSelectComponent) ngSelect: NgSelectComponent; @Input() appendTo: string; @Input() bindLabel: string; @@ -34,22 +47,47 @@ export class GoSelectComponent extends GoFormBaseComponent implements OnInit { @Input() virtualScroll: boolean = false; @Output() scrollToEnd: EventEmitter = new EventEmitter(); - @Output() scroll: EventEmitter<{ start: number, end: number }> = new EventEmitter<{ start: number; end: number }>(); + @Output() scroll: EventEmitter<{ start: number, end: number }> = new EventEmitter<{ start: number, end: number }>(); @ContentChild('goSelectOption') goSelectOption: TemplateRef; @ContentChild('goSelectOptionGroup') goSelectOptionGroup: TemplateRef; @ContentChild('goSelectSelectedOption') goSelectSelectedOption: TemplateRef; + // store refined items after search + refinedItems: any[] = []; + // stores previous selected items when typeahead is enabled only in case of selectAll. + private previousSelectedItems: any[] = []; + private controlSubscription: Subscription; + ngOnInit(): void { this.closeOnSelect = this.multiple ? false : this.closeOnSelect; + this.handleControlInitialValue(); + this.subscribeToControlChanges(); + } + + ngOnDestroy(): void { + this.controlSubscription?.unsubscribe(); } onSelectAll(): void { - this.control.patchValue(this.items.map((item: any) => this.bindValue ? item[this.bindValue] : item)); + if (this.typeahead) { + this.handleTypeAheadSelectAll(); + return; + } + + const items: any[] = this.ngSelect.searchTerm ? this.refinedItems : this.items; + this.processSelectAll(items); + } + + handleInput(search: { term: string; items: any[] }): void { + if (this.multiple) { + this.refinedItems = search.items; + } } onRemoveAll(): void { this.control.reset(); + this.resetTypeAheadItems(); } onScrollToEnd(): void { @@ -61,4 +99,107 @@ export class GoSelectComponent extends GoFormBaseComponent implements OnInit { onScroll($event: { start: number; end: number }): void { this.scroll.emit($event); } + + onClose(): void { + this.emptyRefinedItems(); + } + + // store previous selected items incase of multiple and typeahead. + handleItemAdd(item: any): void { + if (!this.multiple || !this.typeahead) { + return; + } + this.previousSelectedItems.push(item); + } + + // remove item from previous selected items incase of multiple and typeahead. + handleItemRemove(item: any): void { + if (!this.multiple || !this.typeahead ) { + return; + } + + const index: number = this.previousSelectedItems.findIndex((prev: any) => prev[this.bindValue] === item.value[this.bindValue]); + this.previousSelectedItems.splice(index, 1); + } + + private subscribeToControlChanges(): void { + if (this.multiple && this.showSelectAll) { + this.controlSubscription = this.control.valueChanges.subscribe((value: any) => { + this.handleMultipleControlChanges(value); + }); + } + } + + private handleMultipleControlChanges(value: any): void { + this.emptyRefinedItems(); + if (!value?.length) { + this.resetTypeAheadItems(); + } + } + + private handleTypeAheadSelectAll(): void { + // because spread operator is not supported due to tslib version + const items: any[] = JSON.parse(JSON.stringify(this.items)); + for (const previousItem of this.previousSelectedItems) { + const exists: boolean = items.some( + (item: any) => item[this.bindValue] === previousItem[this.bindValue] + ); + if (!exists) { + items.unshift(previousItem); + } + } + this.previousSelectedItems = items; + this.items = items; + this.control.reset([], { emitEvent: false }); + this.processSelectAll(items); + } + + private resetTypeAheadItems(): void { + if (this.typeahead) { + this.items = []; + this.previousSelectedItems = []; + } + } + + private emptyRefinedItems(): void { + if (!this.ngSelect.searchTerm) { + this.refinedItems = []; + } + } + + private processSelectAll(items: any[]): void { + const refinedArr: any[] = items.map((item: any) => + this.bindValue ? item[this.bindValue] : item + ); + + const existing: any[] = Array.isArray(this.control.value) ? this.control.value : []; + const uniq: any[] = Array.from(new Set(existing.concat(refinedArr))); + this.control.patchValue(uniq); + this.ngSelect.searchTerm = ''; + this.ngSelect.itemsList.resetFilteredItems(); + } + + private shouldHandleControlInitialValue(): boolean { + return (this.typeahead || this.multiple) && Array.isArray(this.control.value); + } + + private findItemByValue(value: any): any { + return this.items.find((item: any) => item[this.bindValue] === value); + } + + private handleControlInitialValue(): void { + if (!this.shouldHandleControlInitialValue()) { + return; + } + + const selected: any[] = this.control.value; + + for (const value of selected) { + const exist: any = this.findItemByValue(value); + if (exist) { + this.previousSelectedItems.push(exist); + } + } + } + } diff --git a/projects/go-lib/src/lib/components/go-side-nav/go-side-nav/go-side-nav.component.html b/projects/go-lib/src/lib/components/go-side-nav/go-side-nav/go-side-nav.component.html index 42549bf3b..5ac52cad1 100644 --- a/projects/go-lib/src/lib/components/go-side-nav/go-side-nav/go-side-nav.component.html +++ b/projects/go-lib/src/lib/components/go-side-nav/go-side-nav/go-side-nav.component.html @@ -40,6 +40,7 @@

{{ appDrawerHeader }}