Add skeleton loading to top widget

This commit is contained in:
Clemente Raposo 2024-12-11 00:59:13 +00:00 committed by Jack Anderson
parent 863c6a8d16
commit 737dd75a32
3 changed files with 96 additions and 47 deletions

View file

@ -30,56 +30,97 @@
<div class="p-2 widget-bar-entry-message" *ngIf="this.messageLabelKey">
{{vm.appStrings[this.messageLabelKey] || '' | uppercase}}
</div>
<ng-container *ngFor="let item of statistics | keyvalue">
<ng-container *ngIf="!loading()">
<ng-container *ngFor="let item of statistics | keyvalue">
<div class="d-flex flex-column justify-content-center align-items-baseline widget-bar-entry p-2">
<div class="d-flex flex-column justify-content-center align-items-baseline widget-bar-entry p-2">
<ng-container *ngIf="!shouldHide(vm.statistics[item.key], item.value)">
<ng-container *ngIf="!shouldHide(vm.statistics[item.key], item.value)">
<div *ngIf="item.value.labelKey && getLabel(item.value.labelKey)" class="pr-1 widget-bar-entry-label">
<ng-container *ngIf="!isValueEmpty(vm.statistics[item.key])">
{{getLabel(item.value.labelKey) | uppercase}}:
</ng-container>
<ng-container *ngIf="isValueEmpty(vm.statistics[item.key])">
{{getLabel(item.value.labelKey) | uppercase}}
</ng-container>
</div>
<div *ngIf="item.value.labelKey && getLabel(item.value.labelKey)" class="pr-1 widget-bar-entry-label">
<ng-container *ngIf="!isValueEmpty(vm.statistics[item.key])">
{{getLabel(item.value.labelKey) | uppercase}}:
</ng-container>
<ng-container *ngIf="isValueEmpty(vm.statistics[item.key])">
{{getLabel(item.value.labelKey) | uppercase}}
</ng-container>
</div>
</ng-container>
<ng-container
*ngIf="item.key && vm.statistics[item.key] && !shouldHide(vm.statistics[item.key], item.value)">
<div class="pl-1 pr-1 widget-bar-entry-value"
*ngIf="!vm.statistics[item.key].loading && vm.statistics[item.key].field">
<ng-container
*ngIf="!isValueEmpty(vm.statistics[item.key]) || item.value.hideValueIfEmpty !== true">
<scrm-field [type]="vm.statistics[item.key].field.type" [field]="vm.statistics[item.key].field"
mode="list"></scrm-field>
</ng-container>
</div>
</ng-container>
<div class="pl-1 pr-1 widget-bar-entry-loading" *ngIf="(item.value.store.loading$ | async) as loading">
<scrm-inline-loading-spinner></scrm-inline-loading-spinner>
<ng-container *ngIf="!loading && (!item.key || !vm.statistics[item.key])">
-
</ng-container>
<ng-container
*ngIf="item.key && vm.statistics[item.key] && !shouldHide(vm.statistics[item.key], item.value)">
<div class="pl-1 pr-1 widget-bar-entry-value"
*ngIf="!vm.statistics[item.key].loading && vm.statistics[item.key].field">
<ng-container
*ngIf="!isValueEmpty(vm.statistics[item.key]) || item.value.hideValueIfEmpty !== true">
<scrm-field [type]="vm.statistics[item.key].field.type" [field]="vm.statistics[item.key].field"
mode="list"></scrm-field>
</ng-container>
</div>
</ng-container>
<div class="pl-1 pr-1 widget-bar-entry-loading" *ngIf="(item.value.store.loading$ | async) as loading">
<div class="pb-2">
<div class="large-size-text-skeleton small-length-text-skeleton rounded box-loading skeleton-field-content">
.
</div>
</div>
<ng-container *ngIf="!loading && (!item.key || !vm.statistics[item.key])">
-
</ng-container>
</div>
<ng-container *ngIf="!shouldHide(vm.statistics[item.key], item.value)">
<div *ngIf="item.value.endLabelKey && getLabel(item.value.endLabelKey)"
class="pl-1 widget-bar-entry-end-label">
{{getLabel(item.value.endLabelKey) | uppercase}}
</div>
</ng-container>
</div>
<ng-container *ngIf="!shouldHide(vm.statistics[item.key], item.value)">
</ng-container>
</ng-container>
<div *ngIf="item.value.endLabelKey && getLabel(item.value.endLabelKey)"
class="pl-1 widget-bar-entry-end-label">
{{getLabel(item.value.endLabelKey) | uppercase}}
<ng-container *ngIf="loading()">
<div class="d-flex flex-column justify-content-center align-items-baseline widget-bar-entry p-2">
<div class="pl-1 pr-1 widget-bar-entry-value">
<div class="pb-2">
<div class="large-size-text-skeleton small-length-text-skeleton rounded box-loading skeleton-field-content">
.
</div>
</div>
</div>
<div class="pr-1 widget-bar-entry-label large-length-text-skeleton rounded box-loading skeleton-field-content">
.
</div>
</ng-container>
</div>
<div class="d-flex flex-column justify-content-center align-items-baseline widget-bar-entry p-2">
<div class="pl-1 pr-1 widget-bar-entry-value">
<div class="pb-2">
<div class="large-size-text-skeleton small-length-text-skeleton rounded box-loading skeleton-field-content">
.
</div>
</div>
</div>
<div class="pr-1 widget-bar-entry-label large-length-text-skeleton rounded box-loading skeleton-field-content">
.
</div>
</div>
</ng-container>
</div>

View file

@ -24,7 +24,7 @@
* the words "Supercharged by SuiteCRM".
*/
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Component, OnDestroy, OnInit, signal, WritableSignal} from '@angular/core';
import {BaseWidgetComponent} from '../../../widgets/base-widget.model';
import {SingleValueStatisticsStore} from '../../../../store/single-value-statistics/single-value-statistics.store';
import {
@ -65,7 +65,7 @@ export class StatisticsTopWidgetComponent extends BaseWidgetComponent implements
vm$: Observable<StatisticsTopWidgetState>;
messageLabelKey: string;
loading$: Observable<boolean>;
protected loading = true;
protected loading: WritableSignal<boolean> = signal(true);
protected subs: Subscription[] = [];
constructor(
@ -148,7 +148,7 @@ export class StatisticsTopWidgetComponent extends BaseWidgetComponent implements
combineLatestWith(...loadings$),
map((loadings) => {
if (!loadings || loadings.length < 1) {
this.loading = false;
this.loading.set(false);
return false;
}
@ -158,7 +158,7 @@ export class StatisticsTopWidgetComponent extends BaseWidgetComponent implements
loading = loading && value;
});
this.loading = loading;
this.loading.set(loading);
return loading;
})
@ -186,9 +186,9 @@ export class StatisticsTopWidgetComponent extends BaseWidgetComponent implements
if (this.config.reload$) {
this.subs.push(this.config.reload$.subscribe(() => {
if (this.loading === false) {
if (this.loading() === false) {
this.loading = true;
this.loading.set(true);
this.config.options.statistics.forEach(statistic => {
if (!statistic.type) {
@ -273,4 +273,6 @@ export class StatisticsTopWidgetComponent extends BaseWidgetComponent implements
return this.language.getFieldLabel(key, module);
}
protected readonly signal = signal;
}

View file

@ -27,17 +27,23 @@
.widget-bar {
background-color: $white;
color: $dark-midnight-grey;
box-shadow: 0 .125rem .25rem #00000013 ;
box-shadow: 0 .125rem .25rem #00000013;
border: 1px solid $extra-light-grey;
min-height: 70px;
}
.widget-bar .widget-bar-entry-value {
font-weight: 900;
font-size: 1.7em;
.skeleton-field-content {
background-color: $dark-midnight-grey;
opacity: 0.2;
}
}
.widget-bar .widget-bar-entry-label,
.widget-bar .widget-bar-entry-end-label{
.widget-bar .widget-bar-entry-end-label {
font-weight: 400;
font-size: 0.7em;
}
@ -45,5 +51,5 @@
.widget-bar .inline-spinner > div {
width: 0.45em;
height: 0.45em;
background-color: white;
background-color: $dark-midnight-grey;
}