UI: mobile app qr code improvements, cleanup
This commit is contained in:
		
							parent
							
								
									9d71bb77ea
								
							
						
					
					
						commit
						45ed484c2a
					
				@ -17,7 +17,7 @@
 | 
			
		||||
    "cards.label_widget",
 | 
			
		||||
    "cards.dashboard_state_widget",
 | 
			
		||||
    "cards.qr_code",
 | 
			
		||||
    "cards.mobile_app_qr_code",
 | 
			
		||||
    "mobile_app_qr_code",
 | 
			
		||||
    "cards.attributes_card",
 | 
			
		||||
    "cards.html_card",
 | 
			
		||||
    "cards.html_value_card",
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,6 @@
 | 
			
		||||
    "home_page_widgets.quick_links",
 | 
			
		||||
    "home_page_widgets.documentation_links",
 | 
			
		||||
    "home_page_widgets.dashboards",
 | 
			
		||||
    "home_page_widgets.usage_info",
 | 
			
		||||
    "home_page_widgets.home_page_mobile_app_qr_code"
 | 
			
		||||
    "home_page_widgets.usage_info"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -83,7 +83,7 @@ export const selectMobileQrEnabled = createSelector(
 | 
			
		||||
  (state: AuthState) => state.mobileQrEnabled
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const selectPersistDeviceStateToTelemetryAndMobileQrEnabled = createSelector(
 | 
			
		||||
export const selectHomeDashboardParams = createSelector(
 | 
			
		||||
  selectPersistDeviceStateToTelemetry,
 | 
			
		||||
  selectMobileQrEnabled,
 | 
			
		||||
  (persistDeviceStateToTelemetry, mobileQrEnabled) => ({persistDeviceStateToTelemetry, mobileQrEnabled})
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@ import { HttpClient } from '@angular/common/http';
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { MobileAppQRCodeSettings } from '@shared/models/mobile-app.models';
 | 
			
		||||
import { MobileAppSettings } from '@shared/models/mobile-app.models';
 | 
			
		||||
 | 
			
		||||
@Injectable({
 | 
			
		||||
  providedIn: 'root'
 | 
			
		||||
@ -30,15 +30,15 @@ export class MobileAppService {
 | 
			
		||||
  ) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getMobileAppSettings(config?: RequestConfig): Observable<MobileAppQRCodeSettings> {
 | 
			
		||||
    return this.http.get<MobileAppQRCodeSettings>(`/api/mobile/app/settings`, defaultHttpOptionsFromConfig(config));
 | 
			
		||||
  public getMobileAppSettings(config?: RequestConfig): Observable<MobileAppSettings> {
 | 
			
		||||
    return this.http.get<MobileAppSettings>(`/api/mobile/app/settings`, defaultHttpOptionsFromConfig(config));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public saveMobileAppSettings(mobileAppSettings: MobileAppQRCodeSettings, config?: RequestConfig): Observable<MobileAppQRCodeSettings> {
 | 
			
		||||
    return this.http.post<MobileAppQRCodeSettings>(`/api/mobile/app/settings`, mobileAppSettings, defaultHttpOptionsFromConfig(config));
 | 
			
		||||
  public saveMobileAppSettings(mobileAppSettings: MobileAppSettings, config?: RequestConfig): Observable<MobileAppSettings> {
 | 
			
		||||
    return this.http.post<MobileAppSettings>(`/api/mobile/app/settings`, mobileAppSettings, defaultHttpOptionsFromConfig(config));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getMobileAppDeepLink( config?: RequestConfig): Observable<string> {
 | 
			
		||||
  public getMobileAppDeepLink(config?: RequestConfig): Observable<string> {
 | 
			
		||||
    return this.http.get<string>(`/api/mobile/deepLink`, defaultHttpOptionsFromConfig(config));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,23 +22,20 @@ import {
 | 
			
		||||
  QRCodeConfig
 | 
			
		||||
} from '@shared/models/mobile-app.models';
 | 
			
		||||
 | 
			
		||||
export type MobileAppQrCodeWidgetSettings = {
 | 
			
		||||
  useDefaultApp: boolean;
 | 
			
		||||
  androidConfig: AndroidConfig;
 | 
			
		||||
  iosConfig: IosConfig;
 | 
			
		||||
export interface MobileAppQrCodeWidgetSettings {
 | 
			
		||||
  useSystemSettings: boolean;
 | 
			
		||||
  androidConfig: Pick<AndroidConfig, 'enabled'>;
 | 
			
		||||
  iosConfig: Pick<IosConfig, 'enabled'>;
 | 
			
		||||
  qrCodeConfig: Omit<QRCodeConfig, 'showOnHomePage'>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const mobileAppQrCodeWidgetDefaultSettings: MobileAppQrCodeWidgetSettings = {
 | 
			
		||||
  useDefaultApp: true,
 | 
			
		||||
  useSystemSettings: true,
 | 
			
		||||
  androidConfig: {
 | 
			
		||||
    enabled: true,
 | 
			
		||||
    appPackage: '',
 | 
			
		||||
    sha256CertFingerprints: ''
 | 
			
		||||
    enabled: true
 | 
			
		||||
  },
 | 
			
		||||
  iosConfig: {
 | 
			
		||||
    enabled: true,
 | 
			
		||||
    appId: ''
 | 
			
		||||
    enabled: true
 | 
			
		||||
  },
 | 
			
		||||
  qrCodeConfig: {
 | 
			
		||||
    badgeEnabled: true,
 | 
			
		||||
 | 
			
		||||
@ -15,16 +15,12 @@
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<div *ngIf="!previewMode && !ctx" class="tb-title" translate>admin.mobile-app.connect-mobile-app</div>
 | 
			
		||||
<div class="tb-flex column center align-center">
 | 
			
		||||
  <div class="tb-flex row align-center shrink"
 | 
			
		||||
       [class.row]="mobileAppSettings?.qrCodeConfig.badgePosition === badgePosition.RIGHT"
 | 
			
		||||
       [class.row-reverse]="mobileAppSettings?.qrCodeConfig.badgePosition === badgePosition.LEFT">
 | 
			
		||||
<!--    <canvas #canvas class="tb-qrcode"></canvas>-->
 | 
			
		||||
    <canvas #canvas class="tb-qrcode"></canvas>
 | 
			
		||||
    <div *ngIf="mobileAppSettings?.qrCodeConfig.badgeEnabled"
 | 
			
		||||
         class="tb-flex column tb-badge-container"
 | 
			
		||||
         [class.tb-badge-container]="!previewMode && !ctx">
 | 
			
		||||
    <div class="tb-flex column" *ngIf="mobileAppSettings?.qrCodeConfig.badgeEnabled && showBadgeContainer">
 | 
			
		||||
      <ng-container *ngIf="mobileAppSettings.qrCodeConfig.badgeStyle === badgeStyle.ORIGINAL;else white">
 | 
			
		||||
        <img *ngIf="mobileAppSettings.iosConfig.enabled" [src]="badgeStyleURLMap.get(badgeStyle.ORIGINAL).iOS">
 | 
			
		||||
        <img *ngIf="mobileAppSettings.androidConfig.enabled" [src]="badgeStyleURLMap.get(badgeStyle.ORIGINAL).android">
 | 
			
		||||
 | 
			
		||||
@ -23,24 +23,6 @@
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tb-title {
 | 
			
		||||
  padding-bottom: 12px;
 | 
			
		||||
  align-self: start;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  line-height: 24px;
 | 
			
		||||
  letter-spacing: 0.1px;
 | 
			
		||||
  color: rgba(0, 0, 0, 0.76);
 | 
			
		||||
 | 
			
		||||
  @media #{$mat-md-lg} {
 | 
			
		||||
    padding-bottom: 0;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
    font-size: 14px;
 | 
			
		||||
    line-height: 20px;
 | 
			
		||||
    letter-spacing: 0.25px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tb-qrcode-label {
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  color: rgba(0, 0, 0, 0.54);
 | 
			
		||||
@ -56,8 +38,3 @@
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tb-badge-container {
 | 
			
		||||
  @media #{$mat-md} {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,97 +14,108 @@
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
 | 
			
		||||
import { ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
 | 
			
		||||
import { PageComponent } from '@shared/components/page.component';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { BadgePosition, BadgeStyle, badgeStyleURLMap, MobileAppQRCodeSettings } from '@shared/models/mobile-app.models';
 | 
			
		||||
import { BadgePosition, BadgeStyle, badgeStyleURLMap, MobileAppSettings } from '@shared/models/mobile-app.models';
 | 
			
		||||
import { MobileAppService } from '@core/http/mobile-app.service';
 | 
			
		||||
import { WidgetContext } from '@home/models/widget-component.models';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { interval, mergeMap, Observable, Subject, takeUntil } from 'rxjs';
 | 
			
		||||
import { Subject } from 'rxjs';
 | 
			
		||||
import { MINUTE } from '@shared/models/time/time.models';
 | 
			
		||||
import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
import { MobileAppQrCodeWidgetSettings } from '@home/components/widget/lib/cards/mobile-app-qr-code-widget.models';
 | 
			
		||||
import { isDefinedAndNotNull } from '@core/utils';
 | 
			
		||||
import { ResizeObserver } from '@juggle/resize-observer';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-mobile-app-qrcode-widget',
 | 
			
		||||
  templateUrl: './mobile-app-qrcode-widget.component.html',
 | 
			
		||||
  styleUrls: ['./mobile-app-qrcode-widget.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
			
		||||
export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  ctx: WidgetContext;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  previewMode: boolean;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  set mobileAppSettings(settings: MobileAppQRCodeSettings | MobileAppQrCodeWidgetSettings) {
 | 
			
		||||
  set mobileAppSettings(settings: MobileAppSettings | MobileAppQrCodeWidgetSettings) {
 | 
			
		||||
    if (settings) {
 | 
			
		||||
      this.mobileAppSettingsValue = settings;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  get mobileAppSettings() {
 | 
			
		||||
  get mobileAppSettings(): MobileAppSettings | MobileAppQrCodeWidgetSettings {
 | 
			
		||||
    return this.mobileAppSettingsValue;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @ViewChild('canvas', {static: false}) canvasRef: ElementRef<HTMLCanvasElement>;
 | 
			
		||||
  @ViewChild('canvas', {static: true}) canvasRef: ElementRef<HTMLCanvasElement>;
 | 
			
		||||
 | 
			
		||||
  private readonly destroy$ = new Subject<void>();
 | 
			
		||||
  private widgetResize$: ResizeObserver;
 | 
			
		||||
 | 
			
		||||
  badgeStyle = BadgeStyle;
 | 
			
		||||
  badgePosition = BadgePosition;
 | 
			
		||||
  badgeStyleURLMap = badgeStyleURLMap;
 | 
			
		||||
  showBadgeContainer = true;
 | 
			
		||||
 | 
			
		||||
  private mobileAppSettingsValue: MobileAppQRCodeSettings | MobileAppQrCodeWidgetSettings;
 | 
			
		||||
  private mobileAppSettingsValue: MobileAppSettings | MobileAppQrCodeWidgetSettings;
 | 
			
		||||
  private deepLinkTTL: number;
 | 
			
		||||
  private deepLinkTTLTimeoutID: NodeJS.Timeout;
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              protected cd: ChangeDetectorRef,
 | 
			
		||||
              private mobileAppService: MobileAppService,
 | 
			
		||||
              private utilsService: UtilsService) {
 | 
			
		||||
              private utilsService: UtilsService,
 | 
			
		||||
              private elementRef: ElementRef) {
 | 
			
		||||
    super(store);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    if (!this.previewMode) {
 | 
			
		||||
      if (this.ctx) {
 | 
			
		||||
    if (!this.mobileAppSettings) {
 | 
			
		||||
      if (isDefinedAndNotNull(this.ctx.settings.useSystemSettings) && !this.ctx.settings.useSystemSettings) {
 | 
			
		||||
        this.mobileAppSettings = this.ctx.settings;
 | 
			
		||||
      } else {
 | 
			
		||||
        this.mobileAppService.getMobileAppSettings().subscribe((settings => {
 | 
			
		||||
          this.mobileAppSettings = settings;
 | 
			
		||||
          this.cd.detectChanges();
 | 
			
		||||
          this.cd.markForCheck();
 | 
			
		||||
        }));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngAfterViewInit(): void {
 | 
			
		||||
    this.getMobileAppDeepLink().subscribe(link => {
 | 
			
		||||
      this.deepLinkTTL = Number(this.utilsService.getQueryParam('ttl', link)) * MINUTE;
 | 
			
		||||
      this.updateQRCode(link);
 | 
			
		||||
      interval(this.deepLinkTTL).pipe(
 | 
			
		||||
        takeUntil(this.destroy$),
 | 
			
		||||
        mergeMap(() => this.getMobileAppDeepLink())
 | 
			
		||||
      ).subscribe(link => this.updateQRCode(link));
 | 
			
		||||
    this.initMobileAppQRCode();
 | 
			
		||||
    this.widgetResize$ = new ResizeObserver(() => {
 | 
			
		||||
      const showHideBadgeContainer = this.elementRef.nativeElement.offsetWidth > 250;
 | 
			
		||||
      if (showHideBadgeContainer !== this.showBadgeContainer) {
 | 
			
		||||
        this.showBadgeContainer = showHideBadgeContainer;
 | 
			
		||||
        this.cd.markForCheck();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    this.widgetResize$.observe(this.elementRef.nativeElement);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    if (this.widgetResize$) {
 | 
			
		||||
      this.widgetResize$.disconnect();
 | 
			
		||||
    }
 | 
			
		||||
    super.ngOnDestroy();
 | 
			
		||||
    this.destroy$.next();
 | 
			
		||||
    this.destroy$.complete();
 | 
			
		||||
    clearTimeout(this.deepLinkTTLTimeoutID);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getMobileAppDeepLink(): Observable<string> {
 | 
			
		||||
    return this.mobileAppService.getMobileAppDeepLink();
 | 
			
		||||
  private initMobileAppQRCode() {
 | 
			
		||||
    if (this.deepLinkTTLTimeoutID) {
 | 
			
		||||
      clearTimeout(this.deepLinkTTLTimeoutID);
 | 
			
		||||
      this.deepLinkTTLTimeoutID = null;
 | 
			
		||||
    }
 | 
			
		||||
    this.mobileAppService.getMobileAppDeepLink().subscribe(link => {
 | 
			
		||||
      this.deepLinkTTL = Number(this.utilsService.getQueryParam('ttl', link)) * MINUTE;
 | 
			
		||||
      this.updateQRCode(link);
 | 
			
		||||
      this.deepLinkTTLTimeoutID = setTimeout(() => this.initMobileAppQRCode(), this.deepLinkTTL);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateQRCode(link: string) {
 | 
			
		||||
  private updateQRCode(link: string) {
 | 
			
		||||
    import('qrcode').then((QRCode) => {
 | 
			
		||||
      QRCode.toCanvas(this.canvasRef.nativeElement, link, { width: 100 });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -15,88 +15,36 @@
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<section class="tb-widget-settings tb-form-panel no-border no-padding" [formGroup]="mobileAppQRCodeWidgetSettingsForm" fxLayout="column">
 | 
			
		||||
  <div class="tb-form-panel">
 | 
			
		||||
    <div fxLayout="row" fxLayoutAlign="space-between center">
 | 
			
		||||
      <div class="tb-form-panel-title" translate>admin.mobile-app.applications</div>
 | 
			
		||||
      <tb-toggle-select formControlName="useDefaultApp">
 | 
			
		||||
        <tb-toggle-option [value]="true">{{ 'admin.mobile-app.default' | translate }}</tb-toggle-option>
 | 
			
		||||
        <tb-toggle-option [value]="false">{{ 'admin.mobile-app.custom' | translate }}</tb-toggle-option>
 | 
			
		||||
      </tb-toggle-select>
 | 
			
		||||
<section class="tb-widget-settings tb-form-panel no-border no-padding" [formGroup]="mobileAppQRCodeWidgetSettingsForm">
 | 
			
		||||
  <div class="tb-form-panel no-padding">
 | 
			
		||||
    <div class="tb-form-row no-border no-padding-bottom">
 | 
			
		||||
      <mat-slide-toggle class="mat-slide" formControlName="useSystemSettings" (click)="$event.stopPropagation()">
 | 
			
		||||
        {{ 'admin.mobile-app.use-system-settings' | translate }}
 | 
			
		||||
      </mat-slide-toggle>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-form-panel stroked no-padding no-gap" formGroupName="androidConfig">
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="tb-form-panel" *ngIf="!mobileAppQRCodeWidgetSettingsForm.get('useSystemSettings').value">
 | 
			
		||||
    <div class="tb-form-panel-title" translate>admin.mobile-app.applications</div>
 | 
			
		||||
    <div class="tb-form-panel stroked no-padding no-gap">
 | 
			
		||||
      <div class="tb-form-row no-border no-padding-bottom">
 | 
			
		||||
        <mat-slide-toggle class="mat-slide" formControlName="enabled" (click)="$event.stopPropagation()">
 | 
			
		||||
        <mat-slide-toggle class="mat-slide" [formControl]="mobileAppQRCodeWidgetSettingsForm.get('androidConfig.enabled')" (click)="$event.stopPropagation()">
 | 
			
		||||
          {{ 'admin.mobile-app.android' | translate }}
 | 
			
		||||
        </mat-slide-toggle>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="tb-form-panel no-border no-padding-top"
 | 
			
		||||
           *ngIf="!mobileAppQRCodeWidgetSettingsForm.get('useDefaultApp').value && mobileAppQRCodeWidgetSettingsForm.get('androidConfig.enabled').value">
 | 
			
		||||
        <div class="tb-form-row column-xs">
 | 
			
		||||
          <div class="tb-fixed-width">{{ 'admin.mobile-app.app-package-name' | translate }}</div>
 | 
			
		||||
          <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
            <input matInput formControlName="appPackage" placeholder="{{'admin.mobile-app.set' | translate}}">
 | 
			
		||||
            <mat-icon matSuffix
 | 
			
		||||
                      matTooltipPosition="above"
 | 
			
		||||
                      matTooltipClass="tb-error-tooltip"
 | 
			
		||||
                      [matTooltip]="'admin.mobile-app.app-package-name-required' | translate"
 | 
			
		||||
                      *ngIf="mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').hasError('required')
 | 
			
		||||
                          && mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').touched"
 | 
			
		||||
                      class="tb-error">
 | 
			
		||||
              warning
 | 
			
		||||
            </mat-icon>
 | 
			
		||||
          </mat-form-field>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="tb-form-panel no-border no-padding-top"
 | 
			
		||||
           *ngIf="!mobileAppQRCodeWidgetSettingsForm.get('useDefaultApp').value && mobileAppQRCodeWidgetSettingsForm.get('androidConfig.enabled').value">
 | 
			
		||||
        <div class="tb-form-row column-xs">
 | 
			
		||||
          <div class="tb-fixed-width">{{ 'admin.mobile-app.sha256-certificate-fingerprints' | translate }}</div>
 | 
			
		||||
          <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
            <input matInput formControlName="sha256CertFingerprints" placeholder="{{'admin.mobile-app.set' | translate}}">
 | 
			
		||||
            <mat-icon matSuffix
 | 
			
		||||
                      matTooltipPosition="above"
 | 
			
		||||
                      matTooltipClass="tb-error-tooltip"
 | 
			
		||||
                      [matTooltip]="'admin.mobile-app.sha256-certificate-fingerprints-required' | translate"
 | 
			
		||||
                      *ngIf="mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').hasError('required')
 | 
			
		||||
                          && mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').touched"
 | 
			
		||||
                      class="tb-error">
 | 
			
		||||
              warning
 | 
			
		||||
            </mat-icon>
 | 
			
		||||
          </mat-form-field>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-form-panel stroked no-padding no-gap" formGroupName="iosConfig">
 | 
			
		||||
      <div class="tb-form-row no-border no-padding-bottom">
 | 
			
		||||
        <mat-slide-toggle class="mat-slide" formControlName="enabled" (click)="$event.stopPropagation()">
 | 
			
		||||
        <mat-slide-toggle class="mat-slide" [formControl]="mobileAppQRCodeWidgetSettingsForm.get('iosConfig.enabled')" (click)="$event.stopPropagation()">
 | 
			
		||||
          {{ 'admin.mobile-app.ios' | translate }}
 | 
			
		||||
        </mat-slide-toggle>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="tb-form-panel no-border no-padding-top"
 | 
			
		||||
           *ngIf="!mobileAppQRCodeWidgetSettingsForm.get('useDefaultApp').value && mobileAppQRCodeWidgetSettingsForm.get('iosConfig.enabled').value">
 | 
			
		||||
        <div class="tb-form-row column-xs">
 | 
			
		||||
          <div class="tb-fixed-width">{{ 'admin.mobile-app.app-id' | translate }}</div>
 | 
			
		||||
          <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
            <input matInput formControlName="appId" placeholder="{{'admin.mobile-app.set' | translate}}">
 | 
			
		||||
            <mat-icon matSuffix
 | 
			
		||||
                      matTooltipPosition="above"
 | 
			
		||||
                      matTooltipClass="tb-error-tooltip"
 | 
			
		||||
                      [matTooltip]="'admin.mobile-app.app-id-required' | translate"
 | 
			
		||||
                      *ngIf="mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').hasError('required')
 | 
			
		||||
                          && mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').touched"
 | 
			
		||||
                      class="tb-error">
 | 
			
		||||
              warning
 | 
			
		||||
            </mat-icon>
 | 
			
		||||
          </mat-form-field>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="tb-form-panel" formGroupName="qrCodeConfig">
 | 
			
		||||
  <div class="tb-form-panel" formGroupName="qrCodeConfig" *ngIf="!mobileAppQRCodeWidgetSettingsForm.get('useSystemSettings').value">
 | 
			
		||||
    <div class="tb-form-panel-title" translate>admin.mobile-app.appearance</div>
 | 
			
		||||
    <div class="tb-form-panel stroked no-padding no-gap">
 | 
			
		||||
      <div class="tb-form-row space-between no-border no-padding-bottom column-xs">
 | 
			
		||||
        <mat-slide-toggle class="mat-slide tb-fixed-width" formControlName="badgeEnabled"
 | 
			
		||||
        <mat-slide-toggle class="mat-slide fixed-title-width-230" formControlName="badgeEnabled"
 | 
			
		||||
                          (click)="$event.stopPropagation()">
 | 
			
		||||
          {{ 'admin.mobile-app.badges' | translate }}
 | 
			
		||||
        </mat-slide-toggle>
 | 
			
		||||
@ -118,7 +66,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-form-panel stroked no-padding no-gap">
 | 
			
		||||
      <div class="tb-form-row space-between no-border no-padding-bottom column-xs">
 | 
			
		||||
        <mat-slide-toggle class="mat-slide tb-fixed-width" formControlName="qrCodeLabelEnabled" (click)="$event.stopPropagation()">
 | 
			
		||||
        <mat-slide-toggle class="mat-slide fixed-title-width-230" formControlName="qrCodeLabelEnabled" (click)="$event.stopPropagation()">
 | 
			
		||||
          {{ 'admin.mobile-app.label' | translate }}
 | 
			
		||||
        </mat-slide-toggle>
 | 
			
		||||
        <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2024 The Thingsboard Authors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.tb-fixed-width {
 | 
			
		||||
  min-width: 230px;
 | 
			
		||||
}
 | 
			
		||||
@ -25,7 +25,7 @@ import { mobileAppQrCodeWidgetDefaultSettings } from '@home/components/widget/li
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-mobile-app-qr-code-widget-settings',
 | 
			
		||||
  templateUrl: './mobile-app-qr-code-widget-settings.component.html',
 | 
			
		||||
  styleUrls: ['/mobile-app-qr-code-widget-settings.component.scss', './../widget-settings.scss']
 | 
			
		||||
  styleUrls: ['./../widget-settings.scss']
 | 
			
		||||
})
 | 
			
		||||
export class MobileAppQrCodeWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
 | 
			
		||||
@ -49,15 +49,12 @@ export class MobileAppQrCodeWidgetSettingsComponent extends WidgetSettingsCompon
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
    this.mobileAppQRCodeWidgetSettingsForm = this.fb.group({
 | 
			
		||||
      useDefaultApp: [settings.useDefaultApp],
 | 
			
		||||
      useSystemSettings: [settings.useSystemSettings],
 | 
			
		||||
      androidConfig: this.fb.group({
 | 
			
		||||
        enabled: [settings.androidConfig.enabled],
 | 
			
		||||
        appPackage: [settings.androidConfig.appPackage, [Validators.required]],
 | 
			
		||||
        sha256CertFingerprints: [settings.androidConfig.sha256CertFingerprints, [Validators.required]]
 | 
			
		||||
      }),
 | 
			
		||||
      iosConfig: this.fb.group({
 | 
			
		||||
        enabled: [settings.iosConfig.enabled],
 | 
			
		||||
        appId: [settings.iosConfig.appId, [Validators.required]]
 | 
			
		||||
      }),
 | 
			
		||||
      qrCodeConfig: this.fb.group({
 | 
			
		||||
        badgeEnabled: [settings.qrCodeConfig.badgeEnabled],
 | 
			
		||||
@ -70,35 +67,16 @@ export class MobileAppQrCodeWidgetSettingsComponent extends WidgetSettingsCompon
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected validatorTriggers(): string[] {
 | 
			
		||||
    return ['useDefaultApp', 'androidConfig.enabled', 'iosConfig.enabled', 'qrCodeConfig.badgeEnabled', 'qrCodeConfig.qrCodeLabelEnabled'];
 | 
			
		||||
    return ['useSystemSettings', 'androidConfig.enabled', 'iosConfig.enabled', 'qrCodeConfig.badgeEnabled', 'qrCodeConfig.qrCodeLabelEnabled'];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected updateValidators(emitEvent: boolean) {
 | 
			
		||||
    const useDefaultApp = this.mobileAppQRCodeWidgetSettingsForm.get('useDefaultApp').value;
 | 
			
		||||
    const useSystemSettings = this.mobileAppQRCodeWidgetSettingsForm.get('useSystemSettings').value;
 | 
			
		||||
    const androidEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.enabled').value;
 | 
			
		||||
    const iosEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.enabled').value;
 | 
			
		||||
    const badgeEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').value;
 | 
			
		||||
    const qrCodeLabelEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabelEnabled').value;
 | 
			
		||||
 | 
			
		||||
    if (useDefaultApp) {
 | 
			
		||||
      this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').disable({emitEvent: false});
 | 
			
		||||
      this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').disable({emitEvent: false});
 | 
			
		||||
      this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').disable({emitEvent: false});
 | 
			
		||||
    } else {
 | 
			
		||||
      if (androidEnabled) {
 | 
			
		||||
        this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').enable({emitEvent: false});
 | 
			
		||||
        this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').enable({emitEvent: false});
 | 
			
		||||
      } else {
 | 
			
		||||
        this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').disable({emitEvent: false});
 | 
			
		||||
        this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').disable({emitEvent: false});
 | 
			
		||||
      }
 | 
			
		||||
      if (iosEnabled) {
 | 
			
		||||
        this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').enable({emitEvent: false});
 | 
			
		||||
      } else {
 | 
			
		||||
        this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').disable({emitEvent: false});
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!androidEnabled && !iosEnabled) {
 | 
			
		||||
      this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').disable({emitEvent: false});
 | 
			
		||||
      this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeStyle').disable({emitEvent: false});
 | 
			
		||||
@ -116,7 +94,7 @@ export class MobileAppQrCodeWidgetSettingsComponent extends WidgetSettingsCompon
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (qrCodeLabelEnabled) {
 | 
			
		||||
    if (qrCodeLabelEnabled && !useSystemSettings) {
 | 
			
		||||
      this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabel').enable({emitEvent: false});
 | 
			
		||||
    } else {
 | 
			
		||||
      this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabel').disable({emitEvent: false});
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@
 | 
			
		||||
          <div class="tb-form-panel no-border no-padding-top"
 | 
			
		||||
               *ngIf="!mobileAppSettingsForm.get('useDefaultApp').value && mobileAppSettingsForm.get('androidConfig.enabled').value">
 | 
			
		||||
            <div class="tb-form-row column-xs">
 | 
			
		||||
              <div class="tb-fixed-width">{{ 'admin.mobile-app.app-package-name' | translate }}</div>
 | 
			
		||||
              <div class="fixed-title-width-230">{{ 'admin.mobile-app.app-package-name' | translate }}</div>
 | 
			
		||||
              <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
                <input matInput formControlName="appPackage" placeholder="{{'admin.mobile-app.set' | translate}}">
 | 
			
		||||
                <mat-icon matSuffix
 | 
			
		||||
@ -61,7 +61,7 @@
 | 
			
		||||
          <div class="tb-form-panel no-border no-padding-top"
 | 
			
		||||
               *ngIf="!mobileAppSettingsForm.get('useDefaultApp').value && mobileAppSettingsForm.get('androidConfig.enabled').value">
 | 
			
		||||
            <div class="tb-form-row column-xs">
 | 
			
		||||
              <div class="tb-fixed-width">{{ 'admin.mobile-app.sha256-certificate-fingerprints' | translate }}</div>
 | 
			
		||||
              <div class="fixed-title-width-230">{{ 'admin.mobile-app.sha256-certificate-fingerprints' | translate }}</div>
 | 
			
		||||
              <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
                <input matInput formControlName="sha256CertFingerprints" placeholder="{{'admin.mobile-app.set' | translate}}">
 | 
			
		||||
                <mat-icon matSuffix
 | 
			
		||||
@ -86,7 +86,7 @@
 | 
			
		||||
          <div class="tb-form-panel no-border no-padding-top"
 | 
			
		||||
               *ngIf="!mobileAppSettingsForm.get('useDefaultApp').value && mobileAppSettingsForm.get('iosConfig.enabled').value">
 | 
			
		||||
            <div class="tb-form-row column-xs">
 | 
			
		||||
              <div class="tb-fixed-width">{{ 'admin.mobile-app.app-id' | translate }}</div>
 | 
			
		||||
              <div class="fixed-title-width-230">{{ 'admin.mobile-app.app-id' | translate }}</div>
 | 
			
		||||
              <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
                <input matInput formControlName="appId" placeholder="{{'admin.mobile-app.set' | translate}}">
 | 
			
		||||
                <mat-icon matSuffix
 | 
			
		||||
@ -113,7 +113,7 @@
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="tb-form-panel stroked no-padding no-gap" *ngIf="mobileAppSettingsForm.get('qrCodeConfig.showOnHomePage').value">
 | 
			
		||||
          <div class="tb-form-row space-between no-border no-padding-bottom column-xs">
 | 
			
		||||
            <mat-slide-toggle class="mat-slide tb-fixed-width" formControlName="badgeEnabled"
 | 
			
		||||
            <mat-slide-toggle class="mat-slide fixed-title-width-230" formControlName="badgeEnabled"
 | 
			
		||||
                              (click)="$event.stopPropagation()">
 | 
			
		||||
              {{ 'admin.mobile-app.badges' | translate }}
 | 
			
		||||
            </mat-slide-toggle>
 | 
			
		||||
@ -135,7 +135,7 @@
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="tb-form-panel stroked no-padding no-gap" *ngIf="mobileAppSettingsForm.get('qrCodeConfig.showOnHomePage').value">
 | 
			
		||||
          <div class="tb-form-row space-between no-border no-padding-bottom column-xs">
 | 
			
		||||
            <mat-slide-toggle class="mat-slide tb-fixed-width" formControlName="qrCodeLabelEnabled" (click)="$event.stopPropagation()">
 | 
			
		||||
            <mat-slide-toggle class="mat-slide fixed-title-width-230" formControlName="qrCodeLabelEnabled" (click)="$event.stopPropagation()">
 | 
			
		||||
              {{ 'admin.mobile-app.label' | translate }}
 | 
			
		||||
            </mat-slide-toggle>
 | 
			
		||||
            <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
@ -154,7 +154,7 @@
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="tb-form-panel tb-qrcode-preview" *ngIf="mobileAppSettingsForm.get('qrCodeConfig.showOnHomePage').value">
 | 
			
		||||
          <div class="tb-form-panel-title" translate>admin.mobile-app.preview</div>
 | 
			
		||||
          <tb-mobile-app-qrcode-widget previewMode
 | 
			
		||||
          <tb-mobile-app-qrcode-widget
 | 
			
		||||
            [mobileAppSettings]="mobileAppSettingsForm.getRawValue()">
 | 
			
		||||
          </tb-mobile-app-qrcode-widget>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
@ -14,10 +14,6 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.tb-fixed-width {
 | 
			
		||||
  min-width: 230px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tb-qrcode-preview {
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.04);
 | 
			
		||||
  box-shadow: none;
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ import {
 | 
			
		||||
  badgePositionTranslationsMap,
 | 
			
		||||
  BadgeStyle,
 | 
			
		||||
  badgeStyleTranslationsMap,
 | 
			
		||||
  MobileAppQRCodeSettings
 | 
			
		||||
  MobileAppSettings
 | 
			
		||||
} from '@shared/models/mobile-app.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -39,7 +39,7 @@ export class MobileAppSettingsComponent extends PageComponent implements HasConf
 | 
			
		||||
 | 
			
		||||
  mobileAppSettingsForm: FormGroup;
 | 
			
		||||
 | 
			
		||||
  mobileAppSettings: MobileAppQRCodeSettings;
 | 
			
		||||
  mobileAppSettings: MobileAppSettings;
 | 
			
		||||
 | 
			
		||||
  private readonly destroy$ = new Subject<void>();
 | 
			
		||||
 | 
			
		||||
@ -133,7 +133,7 @@ export class MobileAppSettingsComponent extends PageComponent implements HasConf
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private processMobileAppSettings(mobileAppSettings: MobileAppQRCodeSettings): void {
 | 
			
		||||
  private processMobileAppSettings(mobileAppSettings: MobileAppSettings): void {
 | 
			
		||||
    this.mobileAppSettings = {...mobileAppSettings};
 | 
			
		||||
    this.mobileAppSettingsForm.reset(this.mobileAppSettings);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -27,8 +27,9 @@ import { AppState } from '@core/core.state';
 | 
			
		||||
import { map } from 'rxjs/operators';
 | 
			
		||||
import {
 | 
			
		||||
  getCurrentAuthUser,
 | 
			
		||||
  selectHomeDashboardParams,
 | 
			
		||||
  selectMobileQrEnabled,
 | 
			
		||||
  selectPersistDeviceStateToTelemetryAndMobileQrEnabled
 | 
			
		||||
  selectPersistDeviceStateToTelemetry
 | 
			
		||||
} from '@core/auth/auth.selectors';
 | 
			
		||||
import { EntityKeyType } from '@shared/models/query/query.models';
 | 
			
		||||
import { ResourcesService } from '@core/services/resources.service';
 | 
			
		||||
@ -37,9 +38,42 @@ const sysAdminHomePageJson = '/assets/dashboard/sys_admin_home_page.json';
 | 
			
		||||
const tenantAdminHomePageJson = '/assets/dashboard/tenant_admin_home_page.json';
 | 
			
		||||
const customerUserHomePageJson = '/assets/dashboard/customer_user_home_page.json';
 | 
			
		||||
 | 
			
		||||
const updateDeviceActivityKeyFilterIfNeeded = (store: Store<AppState>,
 | 
			
		||||
                                               dashboard$: Observable<HomeDashboard>): Observable<HomeDashboard> =>
 | 
			
		||||
  store.pipe(select(selectPersistDeviceStateToTelemetryAndMobileQrEnabled)).pipe(
 | 
			
		||||
const getHomeDashboard = (store: Store<AppState>, resourcesService: ResourcesService) => {
 | 
			
		||||
  const authority = getCurrentAuthUser(store).authority;
 | 
			
		||||
  switch (authority) {
 | 
			
		||||
    case Authority.SYS_ADMIN:
 | 
			
		||||
      return applySystemParametersToHomeDashboard(store, resourcesService.loadJsonResource(sysAdminHomePageJson), authority);
 | 
			
		||||
    case Authority.TENANT_ADMIN:
 | 
			
		||||
      return applySystemParametersToHomeDashboard(store, resourcesService.loadJsonResource(tenantAdminHomePageJson), authority);
 | 
			
		||||
    case Authority.CUSTOMER_USER:
 | 
			
		||||
      return applySystemParametersToHomeDashboard(store, resourcesService.loadJsonResource(customerUserHomePageJson), authority);
 | 
			
		||||
    default:
 | 
			
		||||
      return of(null);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const applySystemParametersToHomeDashboard = (store: Store<AppState>,
 | 
			
		||||
                                              dashboard$: Observable<HomeDashboard>,
 | 
			
		||||
                                              authority: Authority): Observable<HomeDashboard> => {
 | 
			
		||||
  let selectParams$: Observable<{persistDeviceStateToTelemetry?: boolean, mobileQrEnabled?: boolean}>;
 | 
			
		||||
  switch (authority) {
 | 
			
		||||
    case Authority.SYS_ADMIN:
 | 
			
		||||
      selectParams$ = store.pipe(
 | 
			
		||||
        select(selectMobileQrEnabled),
 | 
			
		||||
        map(mobileQrEnabled => ({mobileQrEnabled}))
 | 
			
		||||
      );
 | 
			
		||||
      break;
 | 
			
		||||
    case Authority.TENANT_ADMIN:
 | 
			
		||||
      selectParams$ = store.pipe(select(selectHomeDashboardParams));
 | 
			
		||||
      break;
 | 
			
		||||
    case Authority.CUSTOMER_USER:
 | 
			
		||||
      selectParams$ = store.pipe(
 | 
			
		||||
        select(selectPersistDeviceStateToTelemetry),
 | 
			
		||||
        map(persistDeviceStateToTelemetry => ({persistDeviceStateToTelemetry}))
 | 
			
		||||
      );
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  return selectParams$.pipe(
 | 
			
		||||
    mergeMap((params) => dashboard$.pipe(
 | 
			
		||||
      map((dashboard) => {
 | 
			
		||||
        if (params.persistDeviceStateToTelemetry) {
 | 
			
		||||
@ -49,31 +83,21 @@ const updateDeviceActivityKeyFilterIfNeeded = (store: Store<AppState>,
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return params.mobileQrEnabled ? toggleMobileQRCodeDisplay(dashboard) : dashboard;
 | 
			
		||||
        if (params.mobileQrEnabled) {
 | 
			
		||||
          for (const widgetId of Object.keys(dashboard.configuration.widgets)) {
 | 
			
		||||
            if (dashboard.configuration.widgets[widgetId].config.title === 'Select show mobile QR code') {
 | 
			
		||||
              dashboard.configuration.widgets[widgetId].config.settings.markdownTextFunction =
 | 
			
		||||
                (dashboard.configuration.widgets[widgetId].config.settings.markdownTextFunction as string)
 | 
			
		||||
                  .replace('\'${mobileQrEnabled}\'', String(true));
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        dashboard.hideDashboardToolbar = true;
 | 
			
		||||
        return dashboard;
 | 
			
		||||
      })
 | 
			
		||||
    ))
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
const toggleMobileQRCodeDisplayIfNeeded = (store: Store<AppState>,
 | 
			
		||||
              dashboard$: Observable<HomeDashboard>): Observable<HomeDashboard> =>
 | 
			
		||||
  store.pipe(select(selectMobileQrEnabled)).pipe(
 | 
			
		||||
    mergeMap((mobileQrEnabled) => dashboard$.pipe(
 | 
			
		||||
      map((dashboard) => {
 | 
			
		||||
        return mobileQrEnabled ? toggleMobileQRCodeDisplay(dashboard) : dashboard;
 | 
			
		||||
      })
 | 
			
		||||
    ))
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
const toggleMobileQRCodeDisplay = (dashboard: HomeDashboard) => {
 | 
			
		||||
  for (const widgetId of Object.keys(dashboard.configuration.widgets)) {
 | 
			
		||||
    if (dashboard.configuration.widgets[widgetId].config.title === 'Select show mobile QR code') {
 | 
			
		||||
      dashboard.configuration.widgets[widgetId].config.settings.markdownTextFunction =
 | 
			
		||||
        (dashboard.configuration.widgets[widgetId].config.settings.markdownTextFunction as string)
 | 
			
		||||
          .replace('\'${mobileQrEnabled}\'', String(true));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return dashboard;
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const homeDashboardResolver: ResolveFn<HomeDashboard> = (
 | 
			
		||||
  route: ActivatedRouteSnapshot,
 | 
			
		||||
@ -85,27 +109,7 @@ export const homeDashboardResolver: ResolveFn<HomeDashboard> = (
 | 
			
		||||
  dashboardService.getHomeDashboard().pipe(
 | 
			
		||||
    mergeMap((dashboard) => {
 | 
			
		||||
      if (!dashboard) {
 | 
			
		||||
        let dashboard$: Observable<HomeDashboard>;
 | 
			
		||||
        const authority = getCurrentAuthUser(store).authority;
 | 
			
		||||
        switch (authority) {
 | 
			
		||||
          case Authority.SYS_ADMIN:
 | 
			
		||||
            dashboard$ = toggleMobileQRCodeDisplayIfNeeded(store, resourcesService.loadJsonResource(sysAdminHomePageJson));
 | 
			
		||||
            break;
 | 
			
		||||
          case Authority.TENANT_ADMIN:
 | 
			
		||||
            dashboard$ = updateDeviceActivityKeyFilterIfNeeded(store, resourcesService.loadJsonResource(tenantAdminHomePageJson));
 | 
			
		||||
            break;
 | 
			
		||||
          case Authority.CUSTOMER_USER:
 | 
			
		||||
            dashboard$ = updateDeviceActivityKeyFilterIfNeeded(store, resourcesService.loadJsonResource(customerUserHomePageJson));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (dashboard$) {
 | 
			
		||||
          return dashboard$.pipe(
 | 
			
		||||
            map((homeDashboard) => {
 | 
			
		||||
              homeDashboard.hideDashboardToolbar = true;
 | 
			
		||||
              return homeDashboard;
 | 
			
		||||
            })
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
        return getHomeDashboard(store, resourcesService);
 | 
			
		||||
      }
 | 
			
		||||
      return of(dashboard);
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
@ -14,10 +14,9 @@
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { TenantId } from '@shared/models/id/tenant-id';
 | 
			
		||||
import { HasTenantId } from '@shared/models/entity.models';
 | 
			
		||||
 | 
			
		||||
export interface MobileAppQRCodeSettings {
 | 
			
		||||
  tenantId: TenantId;
 | 
			
		||||
export interface MobileAppSettings extends HasTenantId {
 | 
			
		||||
  useDefaultApp: boolean;
 | 
			
		||||
  androidConfig: AndroidConfig;
 | 
			
		||||
  iosConfig: IosConfig;
 | 
			
		||||
 | 
			
		||||
@ -2634,22 +2634,24 @@
 | 
			
		||||
        "typeFullFqn": "system.home_page_widgets.getting_started"
 | 
			
		||||
      },
 | 
			
		||||
      "53d5f2dd-d432-5362-745f-63bf4487dc96": {
 | 
			
		||||
        "typeFullFqn": "system.home_page_widgets.home_page_mobile_app_qr_code",
 | 
			
		||||
        "typeFullFqn": "system.mobile_app_qr_code",
 | 
			
		||||
        "type": "static",
 | 
			
		||||
        "sizeX": 6,
 | 
			
		||||
        "sizeY": 3,
 | 
			
		||||
        "config": {
 | 
			
		||||
          "showTitle": false,
 | 
			
		||||
          "showTitle": true,
 | 
			
		||||
          "backgroundColor": "rgb(255, 255, 255)",
 | 
			
		||||
          "color": "rgba(0, 0, 0, 0.87)",
 | 
			
		||||
          "padding": "8px",
 | 
			
		||||
          "settings": {},
 | 
			
		||||
          "title": "Mobile app QR code",
 | 
			
		||||
          "title": "{i18n:admin.mobile-app.connect-mobile-app}",
 | 
			
		||||
          "dropShadow": false,
 | 
			
		||||
          "enableFullscreen": false,
 | 
			
		||||
          "widgetStyle": {},
 | 
			
		||||
          "widgetCss": "",
 | 
			
		||||
          "noDataDisplayMessage": ""
 | 
			
		||||
          "widgetCss": ".tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title {\n    padding: 0;\n}\n\n.tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title > .title-row > .title {\n    padding-bottom: 12px;\n    font-weight: 600;\n    font-size: 20px;\n    line-height: 24px;\n    letter-spacing: 0.1px;\n    color: rgba(0, 0, 0, 0.76);\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n    .tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title > .title-row > .title {\n        padding-bottom: 0;\n        font-weight: 500;\n        font-size: 14px;\n        line-height: 20px;\n        letter-spacing: 0.25px;\n  }\n}\n",
 | 
			
		||||
          "showTitleIcon": false,
 | 
			
		||||
          "titleTooltip": "",
 | 
			
		||||
          "titleStyle": null
 | 
			
		||||
        },
 | 
			
		||||
        "row": 0,
 | 
			
		||||
        "col": 0,
 | 
			
		||||
 | 
			
		||||
@ -1177,19 +1177,24 @@
 | 
			
		||||
        "typeFullFqn": "system.home_page_widgets.getting_started"
 | 
			
		||||
      },
 | 
			
		||||
      "8c5207d8-7103-4dc2-db48-d61c0c8c61fd": {
 | 
			
		||||
        "typeFullFqn": "system.home_page_widgets.home_page_mobile_app_qr_code",
 | 
			
		||||
        "typeFullFqn": "system.mobile_app_qr_code",
 | 
			
		||||
        "type": "static",
 | 
			
		||||
        "sizeX": 6,
 | 
			
		||||
        "sizeY": 3,
 | 
			
		||||
        "config": {
 | 
			
		||||
          "showTitle": false,
 | 
			
		||||
          "showTitle": true,
 | 
			
		||||
          "backgroundColor": "rgb(255, 255, 255)",
 | 
			
		||||
          "color": "rgba(0, 0, 0, 0.87)",
 | 
			
		||||
          "padding": "8px",
 | 
			
		||||
          "settings": {},
 | 
			
		||||
          "title": "Mobile app QR code",
 | 
			
		||||
          "title": "{i18n:admin.mobile-app.connect-mobile-app}",
 | 
			
		||||
          "dropShadow": false,
 | 
			
		||||
          "enableFullscreen": false
 | 
			
		||||
          "enableFullscreen": false,
 | 
			
		||||
          "widgetStyle": {},
 | 
			
		||||
          "widgetCss": ".tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title {\n    padding: 0;\n}\n\n.tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title > .title-row > .title {\n    padding-bottom: 12px;\n    font-weight: 600;\n    font-size: 20px;\n    line-height: 24px;\n    letter-spacing: 0.1px;\n    color: rgba(0, 0, 0, 0.76);\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n    .tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title > .title-row > .title {\n        padding-bottom: 0;\n        font-weight: 500;\n        font-size: 14px;\n        line-height: 20px;\n        letter-spacing: 0.25px;\n  }\n}\n",
 | 
			
		||||
          "showTitleIcon": false,
 | 
			
		||||
          "titleTooltip": "",
 | 
			
		||||
          "titleStyle": null
 | 
			
		||||
        },
 | 
			
		||||
        "row": 0,
 | 
			
		||||
        "col": 0,
 | 
			
		||||
 | 
			
		||||
@ -433,6 +433,7 @@
 | 
			
		||||
            "ios": "iOS",
 | 
			
		||||
            "app-id": "App ID",
 | 
			
		||||
            "app-id-required": "App ID is required",
 | 
			
		||||
            "appearance": "Appearance",
 | 
			
		||||
            "appearance-on-home-page": "Appearance on Home page",
 | 
			
		||||
            "enabled": "Enabled",
 | 
			
		||||
            "disabled": "Disabled",
 | 
			
		||||
@ -445,7 +446,8 @@
 | 
			
		||||
            "left": "Left",
 | 
			
		||||
            "set": "Set",
 | 
			
		||||
            "preview": "Preview",
 | 
			
		||||
            "connect-mobile-app": "Connect mobile app"
 | 
			
		||||
            "connect-mobile-app": "Connect mobile app",
 | 
			
		||||
            "use-system-settings": "Use system settings"
 | 
			
		||||
        },
 | 
			
		||||
        "2fa":  {
 | 
			
		||||
            "2fa": "Two-factor authentication",
 | 
			
		||||
 | 
			
		||||
@ -234,6 +234,12 @@
 | 
			
		||||
    }
 | 
			
		||||
    .fixed-title-width {
 | 
			
		||||
      min-width: 200px;
 | 
			
		||||
 | 
			
		||||
      &-230 {
 | 
			
		||||
        min-width: 230px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    [class^="fixed-title-width"] {
 | 
			
		||||
      @media #{$mat-xs} {
 | 
			
		||||
        min-width: fit-content;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user