diff --git a/package.json b/package.json index 0a774137..23163280 100644 --- a/package.json +++ b/package.json @@ -14,17 +14,17 @@ "lint": "ng lint" }, "dependencies": { - "@angular/animations": "12.2.3", - "@angular/cdk": "12.2.3", - "@angular/common": "12.2.3", - "@angular/compiler": "12.2.3", - "@angular/core": "12.2.3", - "@angular/forms": "12.2.3", - "@angular/material": "12.2.3", - "@angular/material-moment-adapter": "12.2.3", - "@angular/platform-browser": "12.2.3", - "@angular/platform-browser-dynamic": "12.2.3", - "@angular/router": "12.2.3", + "@angular/animations": "12.2.4", + "@angular/cdk": "12.2.4", + "@angular/common": "12.2.4", + "@angular/compiler": "12.2.4", + "@angular/core": "12.2.4", + "@angular/forms": "12.2.4", + "@angular/material": "12.2.4", + "@angular/material-moment-adapter": "12.2.4", + "@angular/platform-browser": "12.2.4", + "@angular/platform-browser-dynamic": "12.2.4", + "@angular/router": "12.2.4", "@fullcalendar/angular": "4.4.5-beta", "@fullcalendar/core": "4.4.2", "@fullcalendar/daygrid": "4.4.2", @@ -51,14 +51,14 @@ "zone.js": "0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "12.2.3", + "@angular-devkit/build-angular": "12.2.4", "@angular-eslint/builder": "12.3.1", "@angular-eslint/eslint-plugin": "12.3.1", "@angular-eslint/eslint-plugin-template": "12.3.1", "@angular-eslint/schematics": "12.3.1", "@angular-eslint/template-parser": "12.3.1", - "@angular/cli": "12.2.3", - "@angular/compiler-cli": "12.2.3", + "@angular/cli": "12.2.4", + "@angular/compiler-cli": "12.2.4", "@tailwindcss/aspect-ratio": "0.2.1", "@tailwindcss/line-clamp": "0.2.1", "@tailwindcss/typography": "0.4.1", @@ -69,9 +69,9 @@ "@types/lodash": "4.14.172", "@types/lodash-es": "4.17.4", "@types/node": "12.20.21", - "@typescript-eslint/eslint-plugin": "4.30.0", - "@typescript-eslint/parser": "4.30.0", - "autoprefixer": "10.3.3", + "@typescript-eslint/eslint-plugin": "4.31.0", + "@typescript-eslint/parser": "4.31.0", + "autoprefixer": "10.3.4", "chroma-js": "2.1.2", "eslint": "7.32.0", "eslint-plugin-import": "2.24.2", diff --git a/src/@fuse/components/loading-bar/index.ts b/src/@fuse/components/loading-bar/index.ts new file mode 100644 index 00000000..780b263a --- /dev/null +++ b/src/@fuse/components/loading-bar/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/loading-bar/public-api'; diff --git a/src/@fuse/components/loading-bar/loading-bar.component.html b/src/@fuse/components/loading-bar/loading-bar.component.html new file mode 100644 index 00000000..3f884fef --- /dev/null +++ b/src/@fuse/components/loading-bar/loading-bar.component.html @@ -0,0 +1,5 @@ + + + diff --git a/src/@fuse/components/loading-bar/loading-bar.component.scss b/src/@fuse/components/loading-bar/loading-bar.component.scss new file mode 100644 index 00000000..7a46ec0e --- /dev/null +++ b/src/@fuse/components/loading-bar/loading-bar.component.scss @@ -0,0 +1,7 @@ +fuse-loading-bar { + position: fixed; + top: 0; + z-index: 999; + width: 100%; + height: 6px; +} diff --git a/src/@fuse/components/loading-bar/loading-bar.component.ts b/src/@fuse/components/loading-bar/loading-bar.component.ts new file mode 100644 index 00000000..c6a14e0e --- /dev/null +++ b/src/@fuse/components/loading-bar/loading-bar.component.ts @@ -0,0 +1,83 @@ +import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { FuseLoadingBarService } from '@fuse/components/loading-bar/loading-bar.service'; +import { takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; + +@Component({ + selector : 'fuse-loading-bar', + templateUrl : './loading-bar.component.html', + styleUrls : ['./loading-bar.component.scss'], + encapsulation: ViewEncapsulation.None, + exportAs : 'fuseLoadingBar' +}) +export class FuseLoadingBarComponent implements OnChanges, OnInit, OnDestroy +{ + @Input() autoMode: boolean = true; + mode: 'determinate' | 'indeterminate'; + progress: number = 0; + show: boolean = false; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor(private _fuseLoadingBarService: FuseLoadingBarService) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void + { + // Auto mode + if ( 'autoMode' in changes ) + { + // Set the auto mode in the service + this._fuseLoadingBarService.setAutoMode(coerceBooleanProperty(changes.autoMode.currentValue)); + } + } + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to the service + this._fuseLoadingBarService.mode$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((value) => { + this.mode = value; + }); + + this._fuseLoadingBarService.progress$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((value) => { + this.progress = value; + }); + + this._fuseLoadingBarService.show$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((value) => { + this.show = value; + }); + + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/@fuse/components/loading-bar/loading-bar.interceptor.ts b/src/@fuse/components/loading-bar/loading-bar.interceptor.ts new file mode 100644 index 00000000..6c9ba4b0 --- /dev/null +++ b/src/@fuse/components/loading-bar/loading-bar.interceptor.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@angular/core'; +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { finalize } from 'rxjs/operators'; +import { FuseLoadingBarService } from '@fuse/components/loading-bar/loading-bar.service'; + +@Injectable() +export class FuseLoadingBarInterceptor implements HttpInterceptor +{ + handleRequestsAutomatically: boolean; + + /** + * Constructor + */ + constructor( + private _fuseLoadingBarService: FuseLoadingBarService + ) + { + // Subscribe to the auto + this._fuseLoadingBarService.auto$ + .subscribe((value) => { + this.handleRequestsAutomatically = value; + }); + } + + /** + * Intercept + * + * @param req + * @param next + */ + intercept(req: HttpRequest, next: HttpHandler): Observable> + { + // If the Auto mode is turned off, do nothing + if ( !this.handleRequestsAutomatically ) + { + return next.handle(req); + } + + // Set the loading status to true + this._fuseLoadingBarService._setLoadingStatus(true, req.url); + + return next.handle(req).pipe( + finalize(() => { + // Set the status to false if there are any errors or the request is completed + this._fuseLoadingBarService._setLoadingStatus(false, req.url); + })); + } +} diff --git a/src/@fuse/components/loading-bar/loading-bar.module.ts b/src/@fuse/components/loading-bar/loading-bar.module.ts new file mode 100644 index 00000000..4baab4c3 --- /dev/null +++ b/src/@fuse/components/loading-bar/loading-bar.module.ts @@ -0,0 +1,29 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { FuseLoadingBarComponent } from '@fuse/components/loading-bar/loading-bar.component'; +import { FuseLoadingBarInterceptor } from '@fuse/components/loading-bar/loading-bar.interceptor'; + +@NgModule({ + declarations: [ + FuseLoadingBarComponent + ], + imports : [ + CommonModule, + MatProgressBarModule + ], + exports : [ + FuseLoadingBarComponent + ], + providers : [ + { + provide : HTTP_INTERCEPTORS, + useClass: FuseLoadingBarInterceptor, + multi : true + } + ] +}) +export class FuseLoadingBarModule +{ +} diff --git a/src/@fuse/components/loading-bar/loading-bar.service.ts b/src/@fuse/components/loading-bar/loading-bar.service.ts new file mode 100644 index 00000000..88ec2a9b --- /dev/null +++ b/src/@fuse/components/loading-bar/loading-bar.service.ts @@ -0,0 +1,146 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { BehaviorSubject, Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class FuseLoadingBarService +{ + private _auto$: BehaviorSubject = new BehaviorSubject(true); + private _mode$: BehaviorSubject<'determinate' | 'indeterminate'> = new BehaviorSubject<'determinate' | 'indeterminate'>('indeterminate'); + private _progress$: BehaviorSubject = new BehaviorSubject(0); + private _show$: BehaviorSubject = new BehaviorSubject(false); + private _urlMap: Map = new Map(); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for auto mode + */ + get auto$(): Observable + { + return this._auto$.asObservable(); + } + + /** + * Getter for mode + */ + get mode$(): Observable<'determinate' | 'indeterminate'> + { + return this._mode$.asObservable(); + } + + /** + * Getter for progress + */ + get progress$(): Observable + { + return this._progress$.asObservable(); + } + + /** + * Getter for show + */ + get show$(): Observable + { + return this._show$.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Show the loading bar + */ + show(): void + { + this._show$.next(true); + } + + /** + * Hide the loading bar + */ + hide(): void + { + this._show$.next(false); + } + + /** + * Set the auto mode + * + * @param value + */ + setAutoMode(value: boolean): void + { + this._auto$.next(value); + } + + /** + * Set the mode + * + * @param value + */ + setMode(value: 'determinate' | 'indeterminate'): void + { + this._mode$.next(value); + } + + /** + * Set the progress of the bar manually + * + * @param value + */ + setProgress(value: number): void + { + if ( value < 0 || value > 100 ) + { + console.error('Progress value must be between 0 and 100!'); + return; + } + + this._progress$.next(value); + } + + /** + * Sets the loading status on the given url + * + * @param status + * @param url + */ + _setLoadingStatus(status: boolean, url: string): void + { + // Return if the url was not provided + if ( !url ) + { + console.error('The request URL must be provided!'); + return; + } + + if ( status === true ) + { + this._urlMap.set(url, status); + this._show$.next(true); + } + else if ( status === false && this._urlMap.has(url) ) + { + this._urlMap.delete(url); + } + + // Only set the status to 'false' if all outgoing requests are completed + if ( this._urlMap.size === 0 ) + { + this._show$.next(false); + } + } +} diff --git a/src/@fuse/components/loading-bar/public-api.ts b/src/@fuse/components/loading-bar/public-api.ts new file mode 100644 index 00000000..d13b3a63 --- /dev/null +++ b/src/@fuse/components/loading-bar/public-api.ts @@ -0,0 +1,3 @@ +export * from '@fuse/components/loading-bar/loading-bar.component'; +export * from '@fuse/components/loading-bar/loading-bar.service'; +export * from '@fuse/components/loading-bar/loading-bar.module'; diff --git a/src/@fuse/styles/overrides/angular-material.scss b/src/@fuse/styles/overrides/angular-material.scss index 3d671f2c..e2eaffe8 100644 --- a/src/@fuse/styles/overrides/angular-material.scss +++ b/src/@fuse/styles/overrides/angular-material.scss @@ -434,7 +434,7 @@ /* Border color */ .mat-form-field-flex { - @apply border-warn #{'!important'}; + @apply border-warn dark:border-warn #{'!important'}; } } } @@ -446,7 +446,7 @@ /* Background color */ .mat-form-field-flex { - @apply bg-card #{'!important'}; + @apply bg-card dark:bg-card #{'!important'}; } } } @@ -458,7 +458,7 @@ /* Border color */ .mat-form-field-flex { - @apply border-primary #{'!important'}; + @apply border-primary dark:border-primary #{'!important'}; } } } diff --git a/src/app/layout/layout.module.ts b/src/app/layout/layout.module.ts index 426c45ad..88211cab 100644 --- a/src/app/layout/layout.module.ts +++ b/src/app/layout/layout.module.ts @@ -1,7 +1,4 @@ import { NgModule } from '@angular/core'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { FuseDrawerModule } from '@fuse/components/drawer'; import { LayoutComponent } from 'app/layout/layout.component'; import { EmptyLayoutModule } from 'app/layout/layouts/empty/empty.module'; import { CenteredLayoutModule } from 'app/layout/layouts/horizontal/centered/centered.module'; @@ -40,13 +37,10 @@ const layoutModules = [ declarations: [ LayoutComponent ], - imports: [ - MatIconModule, - MatTooltipModule, - FuseDrawerModule, + imports : [ SharedModule, SettingsModule, - ...layoutModules, + ...layoutModules ], exports : [ LayoutComponent, diff --git a/src/app/layout/layouts/empty/empty.component.html b/src/app/layout/layouts/empty/empty.component.html index 3dbd8494..214217fc 100644 --- a/src/app/layout/layouts/empty/empty.component.html +++ b/src/app/layout/layouts/empty/empty.component.html @@ -1,3 +1,6 @@ + + +
diff --git a/src/app/layout/layouts/empty/empty.module.ts b/src/app/layout/layouts/empty/empty.module.ts index 339f5cc6..12153080 100644 --- a/src/app/layout/layouts/empty/empty.module.ts +++ b/src/app/layout/layouts/empty/empty.module.ts @@ -1,5 +1,6 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; +import { FuseLoadingBarModule } from '@fuse/components/loading-bar'; import { SharedModule } from 'app/shared/shared.module'; import { EmptyLayoutComponent } from 'app/layout/layouts/empty/empty.component'; @@ -9,6 +10,7 @@ import { EmptyLayoutComponent } from 'app/layout/layouts/empty/empty.component'; ], imports : [ RouterModule, + FuseLoadingBarModule, SharedModule ], exports : [ diff --git a/src/app/layout/layouts/horizontal/centered/centered.component.html b/src/app/layout/layouts/horizontal/centered/centered.component.html index 8b2ca444..c6c8ca70 100644 --- a/src/app/layout/layouts/horizontal/centered/centered.component.html +++ b/src/app/layout/layouts/horizontal/centered/centered.component.html @@ -1,3 +1,6 @@ + + +
diff --git a/src/app/layout/layouts/horizontal/centered/centered.module.ts b/src/app/layout/layouts/horizontal/centered/centered.module.ts index b1d952f4..cc4bc461 100644 --- a/src/app/layout/layouts/horizontal/centered/centered.module.ts +++ b/src/app/layout/layouts/horizontal/centered/centered.module.ts @@ -6,6 +6,7 @@ import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; import { FuseFullscreenModule } from '@fuse/components/fullscreen'; +import { FuseLoadingBarModule } from '@fuse/components/loading-bar'; import { FuseNavigationModule } from '@fuse/components/navigation'; import { LanguagesModule } from 'app/layout/common/languages/languages.module'; import { MessagesModule } from 'app/layout/common/messages/messages.module'; @@ -28,6 +29,7 @@ import { CenteredLayoutComponent } from 'app/layout/layouts/horizontal/centered/ MatIconModule, MatMenuModule, FuseFullscreenModule, + FuseLoadingBarModule, FuseNavigationModule, LanguagesModule, MessagesModule, diff --git a/src/app/layout/layouts/horizontal/enterprise/enterprise.component.html b/src/app/layout/layouts/horizontal/enterprise/enterprise.component.html index 4f376812..45b3fb3f 100644 --- a/src/app/layout/layouts/horizontal/enterprise/enterprise.component.html +++ b/src/app/layout/layouts/horizontal/enterprise/enterprise.component.html @@ -1,3 +1,6 @@ + + + + + + + + + + + + + + + + + + + Already have an account?
Sign in + [routerLink]="['/sign-in']">Sign in