From 291fcbcd92cde119fbefc0e9252affab796fdc31 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Fri, 13 Sep 2024 10:49:09 +0300 Subject: [PATCH 01/21] add: loading state management for extensible table --- .../extensible-table.component.html | 1 + .../extensible-table.component.ts | 45 +++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html index 471aad0f15..576913b713 100644 --- a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html +++ b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html @@ -1,5 +1,6 @@ implements OnChanges { +export class ExtensibleTableComponent implements OnChanges, OnDestroy { protected _actionsText!: string; @Input() set actionsText(value: string) { @@ -110,6 +113,11 @@ export class ExtensibleTableComponent implements OnChanges { #injector = inject(Injector); getInjected = this.#injector.get.bind(this.#injector); permissionService = this.#injector.get(PermissionService); + subscriptionService = this.#injector.get(SubscriptionService); + listService = this.#injector.get(ListService); + routerWaitService = this.#injector.get(RouterWaitService); + cdRef = this.#injector.get(ChangeDetectorRef); + isLoading = true; constructor() { const extensions = this.#injector.get(ExtensionsService); @@ -123,6 +131,8 @@ export class ExtensibleTableComponent implements OnChanges { this.actionList.toArray().map(action => ({ requiredPolicy: action.permission })), ).length > 0; this.setColumnWidths(DEFAULT_ACTIONS_COLUMN_WIDTH); + + this.subscribeLoading(); } private setColumnWidths(actionsColumn: number | undefined) { @@ -227,4 +237,33 @@ export class ExtensibleTableComponent implements OnChanges { return visibleActions.length > 0; } + + subscribeLoading() { + this.subscriptionService.addOne( + combineLatest([this.listService.isLoading$, this.routerWaitService.getLoading$()]), + ([listLoading, routerLoading]) => { + if (listLoading || routerLoading) { + this.startLoading(); + } else { + this.stopLoading(); + } + }, + ); + } + + startLoading() { + if (this.isLoading) { + return; + } + this.isLoading = true; + this.cdRef.detectChanges(); + } + + stopLoading() { + this.isLoading = false; + } + + ngOnDestroy() { + this.subscriptionService.closeAll(); + } } From a584787522361ab47dda9d681d65fb882da4d220 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Fri, 13 Sep 2024 10:49:36 +0300 Subject: [PATCH 02/21] add: spinner component for theme-shared --- .../theme-shared/src/lib/components/index.ts | 3 ++- .../lib/components/spinner/spinner.component.ts | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts index 3adc055b8c..8eded1d615 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts @@ -14,4 +14,5 @@ export * from './password/password.component'; export * from './card/index'; export * from './checkbox/checkbox.component'; export * from './form-input/form-input.component'; -export * from './internet-connection-status/internet-connection-status.component' +export * from './internet-connection-status/internet-connection-status.component'; +export * from './spinner/spinner.component'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts new file mode 100644 index 0000000000..1f4df7f251 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +@Component({ + exportAs: 'spinner', + selector: 'abp-spinner', + standalone: true, + imports: [], + template: ` +
+
+ Loading... +
+
+ `, +}) +export class SpinnerComponent {} From 49ee0615119fd5bdbb75f8a66fc9504cf2a17995 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Fri, 13 Sep 2024 10:50:59 +0300 Subject: [PATCH 03/21] update: datatable directive to handle loading indicator --- .../ngx-datatable-default.directive.ts | 95 +++++++++++++++++-- 1 file changed, 87 insertions(+), 8 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts index eb781666c1..8f0f49d79e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts @@ -1,34 +1,63 @@ import { DOCUMENT } from '@angular/common'; -import { AfterViewInit, Directive, HostBinding, Inject, Input, OnDestroy } from '@angular/core'; +import { + AfterViewInit, + Directive, + effect, + ElementRef, + HostBinding, + inject, + Inject, + input, + Input, + OnDestroy, + OnInit, + Renderer2, + ViewContainerRef, +} from '@angular/core'; import { ColumnMode, DatatableComponent, ScrollerComponent } from '@swimlane/ngx-datatable'; import { fromEvent, Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; +import { SpinnerComponent } from '../components'; @Directive({ // eslint-disable-next-line @angular-eslint/directive-selector selector: 'ngx-datatable[default]', - standalone:true, + standalone: true, exportAs: 'ngxDatatableDefault', }) -export class NgxDatatableDefaultDirective implements AfterViewInit, OnDestroy { - private subscription = new Subscription(); +export class NgxDatatableDefaultDirective implements OnInit, AfterViewInit, OnDestroy { + @Input() class = 'material bordered'; + loadingIndicator = input(true); - private resizeDiff = 0; + private _loading = true; + private mutationObserver: MutationObserver | null = null; - @Input() class = 'material bordered'; + private subscription = new Subscription(); + private resizeDiff = 0; + private elRef = inject(ElementRef); + private renderer = inject(Renderer2); + private viewContainerRef = inject(ViewContainerRef); @HostBinding('class') get classes(): string { return `ngx-datatable ${this.class}`; } - constructor(private table: DatatableComponent, @Inject(DOCUMENT) private document: MockDocument) { + constructor( + private table: DatatableComponent, + @Inject(DOCUMENT) private document: MockDocument, + ) { this.table.columnMode = ColumnMode.force; this.table.footerHeight = 50; this.table.headerHeight = 50; this.table.rowHeight = 'auto'; this.table.scrollbarH = true; this.table.virtualization = false; + + effect(() => { + this._loading = this.loadingIndicator(); + this.updateLoadingIndicator(); + }); } private fixHorizontalGap(scroller: ScrollerComponent) { @@ -60,17 +89,67 @@ export class NgxDatatableDefaultDirective implements AfterViewInit, OnDestroy { this.subscription.add(subscription); } + private observeMutations() { + this.mutationObserver = new MutationObserver(() => { + if (this._loading) { + this.updateLoadingIndicator(); + } + }); + + this.mutationObserver.observe(this.elRef.nativeElement, { + childList: true, + subtree: true, + }); + } + + private updateLoadingIndicator() { + const progressElement = this.elRef.nativeElement.querySelector('datatable-progress'); + + if (this._loading) { + if (progressElement) { + this.renderer.removeChild(progressElement.parentNode, progressElement); + this.addSpinner(progressElement); + } + } else { + this.removeSpinner(); + } + } + + private addSpinner(placeholder: Comment) { + this.viewContainerRef.clear(); + + const spinnerRef = this.viewContainerRef.createComponent(SpinnerComponent); + + this.renderer.insertBefore( + placeholder.parentNode, + spinnerRef.location.nativeElement, + placeholder, + ); + this.renderer.removeChild(placeholder.parentNode, placeholder); + } + + private removeSpinner() { + this.viewContainerRef.clear(); + } + + ngOnInit() { + this.observeMutations(); + } + ngAfterViewInit() { this.fixStyleOnWindowResize(); } ngOnDestroy() { this.subscription.unsubscribe(); + if (this.mutationObserver) { + this.mutationObserver.disconnect(); + } } } // fix: https://github.com/angular/angular/issues/20351 -interface MockDocument { +interface MockDocument extends ParentNode { body: MockBody; documentElement: MockDocumentElement; } From 27625c7e45fdb2ddd4f663a0693659828fef37d9 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Fri, 13 Sep 2024 11:00:44 +0300 Subject: [PATCH 04/21] remove: unused extension for `MockDocument` interface --- .../src/lib/directives/ngx-datatable-default.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts index 8f0f49d79e..58f315458c 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts @@ -149,7 +149,7 @@ export class NgxDatatableDefaultDirective implements OnInit, AfterViewInit, OnDe } // fix: https://github.com/angular/angular/issues/20351 -interface MockDocument extends ParentNode { +interface MockDocument { body: MockBody; documentElement: MockDocumentElement; } From a4fc18157573700beea44c30927d2c1b61b89caf Mon Sep 17 00:00:00 2001 From: masum-ulu Date: Fri, 13 Sep 2024 15:35:10 +0300 Subject: [PATCH 05/21] add: solution template for loading-indicator --- .../extensible-table.component.ts | 16 +++--- .../ngx-datatable-list.directive.ts | 51 +++++++++++++------ 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts index 8af2a46684..135456db2e 100644 --- a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts +++ b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts @@ -74,7 +74,14 @@ const DEFAULT_ACTIONS_COLUMN_WIDTH = 150; templateUrl: './extensible-table.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ExtensibleTableComponent implements OnChanges, OnDestroy { +export class ExtensibleTableComponent implements OnChanges { + readonly #injector = inject(Injector); + readonly getInjected = this.#injector.get.bind(this.#injector); + protected readonly locale = inject(LOCALE_ID); + protected readonly config = inject(ConfigStateService); + protected readonly entityPropTypeClasses = inject(ENTITY_PROP_TYPE_CLASSES); + protected readonly permissionService = inject(PermissionService); + protected _actionsText!: string; @Input() set actionsText(value: string) { @@ -106,13 +113,6 @@ export class ExtensibleTableComponent implements OnChanges, OnDestroy { readonly actionList: EntityActionList; readonly trackByFn: TrackByFunction> = (_, item) => item.name; - - locale = inject(LOCALE_ID); - private config = inject(ConfigStateService); - entityPropTypeClasses = inject(ENTITY_PROP_TYPE_CLASSES); - #injector = inject(Injector); - getInjected = this.#injector.get.bind(this.#injector); - permissionService = this.#injector.get(PermissionService); subscriptionService = this.#injector.get(SubscriptionService); listService = this.#injector.get(ListService); routerWaitService = this.#injector.get(RouterWaitService); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts index b946ba2639..811693f31f 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts @@ -7,7 +7,7 @@ import { DoCheck, SimpleChanges, inject, - DestroyRef + DestroyRef, } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DatatableComponent } from '@swimlane/ngx-datatable'; @@ -24,14 +24,14 @@ import { exportAs: 'ngxDatatableList', }) export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { - @Input() list!: ListService; - protected readonly table = inject(DatatableComponent); protected readonly cdRef = inject(ChangeDetectorRef); protected readonly destroyRef = inject(DestroyRef); protected readonly localizationService = inject(LocalizationService); protected readonly ngxDatatableMessages = inject(NGX_DATATABLE_MESSAGES, { optional: true }); + @Input() list!: ListService; + constructor() { this.setInitialValues(); } @@ -43,6 +43,25 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { ngOnInit() { this.subscribeToPage(); this.subscribeToSort(); + const indicator = document.createElement(`div`); + indicator.innerHTML = ` +
+
+ Loading... +
+
+ `; + + let ref: HTMLDivElement; + this.list.isLoading$.subscribe(isLoading => { + if (isLoading) { + ref = this.table.element.querySelector('.datatable-body').appendChild(indicator); + } else { + const { emptyMessage } = this.ngxDatatableMessages || defaultNgxDatatableMessages; + this.table.messages.emptyMessage = this.localizationService.instant(emptyMessage); + ref?.remove(); + } + }); } ngOnChanges({ list }: SimpleChanges) { @@ -63,24 +82,26 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { this.ngxDatatableMessages || defaultNgxDatatableMessages; this.table.messages = { - emptyMessage: this.localizationService.instant(emptyMessage), + emptyMessage: '', totalMessage: this.localizationService.instant(totalMessage), selectedMessage: this.localizationService.instant(selectedMessage), }; } protected subscribeToSort() { - this.table.sort.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(({ sorts: [{ prop, dir }] }) => { - if (prop === this.list.sortKey && this.list.sortOrder === 'desc') { - this.list.sortKey = ''; - this.list.sortOrder = ''; - this.table.sorts = []; - this.cdRef.detectChanges(); - } else { - this.list.sortKey = prop; - this.list.sortOrder = dir; - } - }); + this.table.sort + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(({ sorts: [{ prop, dir }] }) => { + if (prop === this.list.sortKey && this.list.sortOrder === 'desc') { + this.list.sortKey = ''; + this.list.sortOrder = ''; + this.table.sorts = []; + this.cdRef.detectChanges(); + } else { + this.list.sortKey = prop; + this.list.sortOrder = dir; + } + }); } protected subscribeToPage() { From 7822e1fb993ad9048fa1c03d5890f0e17ecd01ae Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Mon, 16 Sep 2024 14:55:32 +0300 Subject: [PATCH 06/21] update: remove loading indicator config from extensible table --- .../extensible-table.component.html | 1 - .../extensible-table.component.ts | 34 +------------------ 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html index 576913b713..471aad0f15 100644 --- a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html +++ b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html @@ -1,6 +1,5 @@ implements OnChanges { this.actionList.toArray().map(action => ({ requiredPolicy: action.permission })), ).length > 0; this.setColumnWidths(DEFAULT_ACTIONS_COLUMN_WIDTH); - - this.subscribeLoading(); } private setColumnWidths(actionsColumn: number | undefined) { @@ -237,33 +234,4 @@ export class ExtensibleTableComponent implements OnChanges { return visibleActions.length > 0; } - - subscribeLoading() { - this.subscriptionService.addOne( - combineLatest([this.listService.isLoading$, this.routerWaitService.getLoading$()]), - ([listLoading, routerLoading]) => { - if (listLoading || routerLoading) { - this.startLoading(); - } else { - this.stopLoading(); - } - }, - ); - } - - startLoading() { - if (this.isLoading) { - return; - } - this.isLoading = true; - this.cdRef.detectChanges(); - } - - stopLoading() { - this.isLoading = false; - } - - ngOnDestroy() { - this.subscriptionService.closeAll(); - } } From 021f95d83919c6da31d3e1f86fb03e59fb4aa0d4 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Mon, 16 Sep 2024 14:57:42 +0300 Subject: [PATCH 07/21] update: migrating the loading indicator logic to list directive --- .../ngx-datatable-default.directive.ts | 81 +------------- .../ngx-datatable-list.directive.ts | 101 ++++++++++++++---- 2 files changed, 81 insertions(+), 101 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts index 58f315458c..e6ce7d3435 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts @@ -1,23 +1,8 @@ import { DOCUMENT } from '@angular/common'; -import { - AfterViewInit, - Directive, - effect, - ElementRef, - HostBinding, - inject, - Inject, - input, - Input, - OnDestroy, - OnInit, - Renderer2, - ViewContainerRef, -} from '@angular/core'; +import { AfterViewInit, Directive, HostBinding, Inject, Input, OnDestroy } from '@angular/core'; import { ColumnMode, DatatableComponent, ScrollerComponent } from '@swimlane/ngx-datatable'; import { fromEvent, Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; -import { SpinnerComponent } from '../components'; @Directive({ // eslint-disable-next-line @angular-eslint/directive-selector @@ -25,18 +10,11 @@ import { SpinnerComponent } from '../components'; standalone: true, exportAs: 'ngxDatatableDefault', }) -export class NgxDatatableDefaultDirective implements OnInit, AfterViewInit, OnDestroy { +export class NgxDatatableDefaultDirective implements AfterViewInit, OnDestroy { @Input() class = 'material bordered'; - loadingIndicator = input(true); - - private _loading = true; - private mutationObserver: MutationObserver | null = null; private subscription = new Subscription(); private resizeDiff = 0; - private elRef = inject(ElementRef); - private renderer = inject(Renderer2); - private viewContainerRef = inject(ViewContainerRef); @HostBinding('class') get classes(): string { @@ -53,11 +31,6 @@ export class NgxDatatableDefaultDirective implements OnInit, AfterViewInit, OnDe this.table.rowHeight = 'auto'; this.table.scrollbarH = true; this.table.virtualization = false; - - effect(() => { - this._loading = this.loadingIndicator(); - this.updateLoadingIndicator(); - }); } private fixHorizontalGap(scroller: ScrollerComponent) { @@ -89,62 +62,12 @@ export class NgxDatatableDefaultDirective implements OnInit, AfterViewInit, OnDe this.subscription.add(subscription); } - private observeMutations() { - this.mutationObserver = new MutationObserver(() => { - if (this._loading) { - this.updateLoadingIndicator(); - } - }); - - this.mutationObserver.observe(this.elRef.nativeElement, { - childList: true, - subtree: true, - }); - } - - private updateLoadingIndicator() { - const progressElement = this.elRef.nativeElement.querySelector('datatable-progress'); - - if (this._loading) { - if (progressElement) { - this.renderer.removeChild(progressElement.parentNode, progressElement); - this.addSpinner(progressElement); - } - } else { - this.removeSpinner(); - } - } - - private addSpinner(placeholder: Comment) { - this.viewContainerRef.clear(); - - const spinnerRef = this.viewContainerRef.createComponent(SpinnerComponent); - - this.renderer.insertBefore( - placeholder.parentNode, - spinnerRef.location.nativeElement, - placeholder, - ); - this.renderer.removeChild(placeholder.parentNode, placeholder); - } - - private removeSpinner() { - this.viewContainerRef.clear(); - } - - ngOnInit() { - this.observeMutations(); - } - ngAfterViewInit() { this.fixStyleOnWindowResize(); } ngOnDestroy() { this.subscription.unsubscribe(); - if (this.mutationObserver) { - this.mutationObserver.disconnect(); - } } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts index 811693f31f..e8e49bad34 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts @@ -8,14 +8,19 @@ import { SimpleChanges, inject, DestroyRef, + ViewContainerRef, + Renderer2, + AfterViewInit, } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DatatableComponent } from '@swimlane/ngx-datatable'; -import { ListService, LocalizationService } from '@abp/ng.core'; +import { combineLatest } from 'rxjs'; +import { ListService, LocalizationService, RouterWaitService } from '@abp/ng.core'; import { defaultNgxDatatableMessages, NGX_DATATABLE_MESSAGES, } from '../tokens/ngx-datatable-messages.token'; +import { SpinnerComponent } from '../components'; @Directive({ // eslint-disable-next-line @angular-eslint/directive-selector @@ -23,12 +28,17 @@ import { standalone: true, exportAs: 'ngxDatatableList', }) -export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { +export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, AfterViewInit { protected readonly table = inject(DatatableComponent); protected readonly cdRef = inject(ChangeDetectorRef); protected readonly destroyRef = inject(DestroyRef); protected readonly localizationService = inject(LocalizationService); protected readonly ngxDatatableMessages = inject(NGX_DATATABLE_MESSAGES, { optional: true }); + protected readonly routerWaitService = inject(RouterWaitService); + protected readonly viewContainerRef = inject(ViewContainerRef); + protected readonly renderer = inject(Renderer2); + + protected _loading = true; @Input() list!: ListService; @@ -40,28 +50,15 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { this.refreshPageIfDataExist(); } + ngAfterViewInit() { + this.table.loadingIndicator = this._loading; + this.handleLoadingStart(); + } + ngOnInit() { this.subscribeToPage(); this.subscribeToSort(); - const indicator = document.createElement(`div`); - indicator.innerHTML = ` -
-
- Loading... -
-
- `; - - let ref: HTMLDivElement; - this.list.isLoading$.subscribe(isLoading => { - if (isLoading) { - ref = this.table.element.querySelector('.datatable-body').appendChild(indicator); - } else { - const { emptyMessage } = this.ngxDatatableMessages || defaultNgxDatatableMessages; - this.table.messages.emptyMessage = this.localizationService.instant(emptyMessage); - ref?.remove(); - } - }); + this.subscribeToLoadingState(); } ngOnChanges({ list }: SimpleChanges) { @@ -74,6 +71,66 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { this.table.offset = page; } + protected subscribeToLoadingState() { + combineLatest([this.list.isLoading$, this.routerWaitService.getLoading$()]).subscribe( + ([listLoading, routerLoading]) => { + const isLoading = listLoading || routerLoading; + if (isLoading) { + this.handleLoadingStart(); + } else { + this.handleLoadingStop(); + } + }, + ); + } + + protected handleLoadingStop() { + if (this._loading) { + this.setLoadingState(false); + this.removeSpinner(); + } + } + + protected handleLoadingStart() { + if (!this._loading) { + this.setLoadingState(true); + this.updateLoadingIndicator(); + } + } + + protected setLoadingState(loading: boolean) { + this._loading = loading; + this.table.loadingIndicator = loading; + this.cdRef.detectChanges(); + } + + protected updateLoadingIndicator() { + const body = this.table.element.querySelector('datatable-body'); + const progress = this.table.element.querySelector('datatable-progress'); + + if (!body) { + return; + } + + if (progress) { + this.replaceLoadingIndicator(body, progress); + } + } + + protected replaceLoadingIndicator(parent: Element, placeholder: Element) { + this.viewContainerRef.clear(); + + const spinnerRef = this.viewContainerRef.createComponent(SpinnerComponent); + const spinnerElement = spinnerRef.location.nativeElement; + + this.renderer.insertBefore(parent, spinnerElement, placeholder); + this.renderer.removeChild(parent, placeholder); + } + + protected removeSpinner() { + this.viewContainerRef.clear(); + } + protected setInitialValues() { this.table.externalPaging = true; this.table.externalSorting = true; @@ -82,7 +139,7 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { this.ngxDatatableMessages || defaultNgxDatatableMessages; this.table.messages = { - emptyMessage: '', + emptyMessage: this.localizationService.instant(emptyMessage), totalMessage: this.localizationService.instant(totalMessage), selectedMessage: this.localizationService.instant(selectedMessage), }; From 8b98b29f3a1b58cb024977723f89e95e4a977502 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Tue, 17 Sep 2024 08:27:18 +0300 Subject: [PATCH 08/21] remove: redundant variables --- .../extensible-table/extensible-table.component.ts | 5 ----- .../src/lib/components/spinner/spinner.component.ts | 2 -- 2 files changed, 7 deletions(-) diff --git a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts index a563137408..19841dd838 100644 --- a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts +++ b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts @@ -112,11 +112,6 @@ export class ExtensibleTableComponent implements OnChanges { readonly actionList: EntityActionList; readonly trackByFn: TrackByFunction> = (_, item) => item.name; - subscriptionService = this.#injector.get(SubscriptionService); - listService = this.#injector.get(ListService); - routerWaitService = this.#injector.get(RouterWaitService); - cdRef = this.#injector.get(ChangeDetectorRef); - isLoading = true; constructor() { const extensions = this.#injector.get(ExtensionsService); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts index 1f4df7f251..abb692ed60 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts @@ -1,10 +1,8 @@ import { Component } from '@angular/core'; @Component({ - exportAs: 'spinner', selector: 'abp-spinner', standalone: true, - imports: [], template: `
From 0e619bfbcd2a71bdcc27e6eae4a8d5792194b6c5 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Tue, 17 Sep 2024 08:28:40 +0300 Subject: [PATCH 09/21] remove: router wait service check --- .../ngx-datatable-list.directive.ts | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts index e8e49bad34..b8811106dd 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts @@ -14,8 +14,7 @@ import { } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DatatableComponent } from '@swimlane/ngx-datatable'; -import { combineLatest } from 'rxjs'; -import { ListService, LocalizationService, RouterWaitService } from '@abp/ng.core'; +import { ListService, LocalizationService } from '@abp/ng.core'; import { defaultNgxDatatableMessages, NGX_DATATABLE_MESSAGES, @@ -34,7 +33,6 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, Af protected readonly destroyRef = inject(DestroyRef); protected readonly localizationService = inject(LocalizationService); protected readonly ngxDatatableMessages = inject(NGX_DATATABLE_MESSAGES, { optional: true }); - protected readonly routerWaitService = inject(RouterWaitService); protected readonly viewContainerRef = inject(ViewContainerRef); protected readonly renderer = inject(Renderer2); @@ -72,16 +70,13 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, Af } protected subscribeToLoadingState() { - combineLatest([this.list.isLoading$, this.routerWaitService.getLoading$()]).subscribe( - ([listLoading, routerLoading]) => { - const isLoading = listLoading || routerLoading; - if (isLoading) { - this.handleLoadingStart(); - } else { - this.handleLoadingStop(); - } - }, - ); + this.list.isLoading$.subscribe(listLoading => { + if (listLoading) { + this.handleLoadingStart(); + } else { + this.handleLoadingStop(); + } + }); } protected handleLoadingStop() { From c2d99d01e1e374a17cdea38c2809c7372fe37485 Mon Sep 17 00:00:00 2001 From: Masum ULU <49063256+masum-ulu@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:35:55 +0300 Subject: [PATCH 10/21] Update ngx-datatable-default.directive.ts --- .../src/lib/directives/ngx-datatable-default.directive.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts index e6ce7d3435..359ca72b59 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts @@ -10,12 +10,12 @@ import { debounceTime } from 'rxjs/operators'; standalone: true, exportAs: 'ngxDatatableDefault', }) -export class NgxDatatableDefaultDirective implements AfterViewInit, OnDestroy { - @Input() class = 'material bordered'; - +export class NgxDatatableDefaultDirective implements AfterViewInit, OnDestroy { private subscription = new Subscription(); private resizeDiff = 0; + @Input() class = 'material bordered'; + @HostBinding('class') get classes(): string { return `ngx-datatable ${this.class}`; From c58f646a78881877c388f9850a3a93bc1cbe81e3 Mon Sep 17 00:00:00 2001 From: masum-ulu Date: Wed, 18 Sep 2024 15:10:25 +0300 Subject: [PATCH 11/21] add: requestStatus variable for track request process --- .../core/src/lib/services/list.service.ts | 23 ++++++++++---- .../core/src/lib/tests/list.service.spec.ts | 30 +++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts index ef835e9fcd..f0ede2e795 100644 --- a/npm/ng-packs/packages/core/src/lib/services/list.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -20,6 +20,8 @@ import { ABP } from '../models/common'; import { PagedResultDto } from '../models/dtos'; import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token'; +export type RequestStatus = 'idle' | 'loading' | 'success' | 'error'; + @Injectable() export class ListService implements OnDestroy { private _filter = ''; @@ -40,7 +42,6 @@ export class ListService implements return this._maxResultCount; } - private _skipCount = 0; private _page = 0; set page(value: number) { if (value === this._page) return; @@ -91,12 +92,21 @@ export class ListService implements private _isLoading$ = new BehaviorSubject(false); + private _requestStatus = new BehaviorSubject('idle'); + private destroy$ = new Subject(); private delay: MonoTypeOperatorFunction; + /** + * @deprecated Use `requestStatus$` instead. + */ get isLoading$(): Observable { - return this._isLoading$.asObservable(); + return this._isLoading$.asObservable().pipe(takeUntil(this.destroy$)); + } + + get requestStatus$(): Observable { + return this._requestStatus.asObservable().pipe(takeUntil(this.destroy$)); } get = () => { @@ -119,29 +129,32 @@ export class ListService implements ): Observable> { return this.query$.pipe( tap(() => this._isLoading$.next(true)), + tap(() => this._requestStatus.next('loading')), switchMap(query => streamCreatorCallback(query).pipe(catchError(() => of(null)))), filter(Boolean), tap(() => this._isLoading$.next(false)), + tap(() => this._requestStatus.next('success')), shareReplay({ bufferSize: 1, refCount: true }), takeUntil(this.destroy$), + catchError(error => { + this._requestStatus.next('error'); + throw error; + }), ); } ngOnDestroy() { this.destroy$.next(); } - private resetPageWhenUnchanged() { const maxPage = Number(Number(this.totalCount / this._maxResultCount).toFixed()); const skipCount = this._page * this._maxResultCount; if (skipCount !== this._totalCount) { - this._skipCount = skipCount; return; } if (this.page === maxPage && this.page > 0) { - this._skipCount = skipCount - this._maxResultCount; this.page = this.page - 1; } } diff --git a/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts index f26c39d4ad..3c36b19205 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts @@ -149,5 +149,35 @@ describe('ListService', () => { service.hookToQuery(callback).subscribe(); }); + + it('should emit requestStatus as side effect', done => { + const callback: QueryStreamCreatorCallback = query => + of({ items: [query], totalCount: 1 }); + + service.requestStatus$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => { + expect(idle).toBe('idle'); + expect(init).toBe('loading'); + expect(end).toBe('success'); + + done(); + }); + + service.hookToQuery(callback).subscribe(); + }); + + it('should emit error requestStatus as side effect', done => { + const errCallback: QueryStreamCreatorCallback = query => { + throw Error('A server error occurred'); + }; + + service.requestStatus$.pipe(bufferCount(3)).subscribe(([idle, loading, error]) => { + expect(idle).toBe('idle'); + expect(loading).toBe('loading'); + expect(error).toBe('error'); + done(); + }); + + service.hookToQuery(errCallback).subscribe(); + }); }); }); From 89ff5c9780fc849597c593e3d0feb462f256c9c6 Mon Sep 17 00:00:00 2001 From: masum-ulu Date: Wed, 18 Sep 2024 15:10:50 +0300 Subject: [PATCH 12/21] improve logic in ngx-datatable-list.directive --- .../ngx-datatable-list.directive.ts | 62 +++++++------------ 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts index b8811106dd..c31acd9fe8 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts @@ -10,9 +10,9 @@ import { DestroyRef, ViewContainerRef, Renderer2, - AfterViewInit, } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { distinctUntilChanged } from 'rxjs'; import { DatatableComponent } from '@swimlane/ngx-datatable'; import { ListService, LocalizationService } from '@abp/ng.core'; import { @@ -27,7 +27,7 @@ import { SpinnerComponent } from '../components'; standalone: true, exportAs: 'ngxDatatableList', }) -export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, AfterViewInit { +export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { protected readonly table = inject(DatatableComponent); protected readonly cdRef = inject(ChangeDetectorRef); protected readonly destroyRef = inject(DestroyRef); @@ -36,8 +36,6 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, Af protected readonly viewContainerRef = inject(ViewContainerRef); protected readonly renderer = inject(Renderer2); - protected _loading = true; - @Input() list!: ListService; constructor() { @@ -48,11 +46,6 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, Af this.refreshPageIfDataExist(); } - ngAfterViewInit() { - this.table.loadingIndicator = this._loading; - this.handleLoadingStart(); - } - ngOnInit() { this.subscribeToPage(); this.subscribeToSort(); @@ -70,33 +63,29 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, Af } protected subscribeToLoadingState() { - this.list.isLoading$.subscribe(listLoading => { - if (listLoading) { - this.handleLoadingStart(); - } else { - this.handleLoadingStop(); - } - }); - } + const requestStatus$ = this.list.requestStatus$.pipe(distinctUntilChanged()); + const { emptyMessage } = this.ngxDatatableMessages || defaultNgxDatatableMessages; - protected handleLoadingStop() { - if (this._loading) { - this.setLoadingState(false); - this.removeSpinner(); - } - } + requestStatus$.subscribe(status => { + this.table.loadingIndicator = false; + + if (status === 'idle') { + return; + } - protected handleLoadingStart() { - if (!this._loading) { - this.setLoadingState(true); - this.updateLoadingIndicator(); - } - } + if (status === 'loading') { + this.table.messages.emptyMessage = undefined; + this.table.loadingIndicator = true; + this.cdRef.detectChanges(); + this.updateLoadingIndicator(); + return; + } - protected setLoadingState(loading: boolean) { - this._loading = loading; - this.table.loadingIndicator = loading; - this.cdRef.detectChanges(); + if (status === 'success') { + this.table.messages.emptyMessage = this.localizationService.instant(emptyMessage); + this.viewContainerRef.clear(); + } + }); } protected updateLoadingIndicator() { @@ -122,19 +111,14 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, Af this.renderer.removeChild(parent, placeholder); } - protected removeSpinner() { - this.viewContainerRef.clear(); - } - protected setInitialValues() { this.table.externalPaging = true; this.table.externalSorting = true; - const { emptyMessage, selectedMessage, totalMessage } = + const { selectedMessage, totalMessage } = this.ngxDatatableMessages || defaultNgxDatatableMessages; this.table.messages = { - emptyMessage: this.localizationService.instant(emptyMessage), totalMessage: this.localizationService.instant(totalMessage), selectedMessage: this.localizationService.instant(selectedMessage), }; From 136edf5debf361b621e46f0ff234a32070bc4923 Mon Sep 17 00:00:00 2001 From: masum-ulu Date: Wed, 18 Sep 2024 15:11:16 +0300 Subject: [PATCH 13/21] track request status for set data empty and improve spinner component --- .../extensible-table.component.ts | 15 +++++++++++---- .../lib/components/spinner/spinner.component.ts | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts index 19841dd838..9d4a7be83f 100644 --- a/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts +++ b/npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts @@ -1,4 +1,5 @@ import { + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, @@ -15,7 +16,7 @@ import { } from '@angular/core'; import { AsyncPipe, formatDate, NgComponentOutlet, NgTemplateOutlet } from '@angular/common'; -import { Observable, map } from 'rxjs'; +import { Observable, filter, map } from 'rxjs'; import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; import { NgxDatatableModule } from '@swimlane/ngx-datatable'; @@ -30,8 +31,6 @@ import { LocalizationModule, PermissionDirective, PermissionService, - RouterWaitService, - SubscriptionService, } from '@abp/ng.core'; import { AbpVisibleDirective, @@ -73,9 +72,10 @@ const DEFAULT_ACTIONS_COLUMN_WIDTH = 150; templateUrl: './extensible-table.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ExtensibleTableComponent implements OnChanges { +export class ExtensibleTableComponent implements OnChanges, AfterViewInit { readonly #injector = inject(Injector); readonly getInjected = this.#injector.get.bind(this.#injector); + protected readonly cdr = inject(ChangeDetectorRef); protected readonly locale = inject(LOCALE_ID); protected readonly config = inject(ConfigStateService); protected readonly entityPropTypeClasses = inject(ENTITY_PROP_TYPE_CLASSES); @@ -229,4 +229,11 @@ export class ExtensibleTableComponent implements OnChanges { return visibleActions.length > 0; } + + ngAfterViewInit(): void { + this.list?.requestStatus$?.pipe(filter(status => status === 'loading')).subscribe(() => { + this.data = []; + this.cdr.markForCheck(); + }); + } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts index abb692ed60..e1d3493261 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/spinner/spinner.component.ts @@ -4,7 +4,7 @@ import { Component } from '@angular/core'; selector: 'abp-spinner', standalone: true, template: ` -
+
Loading...
From c8caa03519014cb169f7ffcf2230faf17cac545a Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Thu, 3 Oct 2024 11:53:37 +0300 Subject: [PATCH 14/21] update: handle catch error inside `streamCreatorCallback` --- .../core/src/lib/services/list.service.ts | 25 +++++++++++-------- .../core/src/lib/tests/list.service.spec.ts | 6 +++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts index f0ede2e795..48730efef1 100644 --- a/npm/ng-packs/packages/core/src/lib/services/list.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -1,9 +1,9 @@ import { Injectable, Injector, OnDestroy } from '@angular/core'; import { + EMPTY, BehaviorSubject, MonoTypeOperatorFunction, Observable, - of, ReplaySubject, Subject, } from 'rxjs'; @@ -130,16 +130,19 @@ export class ListService implements return this.query$.pipe( tap(() => this._isLoading$.next(true)), tap(() => this._requestStatus.next('loading')), - switchMap(query => streamCreatorCallback(query).pipe(catchError(() => of(null)))), - filter(Boolean), - tap(() => this._isLoading$.next(false)), - tap(() => this._requestStatus.next('success')), - shareReplay({ bufferSize: 1, refCount: true }), - takeUntil(this.destroy$), - catchError(error => { - this._requestStatus.next('error'); - throw error; - }), + switchMap(query => + streamCreatorCallback(query).pipe( + catchError(() => { + this._requestStatus.next('error'); + return EMPTY; + }), + filter(Boolean), + tap(() => this._isLoading$.next(false)), + tap(() => this._requestStatus.next('success')), + shareReplay({ bufferSize: 1, refCount: true }), + takeUntil(this.destroy$), + ), + ), ); } diff --git a/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts index 3c36b19205..d81091b2f7 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts @@ -165,7 +165,7 @@ describe('ListService', () => { service.hookToQuery(callback).subscribe(); }); - it('should emit error requestStatus as side effect', done => { + it('should emit error requestStatus as side effect and stop processing', done => { const errCallback: QueryStreamCreatorCallback = query => { throw Error('A server error occurred'); }; @@ -177,7 +177,9 @@ describe('ListService', () => { done(); }); - service.hookToQuery(errCallback).subscribe(); + service.hookToQuery(errCallback).subscribe({ + error: () => done(), + }); }); }); }); From f8845fc927f91a0be272554b30e0d1b97c056181 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Thu, 3 Oct 2024 15:35:37 +0300 Subject: [PATCH 15/21] update: add error message localization --- framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json | 1 + .../src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json | 1 + .../src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json | 1 + .../src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json | 1 + .../src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json | 1 + framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json | 1 + .../src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json | 1 + .../src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json | 1 + 26 files changed, 26 insertions(+) diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json index 6a862fa016..c1097000c1 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "عرض 0 الي 0 من 0 إدخالات", "PagerInfoFiltered": "(تمت تصفيته من _MAX_ مجموع الإدخالات)", "NoDataAvailableInDatatable": "لا توجد بيانات متاحة في الجدول", + "ErrorLoadingDatatable": "حدث خطأ أثناء الطلب. تحقق من الرسالة للتفاصيل.", "Total": "مجموع", "Selected": "مختارة", "PagerShowMenuEntries": "عرض _MENU_ إدخالات", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json index 46de32b3e6..710a57a2a9 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json @@ -39,6 +39,7 @@ "PagerInfoFiltered": "(filtrováno ze všech _MAX_ záznamů)", "NoDataAvailableInDatatable": "Nejsou žádná data", "Total": "celkem", + "ErrorLoadingDatatable": "Došlo k chybě během požadavku. Zkontrolujte zprávu pro podrobnosti.", "Selected": "vybráno", "PagerShowMenuEntries": "Zobrazit _MENU_ záznamů", "DatatableActionDropdownDefaultText": "Akce", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json index 3d5a4f3bf3..a955a9066d 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "0 bis 0 von 0 Einträgen anzeigen", "PagerInfoFiltered": "(gefiltert aus _MAX_ Einträgen)", "NoDataAvailableInDatatable": "Keine Daten verfügbar", + "ErrorLoadingDatatable": "Ein Fehler ist während der Anfrage aufgetreten. Überprüfen Sie die Nachricht auf Details.", "Total": "gesamt", "Selected": "ausgewählt", "PagerShowMenuEntries": "_MENU_ Einträge anzeigen", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json index ede2ca211a..2abb92eab7 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Εμφάνιση 0 έως 0 από 0 εγγραφές", "PagerInfoFiltered": "(φιλτραρισμένο από _MAX_ συνολικές εγγραφές)", "NoDataAvailableInDatatable": "Δεν υπάρχουν διαθέσιμα δεδομένα", + "ErrorLoadingDatatable": "Παρουσιάστηκε σφάλμα κατά τη διάρκεια του αιτήματος. Ελέγξτε το μήνυμα για λεπτομέρειες.", "Total": "Σύνολο", "Selected": "Έχει γίνει επιλογή", "PagerShowMenuEntries": "Εμφάνιση στοιχείων _MENU_", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json index 44913c3b1e..7bbcc9d82f 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Showing 0 to 0 of 0 entries", "PagerInfoFiltered": "(filtered from _MAX_ total entries)", "NoDataAvailableInDatatable": "No data available", + "ErrorLoadingDatatable": "An error occurred during the request. Check the message for details.", "Total": "total", "Selected": "selected", "PagerShowMenuEntries": "Show _MENU_ entries", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json index 5c2810f555..8ea53bba77 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Showing 0 to 0 of 0 entries", "PagerInfoFiltered": "(filtered from _MAX_ total entries)", "NoDataAvailableInDatatable": "No data available", + "ErrorLoadingDatatable": "An error occurred during the request. Check the message for details.", "Total": "total", "Selected": "selected", "PagerShowMenuEntries": "Show _MENU_ entries", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json index 9d8578bc94..df75ed8799 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Mostrando de 0 a 0 de 0 entradas", "PagerInfoFiltered": "(filtrado desde _MAX_ entradas totales)", "NoDataAvailableInDatatable": "No hay datos disponibles", + "ErrorLoadingDatatable": "Se produjo un error durante la solicitud. Consulte el mensaje para más detalles.", "Total": "Total", "Selected": "Seleccionado", "PagerShowMenuEntries": "Mostrar _MENU_ registros", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json index 017f97ccb2..c5cb5960bd 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "نمایش از 0 تا 0 از مجموع 0 مورد", "PagerInfoFiltered": "(فیلتر شده از مجموع _MAX_ مورد)", "NoDataAvailableInDatatable": "داده ای وجود ندارد", + "ErrorLoadingDatatable": "در طول درخواست خطایی رخ داد. برای جزئیات پیام را بررسی کنید.", "Total": "مجموع", "Selected": "انتخاب شده", "PagerShowMenuEntries": "نمایش _MENU_ مورد", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json index 481ac49158..d2b5018e73 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Näytetään 0 - 0/0 tietueesta", "PagerInfoFiltered": "(suodatettu _MAX_ tietueen kokonaismäärästä)", "NoDataAvailableInDatatable": "Tietoja ei löydy", + "ErrorLoadingDatatable": "Pyynnön aikana tapahtui virhe. Tarkista viesti yksityiskohtia varten.", "Total": "kaikki yhteensä", "Selected": "valittu", "PagerShowMenuEntries": "Näytä _MENU_ tietueet", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json index ecef824b2a..66e37491fb 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Affichage de 0 à 0 sur 0 entrées", "PagerInfoFiltered": "(filtré à partir des entrées _MAX_ totale)", "NoDataAvailableInDatatable": "Aucune donnée disponible", + "ErrorLoadingDatatable": "Une erreur est survenue lors de la requête. Vérifiez le message pour plus de détails.", "Total": "Total", "Selected": "Sélectionné", "PagerShowMenuEntries": "Afficher les entrées _MENU_", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json index a21b9e3443..7da0065d95 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "0 से 0 प्रविष्टियों को दिखा रहा है", "PagerInfoFiltered": "(_MAX_ कुल प्रविष्टियों से फ़िल्टर किया गया)", "NoDataAvailableInDatatable": "कोई डेटा उपलब्ध नहीं है", + "ErrorLoadingDatatable": "अनुरोध के दौरान एक त्रुटि हुई। विवरण के लिए संदेश देखें।", "Total": "संपूर्ण", "Selected": "चयनित", "PagerShowMenuEntries": "_MENU_ प्रविष्टियाँ दिखाएँ", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json index e3c7ebf295..b1073d62e7 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Prikazano 0 do 0 od 0 zapisa", "PagerInfoFiltered": "(filtrirano od _MAX_ ukupnih zapisa)", "NoDataAvailableInDatatable": "Nema dostupnih podataka", + "ErrorLoadingDatatable": "Došlo je do pogreške tijekom zahtjeva. Provjerite poruku za detalje.", "Total": "ukupno", "Selected": "odabrano", "PagerShowMenuEntries": "Pokaži _MENU_ zapise", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json index bf54087eba..3df6177a9f 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Látható 0-tól 0-ig 0 elemből", "PagerInfoFiltered": "(szűrve _MAX_ elemből)", "NoDataAvailableInDatatable": "Nem elérhető adat", + "ErrorLoadingDatatable": "Hiba történt a kérés során. Ellenőrizze az üzenetet a részletekért.", "Total": "összesen", "Selected": "kiválasztott", "PagerShowMenuEntries": "Megjelenítve _MENU_ elem", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json index 93d0d8a161..d2eba16bd8 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Sýnir 0 til 0 af 0 færslum", "PagerInfoFiltered": "(síað úr _MAX_ heildar færslum)", "NoDataAvailableInDatatable": "Engar upplýsingar fáanlegar", + "ErrorLoadingDatatable": "Villa kom upp við beiðni. Athugaðu skilaboðin til að fá frekari upplýsingar.", "Total": "Samtals", "Selected": "valið", "PagerShowMenuEntries": "Sýna færslur _MENU_", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json index 852ce0d3e2..ef255274df 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Risultati da 0 a 0 di 0 elementi", "PagerInfoFiltered": "(filtrati da _MAX_ elementi totali)", "NoDataAvailableInDatatable": "Nessun dato disponibile", + "ErrorLoadingDatatable": "Si è verificato un errore durante la richiesta. Controlla il messaggio per i dettagli.", "Total": "Totale", "Selected": "Selezionato", "PagerShowMenuEntries": "Righe per pagina _MENU_", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json index 2ac54e4341..85b8b4f88b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Toont 0 tot 0 van 0 vermeldingen", "PagerInfoFiltered": "(gefilterd uit in totaal _MAX_ vermeldingen)", "NoDataAvailableInDatatable": "Geen gegevens beschikbaar", + "ErrorLoadingDatatable": "Er is een fout opgetreden tijdens het verzoek. Controleer het bericht voor details.", "Total": "totaal", "Selected": "geselecteed", "PagerShowMenuEntries": "Toon _MENU_-vermeldingen", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json index 596f816b4f..6739b673d7 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Pokaż od 0 do 0 z 0 rekordów", "PagerInfoFiltered": "(filtruj od _MAX_ wszystkich rekordów)", "NoDataAvailableInDatatable": "Nie znaleziono danych w tabeli", + "ErrorLoadingDatatable": "Wystąpił błąd podczas żądania. Sprawdź wiadomość, aby uzyskać szczegóły.", "Total": "całkowity", "Selected": "wybrany", "PagerShowMenuEntries": "Pokaż _MENU_ rekordów", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json index 73ec4120ce..5c4a6790f7 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Mostrando 0 até 0 de 0 registros", "PagerInfoFiltered": "(filtrado de um total de _MAX_ registros)", "NoDataAvailableInDatatable": "Nenhum dado disponível", + "ErrorLoadingDatatable": "Ocorreu um erro durante a solicitação. Verifique a mensagem para mais detalhes.", "Total": "total", "Selected": "selecionado", "PagerShowMenuEntries": "Mostrando _MENU_ registros", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json index bf83b4e89a..c5850bef00 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Afişate 0 din 0 înregistrări", "PagerInfoFiltered": "(filtrate de la _MAX_ înregistrări totale)", "NoDataAvailableInDatatable": "Nicio informaţie disponibilă", + "ErrorLoadingDatatable": "A apărut o eroare în timpul solicitării. Verificați mesajul pentru detalii.", "Total": "total", "Selected": "selectate", "PagerShowMenuEntries": "Afişează _MENU_ intrări", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json index c7e6cc5439..f329315488 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Записи с 0 до 0 из 0 записей.", "PagerInfoFiltered": "(отфильтровано из _MAX_ записей)", "NoDataAvailableInDatatable": "Данные в таблице отсутствуют", + "ErrorLoadingDatatable": "Произошла ошибка во время запроса. Проверьте сообщение для получения деталей.", "Total": "общий", "Selected": "выбранный", "PagerShowMenuEntries": "Показать _MENU_ записей", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json index eb06cdf1d0..6cc73f0cc6 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Zobrazených 0 až 0 z 0 záznamov", "PagerInfoFiltered": "(filtrované z celkom _MAX_ záznamov)", "NoDataAvailableInDatatable": "Nie sú k dispozícii žiadne údaje", + "ErrorLoadingDatatable": "Počas žiadosti došlo k chybe. Skontrolujte správu pre podrobnosti.", "Total": "celkom", "Selected": "vybrané", "PagerShowMenuEntries": "Zobraziť _MENU_ záznamov", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json index 3516ba5499..36d1bb14a6 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Prikazanih 0 do 0 od 0 zapisov", "PagerInfoFiltered": "(filtrirano od vseh _MAX_ zapisov)", "NoDataAvailableInDatatable": "V tabeli ni na voljo podatkov", + "ErrorLoadingDatatable": "Pri zahtevi je prišlo do napake. Preverite sporočilo za podrobnosti.", "Total": "skupaj", "Selected": "izbrani", "PagerShowMenuEntries": "Prikaži _MENU_ zapise", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json index 1278ee2375..2636d1087a 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "0 kayıttan 0 ile 0 arası gösteriliyor.", "PagerInfoFiltered": "(_MAX_ kayıt arasından filtrelendi)", "NoDataAvailableInDatatable": "Tabloda kayıt mevcut değil.", + "ErrorLoadingDatatable": "İstek sırasında bir hata oluştu. Detaylar için mesajı kontrol edin.", "Total": "toplam", "Selected": "seçilen", "PagerShowMenuEntries": "Sayfada _MENU_ kayıt göster.", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json index e807f851a1..fca1f0954c 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "Hiển thị từ 0 đến 0 trong 0 mục", "PagerInfoFiltered": "(được lọc từ tổng số _MAX_ mục)", "NoDataAvailableInDatatable": "Không có dữ liệu trong bảng", + "ErrorLoadingDatatable": "Đã xảy ra lỗi trong quá trình yêu cầu. Kiểm tra tin nhắn để biết chi tiết.", "Total": "toàn bộ", "Selected": "đã chọn", "PagerShowMenuEntries": "Hiển thị _MENU_ mục", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json index 9a2ab1091b..2824c1bbbc 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "显示0个条目中的0到0", "PagerInfoFiltered": "(从 _MAX_ 总条目中过滤掉)", "NoDataAvailableInDatatable": "表中没有数据", + "ErrorLoadingDatatable": " 请求过程中发生错误。检查消息以获取详细信息", "Total": "总计", "Selected": "已选", "PagerShowMenuEntries": "显示 _MENU_ 条数据", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json index 897356e3b7..17dac54739 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json @@ -38,6 +38,7 @@ "PagerInfoEmpty": "顯示0個紀錄中的0到0", "PagerInfoFiltered": "(從 _MAX_ 所有紀錄中過濾掉)", "NoDataAvailableInDatatable": "資料表中沒有資料", + "ErrorLoadingDatatable": "請求過程中發生錯誤。檢查消息以獲取詳細信息。", "Total": "總共", "Selected": "已選擇", "PagerShowMenuEntries": "顯示 _MENU_ 實體", From 18aef2d6da47b0688c1952d7a4517182529319f6 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Thu, 3 Oct 2024 15:35:59 +0300 Subject: [PATCH 16/21] add: error state config --- .../src/lib/directives/ngx-datatable-list.directive.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts index c31acd9fe8..f6f163a4d4 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts @@ -64,11 +64,11 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { protected subscribeToLoadingState() { const requestStatus$ = this.list.requestStatus$.pipe(distinctUntilChanged()); - const { emptyMessage } = this.ngxDatatableMessages || defaultNgxDatatableMessages; + const { emptyMessage, errorMessage } = this.ngxDatatableMessages || defaultNgxDatatableMessages; requestStatus$.subscribe(status => { this.table.loadingIndicator = false; - + if (status === 'idle') { return; } @@ -81,6 +81,12 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { return; } + if (status === 'error') { + this.table.messages.emptyMessage = this.localizationService.instant(errorMessage); + this.viewContainerRef.clear(); + this.cdRef.markForCheck(); + } + if (status === 'success') { this.table.messages.emptyMessage = this.localizationService.instant(emptyMessage); this.viewContainerRef.clear(); From 078914d2fb537245acff3a435b05bb12264a3f9f Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Thu, 3 Oct 2024 15:36:33 +0300 Subject: [PATCH 17/21] add: `errorMessage` for datatable messages --- .../theme-shared/src/lib/tokens/ngx-datatable-messages.token.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tokens/ngx-datatable-messages.token.ts b/npm/ng-packs/packages/theme-shared/src/lib/tokens/ngx-datatable-messages.token.ts index bf1a73ab09..07b4157a37 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tokens/ngx-datatable-messages.token.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tokens/ngx-datatable-messages.token.ts @@ -2,12 +2,14 @@ import { InjectionToken } from '@angular/core'; export interface NgxDatatableMessages { emptyMessage: string; + errorMessage: string; totalMessage: string; selectedMessage: string; } export const defaultNgxDatatableMessages = { emptyMessage: 'AbpUi::NoDataAvailableInDatatable', + errorMessage: 'AbpUi::ErrorLoadingDatatable', totalMessage: 'AbpUi::Total', selectedMessage: 'AbpUi::Selected', }; From 774d81c14cd4e48f117795c23ac671e3df8e1217 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Thu, 3 Oct 2024 16:22:15 +0300 Subject: [PATCH 18/21] update: rollback to idle request status --- npm/ng-packs/packages/core/src/lib/services/list.service.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts index 48730efef1..a2bdd71048 100644 --- a/npm/ng-packs/packages/core/src/lib/services/list.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -11,6 +11,7 @@ import { catchError, debounceTime, filter, + finalize, shareReplay, switchMap, takeUntil, @@ -140,6 +141,7 @@ export class ListService implements tap(() => this._isLoading$.next(false)), tap(() => this._requestStatus.next('success')), shareReplay({ bufferSize: 1, refCount: true }), + finalize(() => this._requestStatus.next('idle')), takeUntil(this.destroy$), ), ), From e5b4451c5d35f51e9753cef4f8461be58405d278 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Fri, 4 Oct 2024 08:16:55 +0300 Subject: [PATCH 19/21] update: deal with request status changes inside the stream callback --- .../packages/core/src/lib/services/list.service.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts index a2bdd71048..027624ef88 100644 --- a/npm/ng-packs/packages/core/src/lib/services/list.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -137,14 +137,16 @@ export class ListService implements this._requestStatus.next('error'); return EMPTY; }), - filter(Boolean), - tap(() => this._isLoading$.next(false)), tap(() => this._requestStatus.next('success')), - shareReplay({ bufferSize: 1, refCount: true }), - finalize(() => this._requestStatus.next('idle')), - takeUntil(this.destroy$), + finalize(() => { + this._isLoading$.next(false); + this._requestStatus.next('idle'); + }), ), ), + filter(Boolean), + shareReplay({ bufferSize: 1, refCount: true }), + takeUntil(this.destroy$), ); } From fb7f8acbabfaaf13dfa015305106e4358235772a Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Fri, 4 Oct 2024 10:54:56 +0300 Subject: [PATCH 20/21] update: function naming to handle request states --- .../src/lib/directives/ngx-datatable-list.directive.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts index f6f163a4d4..d50038b1b7 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts @@ -49,7 +49,7 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { ngOnInit() { this.subscribeToPage(); this.subscribeToSort(); - this.subscribeToLoadingState(); + this.subscribeToRequestStatus(); } ngOnChanges({ list }: SimpleChanges) { @@ -62,7 +62,7 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { this.table.offset = page; } - protected subscribeToLoadingState() { + protected subscribeToRequestStatus() { const requestStatus$ = this.list.requestStatus$.pipe(distinctUntilChanged()); const { emptyMessage, errorMessage } = this.ngxDatatableMessages || defaultNgxDatatableMessages; From 91c1beef259c0271cff77f35b229a478971c2214 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Fri, 4 Oct 2024 15:12:44 +0300 Subject: [PATCH 21/21] fix: rollback to the latest home page for the app template --- .../angular/src/app/home/home.component.html | 407 +++++++++++++----- 1 file changed, 298 insertions(+), 109 deletions(-) diff --git a/templates/app/angular/src/app/home/home.component.html b/templates/app/angular/src/app/home/home.component.html index c4149e6905..c80dd1724e 100644 --- a/templates/app/angular/src/app/home/home.component.html +++ b/templates/app/angular/src/app/home/home.component.html @@ -1,120 +1,309 @@ -
-

Let's improve your application!

-

Here are some links to help you get started:

-
-
-
-
- +
+
+
+
+
+ @if(!hasLoggedIn){ +

Welcome

+

+ {{ '::LongWelcomeMessage' | abpLocalization }} +

+ {{ 'AbpAccount::Login' | abpLocalization }} + } - + " + > - + +

Customize Lepton Theme

+

Learn how to customize LeptonX Theme as you wish.

+ Customize Lepton +
+ + +
+
+
+
+
+ + +
+
+
+
+
+ +

+ A unique community platform for + ABP Lovers! +

+

+ Explore all ABP users' experiences with the ABP Framework, discover articles and videos on + how to use ABP, and join raffles for a chance to win surprise gifts! +

+ Join ABP Community +
+ +
+
+
+
+ +
+
+
+
+
+

THE OFFICIAL GUIDE

+

Mastering ABP Framework

+

+ Written by the creator of the ABP Framework, this book will help you gain a complete + understanding of the framework and modern web application development techniques. +

+ +
+
+ +
+
+
+
+
+ + ] + } + } + " + > +
+ + +

+ {{ context.label }} +
+ + +
+
+ +
+
+
+ + +
+
+
+
{{ context.title }}
-
- +
+ + + @for(item of context.items; track $index; let last = $last){ + + + + } - } - " - > - - -

- - - - -

-
+ +
+ @if(item.icon){ +
+ @if(item.iconType === 'image'){ + + }@else if(item.iconType === 'icon'){ + + }@else{ +
+ } +
} - ] +
{{ item.title }}
+
+ + + +
+
+