Browse Source

UI: added separate mobile qrcode widget to cards bundle

pull/10591/head
rusikv 2 years ago
parent
commit
953c215002
  1. 1
      application/src/main/data/json/system/widget_bundles/cards.json
  2. 2
      application/src/main/data/json/system/widget_bundles/home_page_widgets.json
  3. 21
      application/src/main/data/json/system/widget_types/home_mobile_app_qr_code.json
  4. 10
      application/src/main/data/json/system/widget_types/mobile_app_qr_code.json
  5. 10
      ui-ngx/src/app/core/http/mobile-app.service.ts
  6. 50
      ui-ngx/src/app/modules/home/components/widget/lib/cards/mobile-app-qr-code-widge.models.ts
  7. 6
      ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.html
  8. 3
      ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.scss
  9. 14
      ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts
  10. 130
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.html
  11. 19
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.scss
  12. 156
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.ts
  13. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  14. 6
      ui-ngx/src/app/modules/home/pages/admin/mobile-app-settings.component.ts
  15. 2
      ui-ngx/src/app/shared/models/mobile-app.models.ts
  16. 12
      ui-ngx/src/assets/dashboard/tenant_admin_home_page.json
  17. 3
      ui-ngx/src/form.scss

1
application/src/main/data/json/system/widget_bundles/cards.json

@ -17,6 +17,7 @@
"cards.label_widget",
"cards.dashboard_state_widget",
"cards.qr_code",
"cards.mobile_app_qr_code",
"cards.attributes_card",
"cards.html_card",
"cards.html_value_card",

2
application/src/main/data/json/system/widget_bundles/home_page_widgets.json

@ -14,6 +14,6 @@
"home_page_widgets.documentation_links",
"home_page_widgets.dashboards",
"home_page_widgets.usage_info",
"home_page_widgets.mobile_app_qr_code"
"home_page_widgets.home_mobile_app_qr_code"
]
}

21
application/src/main/data/json/system/widget_types/home_mobile_app_qr_code.json

@ -0,0 +1,21 @@
{
"fqn": "home_page_widgets.home_mobile_app_qr_code",
"name": "Mobile app QR code",
"deprecated": false,
"image": null,
"description": null,
"descriptor": {
"type": "static",
"sizeX": 6,
"sizeY": 3,
"resources": [],
"templateHtml": "<tb-mobile-app-qrcode-widget>\n</tb-mobile-app-qrcode-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n}",
"settingsSchema": "",
"dataKeySettingsSchema": "",
"settingsDirective": "",
"defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"cardHtml\":\"<div class='card'>HTML code here</div>\",\"cardCss\":\".card {\\n font-weight: bold;\\n font-size: 32px;\\n color: #999;\\n width: 100%;\\n height: 100%;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\"},\"title\":\"Mobile app QR code\",\"dropShadow\":true}"
},
"tags": null
}

10
application/src/main/data/json/system/widget_types/mobile_app_qr_code.json

@ -1,21 +1,21 @@
{
"fqn": "home_page_widgets.mobile_app_qr_code",
"fqn": "cards.mobile_app_qr_code",
"name": "Mobile app QR code",
"deprecated": false,
"image": null,
"description": null,
"descriptor": {
"type": "static",
"sizeX": 6,
"sizeX": 7.5,
"sizeY": 3,
"resources": [],
"templateHtml": "<tb-mobile-app-qrcode-widget\n [ctx]=\"ctx\">\n</tb-mobile-app-qrcode-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.mobileAppQrcodeWidget.ngOnInit();\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.mobileAppQrcodeWidget.ngOnDestroy();\n}",
"controllerScript": "self.onInit = function() {\n}\n",
"settingsSchema": "",
"dataKeySettingsSchema": "",
"settingsDirective": "",
"defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"cardHtml\":\"<div class='card'>HTML code here</div>\",\"cardCss\":\".card {\\n font-weight: bold;\\n font-size: 32px;\\n color: #999;\\n width: 100%;\\n height: 100%;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\"},\"title\":\"HTML Card\",\"dropShadow\":true}"
"settingsDirective": "tb-mobile-app-qr-code-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"useDefaultApp\":true,\"androidConfig\":{\"enabled\":true,\"appPackage\":\"\",\"sha256CertFingerprints\":\"\"},\"iosConfig\":{\"enabled\":true,\"appId\":\"\"},\"qrCodeConfig\":{\"badgeEnabled\":true,\"badgeStyle\":\"ORIGINAL\",\"badgePosition\":\"RIGHT\",\"qrCodeLabelEnabled\":true,\"qrCodeLabel\":\"Scan to connect or download mobile app\"}},\"title\":\"Mobile app QR code\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400}}"
},
"tags": null
}

10
ui-ngx/src/app/core/http/mobile-app.service.ts

@ -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 { MobileAppSettings } from '@shared/models/mobile-app.models';
import { MobileAppQRCodeSettings } from '@shared/models/mobile-app.models';
@Injectable({
providedIn: 'root'
@ -30,12 +30,12 @@ export class MobileAppService {
) {
}
public getMobileAppSettings(config?: RequestConfig): Observable<MobileAppSettings> {
return this.http.get<MobileAppSettings>(`/api/mobile/app/settings`, defaultHttpOptionsFromConfig(config));
public getMobileAppSettings(config?: RequestConfig): Observable<MobileAppQRCodeSettings> {
return this.http.get<MobileAppQRCodeSettings>(`/api/mobile/app/settings`, defaultHttpOptionsFromConfig(config));
}
public saveMobileAppSettings(mobileAppSettings: MobileAppSettings, config?: RequestConfig): Observable<MobileAppSettings> {
return this.http.post<MobileAppSettings>(`/api/mobile/app/settings`, mobileAppSettings, defaultHttpOptionsFromConfig(config));
public saveMobileAppSettings(mobileAppSettings: MobileAppQRCodeSettings, config?: RequestConfig): Observable<MobileAppQRCodeSettings> {
return this.http.post<MobileAppQRCodeSettings>(`/api/mobile/app/settings`, mobileAppSettings, defaultHttpOptionsFromConfig(config));
}
public getMobileAppDeepLink( config?: RequestConfig): Observable<string> {

50
ui-ngx/src/app/modules/home/components/widget/lib/cards/mobile-app-qr-code-widge.models.ts

@ -0,0 +1,50 @@
///
/// 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.
///
import {
AndroidConfig,
BadgePosition,
BadgeStyle,
IosConfig,
QRCodeConfig
} from '@shared/models/mobile-app.models';
export type MobileAppQrCodeWidgetSettings = {
useDefaultApp: boolean;
androidConfig: AndroidConfig;
iosConfig: IosConfig;
qrCodeConfig: Omit<QRCodeConfig, 'showOnHomePage'>;
}
export const mobileAppQrCodeWidgetDefaultSettings: MobileAppQrCodeWidgetSettings = {
useDefaultApp: true,
androidConfig: {
enabled: true,
appPackage: '',
sha256CertFingerprints: ''
},
iosConfig: {
enabled: true,
appId: ''
},
qrCodeConfig: {
badgeEnabled: true,
badgeStyle: BadgeStyle.ORIGINAL,
badgePosition: BadgePosition.RIGHT,
qrCodeLabelEnabled: true,
qrCodeLabel: 'Scan to connect or download mobile app'
}
}

6
ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.html

@ -15,15 +15,15 @@
limitations under the License.
-->
<div *ngIf="!previewMode" class="tb-title" translate>admin.mobile-app.connect-mobile-app</div>
<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" style="margin-bottom: 8px"
<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>
<div *ngIf="mobileAppSettings?.qrCodeConfig.badgeEnabled"
class="tb-flex column no-gap tb-badge-container"
[class.tb-badge-container]="!previewMode">
[class.tb-badge-container]="!previewMode && !ctx">
<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">

3
ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.scss

@ -17,7 +17,6 @@
@import '../../../../../../scss/constants';
:host {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
@ -25,12 +24,14 @@
}
.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} {
font-weight: 500;
font-size: 14px;

14
ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts

@ -18,13 +18,14 @@ import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, Input, OnDestr
import { PageComponent } from '@shared/components/page.component';
import { AppState } from '@core/core.state';
import { Store } from '@ngrx/store';
import { BadgePosition, BadgeStyle, badgeStyleURLMap, MobileAppSettings } from '@shared/models/mobile-app.models';
import { BadgePosition, BadgeStyle, badgeStyleURLMap, MobileAppQRCodeSettings } 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 { 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-widge.models';
@Component({
selector: 'tb-mobile-app-qrcode-widget',
@ -41,7 +42,7 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI
previewMode: boolean;
@Input()
set mobileAppSettings(settings: MobileAppSettings) {
set mobileAppSettings(settings: MobileAppQRCodeSettings | MobileAppQrCodeWidgetSettings) {
if (settings) {
this.mobileAppSettingsValue = settings;
}
@ -59,7 +60,7 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI
badgePosition = BadgePosition;
badgeStyleURLMap = badgeStyleURLMap;
private mobileAppSettingsValue: MobileAppSettings;
private mobileAppSettingsValue: MobileAppQRCodeSettings | MobileAppQrCodeWidgetSettings;
private deepLinkTTL: number;
constructor(protected store: Store<AppState>,
@ -71,9 +72,8 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI
ngOnInit(): void {
if (this.ctx) {
this.ctx.$scope.mobileAppQrcodeWidget = this;
}
if (!this.mobileAppSettings) {
this.mobileAppSettings = this.ctx.settings;
} else {
this.mobileAppService.getMobileAppSettings().subscribe((settings => {
this.mobileAppSettings = settings;
this.cd.detectChanges();
@ -104,7 +104,7 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI
updateQRCode(link: string) {
import('qrcode').then((QRCode) => {
QRCode.toCanvas(this.canvasRef.nativeElement, link, { width: 125});
QRCode.toCanvas(this.canvasRef.nativeElement, link, { width: 90 });
});
}

130
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.html

@ -0,0 +1,130 @@
<!--
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.
-->
<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>
</div>
<div class="tb-form-panel stroked no-padding no-gap" formGroupName="androidConfig">
<div class="tb-form-row no-border no-padding-bottom">
<mat-slide-toggle class="mat-slide" formControlName="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()">
{{ '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 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"
(click)="$event.stopPropagation()">
{{ 'admin.mobile-app.badges' | translate }}
</mat-slide-toggle>
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="badgeStyle" appearance="outline" subscriptSizing="dynamic">
<mat-option *ngFor="let badgeStyle of badgeStyleTranslationsMap | keyvalue" [value]="badgeStyle.key">
{{ badgeStyle.value | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="badgePosition" appearance="outline" subscriptSizing="dynamic">
<mat-option *ngFor="let badgePosition of badgePositionTranslationsMap | keyvalue" [value]="badgePosition.key">
{{ badgePosition.value | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</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()">
{{ 'admin.mobile-app.label' | translate }}
</mat-slide-toggle>
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="qrCodeLabel" maxlength="50" placeholder="{{'admin.mobile-app.set' | translate}}">
</mat-form-field>
</div>
</div>
</div>
</section>

19
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.scss

@ -0,0 +1,19 @@
/**
* 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;
}

156
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.ts

@ -0,0 +1,156 @@
///
/// 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.
///
import { Component } from "@angular/core";
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { WidgetSettings, WidgetSettingsComponent } from "@shared/models/widget.models";
import { AppState } from '@core/core.state';
import { Store } from "@ngrx/store";
import { badgePositionTranslationsMap, badgeStyleTranslationsMap } from '@shared/models/mobile-app.models';
import { mobileAppQrCodeWidgetDefaultSettings } from '@home/components/widget/lib/cards/mobile-app-qr-code-widge.models';
@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']
})
export class MobileAppQrCodeWidgetSettingsComponent extends WidgetSettingsComponent {
mobileAppQRCodeWidgetSettingsForm: UntypedFormGroup;
badgePositionTranslationsMap = badgePositionTranslationsMap;
badgeStyleTranslationsMap = badgeStyleTranslationsMap;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
}
protected settingsForm(): UntypedFormGroup {
return this.mobileAppQRCodeWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {...mobileAppQrCodeWidgetDefaultSettings};
}
protected onSettingsSet(settings: WidgetSettings) {
this.mobileAppQRCodeWidgetSettingsForm = this.fb.group({
useDefaultApp: [settings.useDefaultApp, []],
androidConfig: this.fb.group({
enabled: [settings.androidConfig.enabled, []],
appPackage: [settings.androidConfig.appPackage, []],
sha256CertFingerprints: [settings.androidConfig.sha256CertFingerprints, []]
}),
iosConfig: this.fb.group({
enabled: [settings.iosConfig.enabled, []],
appId: [settings.iosConfig.appId, []]
}),
qrCodeConfig: this.fb.group({
badgeEnabled: [settings.qrCodeConfig.badgeEnabled, []],
badgeStyle: [{value: settings.qrCodeConfig.badgeStyle, disabled: true}, []],
badgePosition: [{value: settings.qrCodeConfig.badgePosition, disabled: true}, []],
qrCodeLabelEnabled: [settings.qrCodeConfig.qrCodeLabelEnabled, []],
qrCodeLabel: [settings.qrCodeConfig.qrCodeLabel, []]
})
});
}
protected validatorTriggers(): string[] {
return ['useDefaultApp', 'androidConfig.enabled', 'iosConfig.enabled', 'qrCodeConfig.badgeEnabled', 'qrCodeConfig.qrCodeLabelEnabled'];
}
protected updateValidators(emitEvent: boolean) {
const useDefaultApp = this.mobileAppQRCodeWidgetSettingsForm.get('useDefaultApp').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').clearValidators();
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').clearValidators();
this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').clearValidators();
} else {
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').setValidators([Validators.required]);
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').setValidators([Validators.required]);
this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').setValidators([Validators.required]);
}
if (androidEnabled) {
if (!useDefaultApp) {
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').setValidators([Validators.required]);
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').setValidators([Validators.required]);
}
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').enable({emitEvent: false});
if (badgeEnabled) {
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeStyle').enable();
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').enable();
}
} else {
if (!useDefaultApp) {
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').clearValidators();
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').clearValidators();
}
if (!iosEnabled) {
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').disable({emitEvent: false});
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeStyle').disable();
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').disable();
}
}
if (iosEnabled) {
if (!useDefaultApp) {
this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').setValidators([Validators.required]);
}
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').enable({emitEvent: false});
if (badgeEnabled) {
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeStyle').enable();
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').enable();
}
} else {
if (!useDefaultApp) {
this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').clearValidators();
}
if (!androidEnabled) {
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').disable({emitEvent: false});
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeStyle').disable();
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').disable();
}
}
if (badgeEnabled) {
if (androidEnabled || iosEnabled) {
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeStyle').enable();
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').enable();
}
} else {
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeStyle').disable();
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').disable();
}
if (qrCodeLabelEnabled) {
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabel').enable();
} else {
this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabel').disable();
}
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.appPackage').updateValueAndValidity({emitEvent});
this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.sha256CertFingerprints').updateValueAndValidity({emitEvent});
this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.appId').updateValueAndValidity({emitEvent});
}
}

6
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts

@ -354,10 +354,14 @@ import {
import {
RadarChartWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/radar-chart-widget-settings.component';
import {
MobileAppQrCodeWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component';
@NgModule({
declarations: [
QrCodeWidgetSettingsComponent,
MobileAppQrCodeWidgetSettingsComponent,
TimeseriesTableWidgetSettingsComponent,
TimeseriesTableKeySettingsComponent,
TimeseriesTableLatestKeySettingsComponent,
@ -490,6 +494,7 @@ import {
],
exports: [
QrCodeWidgetSettingsComponent,
MobileAppQrCodeWidgetSettingsComponent,
TimeseriesTableWidgetSettingsComponent,
TimeseriesTableKeySettingsComponent,
TimeseriesTableLatestKeySettingsComponent,
@ -620,6 +625,7 @@ export class WidgetSettingsModule {
export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsComponent>} = {
'tb-qrcode-widget-settings': QrCodeWidgetSettingsComponent,
'tb-mobile-app-qr-code-widget-settings': MobileAppQrCodeWidgetSettingsComponent,
'tb-timeseries-table-widget-settings': TimeseriesTableWidgetSettingsComponent,
'tb-timeseries-table-key-settings': TimeseriesTableKeySettingsComponent,
'tb-timeseries-table-latest-key-settings': TimeseriesTableLatestKeySettingsComponent,

6
ui-ngx/src/app/modules/home/pages/admin/mobile-app-settings.component.ts

@ -27,7 +27,7 @@ import {
badgePositionTranslationsMap,
BadgeStyle,
badgeStyleTranslationsMap,
MobileAppSettings
MobileAppQRCodeSettings
} from '@shared/models/mobile-app.models';
@Component({
@ -39,7 +39,7 @@ export class MobileAppSettingsComponent extends PageComponent implements HasConf
mobileAppSettingsForm: FormGroup;
mobileAppSettings: MobileAppSettings;
mobileAppSettings: MobileAppQRCodeSettings;
private readonly destroy$ = new Subject<void>();
@ -179,7 +179,7 @@ export class MobileAppSettingsComponent extends PageComponent implements HasConf
});
}
private processMobileAppSettings(mobileAppSettings: MobileAppSettings): void {
private processMobileAppSettings(mobileAppSettings: MobileAppQRCodeSettings): void {
this.mobileAppSettings = {...mobileAppSettings};
this.mobileAppSettingsForm.reset(this.mobileAppSettings);
}

2
ui-ngx/src/app/shared/models/mobile-app.models.ts

@ -16,7 +16,7 @@
import { TenantId } from '@shared/models/id/tenant-id';
export interface MobileAppSettings {
export interface MobileAppQRCodeSettings {
tenantId: TenantId;
useDefaultApp: boolean;
androidConfig: AndroidConfig;

12
ui-ngx/src/assets/dashboard/tenant_admin_home_page.json

@ -1145,7 +1145,7 @@
"id": "8e71a398-caf5-540d-cec5-6e5dc264343e"
},
"b9d704a2-f579-dbff-f123-f953d92081fd": {
"typeFullFqn": "system.home_page_widgets.mobile_app_qr_code",
"typeFullFqn": "system.home_page_widgets.home_mobile_app_qr_code",
"type": "static",
"sizeX": 6,
"sizeY": 3,
@ -1176,12 +1176,10 @@
"backgroundColor": "rgb(255, 255, 255)",
"color": "rgba(0, 0, 0, 0.87)",
"padding": "8px",
"settings": {
"cardHtml": "<div class='card'>HTML code here</div>",
"cardCss": ".card {\n font-weight: bold;\n font-size: 32px;\n color: #999;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n}"
},
"title": "HTML Card",
"dropShadow": false
"settings": {},
"title": "Mobile app QR code",
"dropShadow": false,
"enableFullscreen": false
},
"row": 0,
"col": 0,

3
ui-ngx/src/form.scss

@ -290,9 +290,6 @@
&.shrink {
flex: 0;
}
&.no-gap {
gap: 0;
}
}
.tb-form-panel, .tb-form-row {

Loading…
Cancel
Save