UI: Add mobile qr code settings and fixed minor bug in mobile center

This commit is contained in:
Vladyslav_Prykhodko 2024-11-01 11:53:26 +02:00
parent 1f784ce01c
commit 40de798cd6
19 changed files with 165 additions and 280 deletions

View File

@ -180,6 +180,9 @@ export class EntityService {
case EntityType.MOBILE_APP: case EntityType.MOBILE_APP:
observable = this.mobileAppService.getMobileAppInfoById(entityId, config); observable = this.mobileAppService.getMobileAppInfoById(entityId, config);
break; break;
case EntityType.MOBILE_APP_BUNDLE:
observable = this.mobileAppService.getMobileAppBundleInfoById(entityId, config);
break;
} }
return observable; return observable;
} }
@ -473,6 +476,10 @@ export class EntityService {
pageLink.sortOrder.property = 'pkgName'; pageLink.sortOrder.property = 'pkgName';
entitiesObservable = this.mobileAppService.getTenantMobileAppInfos(pageLink, subType as PlatformType, config); entitiesObservable = this.mobileAppService.getTenantMobileAppInfos(pageLink, subType as PlatformType, config);
break; break;
case EntityType.MOBILE_APP_BUNDLE:
pageLink.sortOrder.property = 'title';
entitiesObservable = this.mobileAppService.getTenantMobileAppBundleInfos(pageLink, config);
break;
} }
return entitiesObservable; return entitiesObservable;
} }

View File

@ -18,7 +18,7 @@ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { BaseData } from '@shared/models/base-data'; import { BaseData } from '@shared/models/base-data';
import { EntityId } from '@shared/models/id/entity-id'; import { EntityId } from '@shared/models/id/entity-id';
import { baseDetailsPageByEntityType, EntityType } from '@app/shared/public-api'; import { baseDetailsPageByEntityType, EntityType } from '@app/shared/public-api';
import { isObject } from '@core/utils'; import { isEqual, isObject } from '@core/utils';
@Component({ @Component({
selector: 'tb-entity-chips', selector: 'tb-entity-chips',
@ -53,10 +53,14 @@ export class EntityChipsComponent implements OnChanges {
entitiesList = [entitiesList]; entitiesList = [entitiesList];
} }
if (Array.isArray(entitiesList)) { if (Array.isArray(entitiesList)) {
this.subEntities = entitiesList; if (entitiesList.length) {
if (this.subEntities.length) { this.entityDetailsPrefixUrl = baseDetailsPageByEntityType.get(entitiesList[0].id.entityType as EntityType);
this.entityDetailsPrefixUrl = baseDetailsPageByEntityType.get(this.subEntities[0].id.entityType as EntityType);
} }
} else {
entitiesList = [];
}
if (!isEqual(entitiesList, this.subEntities)) {
this.subEntities = entitiesList;
} }
} }
} }

View File

@ -27,13 +27,13 @@
[class.row-reverse]="mobileAppSettings?.qrCodeConfig.badgePosition === badgePosition.LEFT"> [class.row-reverse]="mobileAppSettings?.qrCodeConfig.badgePosition === badgePosition.LEFT">
<div class="tb-qrcode" (click)="navigateByDeepLink($event)" [innerHTML]="qrCodeSVG | safe: 'html'"></div> <div class="tb-qrcode" (click)="navigateByDeepLink($event)" [innerHTML]="qrCodeSVG | safe: 'html'"></div>
<div class="tb-badges" [class.tb-no-interaction]="previewMode" <div class="tb-badges" [class.tb-no-interaction]="previewMode"
*ngIf="(mobileAppSettings?.iosConfig?.enabled || mobileAppSettings?.androidConfig?.enabled) && *ngIf="(mobileAppSettings?.iosEnabled || mobileAppSettings?.androidEnabled) &&
mobileAppSettings?.qrCodeConfig.badgeEnabled && showBadgeContainer"> mobileAppSettings?.qrCodeConfig.badgeEnabled && showBadgeContainer">
<a *ngIf="mobileAppSettings?.iosConfig?.enabled" [href]="appStoreLink" target="_blank"> <a *ngIf="mobileAppSettings?.iosEnabled" [href]="appStoreLink" target="_blank">
<img alt="{{ 'widgets.mobile-app-qr-code.download-on-the-app-store' | translate }}" <img alt="{{ 'widgets.mobile-app-qr-code.download-on-the-app-store' | translate }}"
src="assets/android-ios-stores-badges/ios_store_en_black_badge.svg"> src="assets/android-ios-stores-badges/ios_store_en_black_badge.svg">
</a> </a>
<a *ngIf="mobileAppSettings?.androidConfig?.enabled" [href]="googlePlayLink" target="_blank"> <a *ngIf="mobileAppSettings?.androidEnabled" [href]="googlePlayLink" target="_blank">
<img alt="{{ 'widgets.mobile-app-qr-code.get-it-on-google-play' | translate }}" <img alt="{{ 'widgets.mobile-app-qr-code.get-it-on-google-play' | translate }}"
src="assets/android-ios-stores-badges/android_store_en_black_badge.svg"> src="assets/android-ios-stores-badges/android_store_en_black_badge.svg">
</a> </a>

View File

@ -91,11 +91,8 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI
this.mobileAppService.getMobileAppSettings().subscribe((settings => { this.mobileAppService.getMobileAppSettings().subscribe((settings => {
this.mobileAppSettings = settings; this.mobileAppSettings = settings;
const useDefaultApp = this.mobileAppSettings.useDefaultApp; this.appStoreLink = this.mobileAppSettings.appStoreLink;
this.appStoreLink = useDefaultApp ? this.mobileAppSettings.defaultAppStoreLink : this.googlePlayLink = this.mobileAppSettings.googlePlayLink;
this.mobileAppSettings.iosConfig.storeLink;
this.googlePlayLink = useDefaultApp ? this.mobileAppSettings.defaultGooglePlayLink :
this.mobileAppSettings.androidConfig.storeLink;
if (isDefinedAndNotNull(this.ctx.settings.useSystemSettings) && !this.ctx.settings.useSystemSettings) { if (isDefinedAndNotNull(this.ctx.settings.useSystemSettings) && !this.ctx.settings.useSystemSettings) {
this.mobileAppSettings = mergeDeep(this.mobileAppSettings, this.ctx.settings); this.mobileAppSettings = mergeDeep(this.mobileAppSettings, this.ctx.settings);
@ -133,10 +130,8 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI
clearTimeout(this.deepLinkTTLTimeoutID); clearTimeout(this.deepLinkTTLTimeoutID);
} }
navigateByDeepLink($event) { navigateByDeepLink($event: Event) {
if ($event) { $event?.stopPropagation();
$event.stopPropagation();
}
if (this.ctx.isMobile) { if (this.ctx.isMobile) {
window.open(this.deepLink, '_blank'); window.open(this.deepLink, '_blank');
} }
@ -157,7 +152,7 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI
private updateQRCode(link: string) { private updateQRCode(link: string) {
import('qrcode').then((QRCode) => { import('qrcode').then((QRCode) => {
QRCode.toString(link, (err, svgElement) => { QRCode.toString(link, (_err, svgElement) => {
this.qrCodeSVG = svgElement; this.qrCodeSVG = svgElement;
this.cd.markForCheck(); this.cd.markForCheck();
}) })

View File

@ -21,18 +21,17 @@ import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module'; import { SharedModule } from '@shared/shared.module';
import { HomeComponentsModule } from '@home/components/home-components.module'; import { HomeComponentsModule } from '@home/components/home-components.module';
import { ApplicationsRoutingModule } from '@home/pages/mobile/applications/applications-routing.module'; import { ApplicationsRoutingModule } from '@home/pages/mobile/applications/applications-routing.module';
import { ReleaseNotesPanelComponent } from '@home/pages/mobile/applications/release-notes-panel.component';
import { MobileAppDialogComponent } from '@home/pages/mobile/applications/mobile-app-dialog.component'; import { MobileAppDialogComponent } from '@home/pages/mobile/applications/mobile-app-dialog.component';
import { RemoveAppDialogComponent } from '@home/pages/mobile/applications/remove-app-dialog.component'; import { RemoveAppDialogComponent } from '@home/pages/mobile/applications/remove-app-dialog.component';
import { import {
MobileAppConfigurationDialogComponent MobileAppConfigurationDialogComponent
} from '@home/pages/mobile/applications/mobile-app-configuration-dialog.component'; } from '@home/pages/mobile/applications/mobile-app-configuration-dialog.component';
import { CommMobileModule } from '@home/pages/mobile/common/comm-mobile.module';
@NgModule({ @NgModule({
declarations: [ declarations: [
MobileAppComponent, MobileAppComponent,
MobileAppTableHeaderComponent, MobileAppTableHeaderComponent,
ReleaseNotesPanelComponent,
MobileAppDialogComponent, MobileAppDialogComponent,
RemoveAppDialogComponent, RemoveAppDialogComponent,
MobileAppConfigurationDialogComponent, MobileAppConfigurationDialogComponent,
@ -41,6 +40,7 @@ import {
CommonModule, CommonModule,
SharedModule, SharedModule,
HomeComponentsModule, HomeComponentsModule,
CommMobileModule,
ApplicationsRoutingModule, ApplicationsRoutingModule,
], ],
exports: [ exports: [

View File

@ -28,7 +28,7 @@ import { PlatformType, platformTypeTranslations } from '@shared/models/oauth2.mo
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatButton } from '@angular/material/button'; import { MatButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service'; import { TbPopoverService } from '@shared/components/popover.service';
import { ReleaseNotesPanelComponent } from '@home/pages/mobile/applications/release-notes-panel.component'; import { EditorPanelComponent } from '@home/pages/mobile/common/editor-panel.component';
@Component({ @Component({
selector: 'tb-mobile-app', selector: 'tb-mobile-app',
@ -155,18 +155,18 @@ export class MobileAppComponent extends EntityComponent<MobileApp> {
} else { } else {
const ctx: any = { const ctx: any = {
disabled: !(this.isAdd || this.isEdit), disabled: !(this.isAdd || this.isEdit),
isLatest: isLatest, title: isLatest ? 'mobile.latest-version-release-notes' : 'mobile.min-version-release-notes',
releaseNotes: isLatest content: isLatest
? this.entityForm.get('versionInfo.latestVersionReleaseNotes').value ? this.entityForm.get('versionInfo.latestVersionReleaseNotes').value
: this.entityForm.get('versionInfo.minVersionReleaseNotes').value : this.entityForm.get('versionInfo.minVersionReleaseNotes').value
}; };
const releaseNotesPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, const releaseNotesPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, ReleaseNotesPanelComponent, ['leftOnly', 'leftBottomOnly', 'leftTopOnly'], true, null, this.viewContainerRef, EditorPanelComponent, ['leftOnly', 'leftBottomOnly', 'leftTopOnly'], true, null,
ctx, ctx,
{}, {},
{}, {}, false, () => {}, {padding: '16px 24px'}); {}, {}, false, () => {}, {padding: '16px 24px'});
releaseNotesPanelPopover.tbComponentRef.instance.popover = releaseNotesPanelPopover; releaseNotesPanelPopover.tbComponentRef.instance.popover = releaseNotesPanelPopover;
releaseNotesPanelPopover.tbComponentRef.instance.releaseNotesApplied.subscribe((releaseNotes) => { releaseNotesPanelPopover.tbComponentRef.instance.editorContentApplied.subscribe((releaseNotes) => {
releaseNotesPanelPopover.hide(); releaseNotesPanelPopover.hide();
if (isLatest) { if (isLatest) {
this.entityForm.get('versionInfo.latestVersionReleaseNotes').setValue(releaseNotes); this.entityForm.get('versionInfo.latestVersionReleaseNotes').setValue(releaseNotes);

View File

@ -53,7 +53,7 @@
(click)="resetToDefault()"> (click)="resetToDefault()">
<tb-icon color="primary" matButtonIcon>mdi:broom</tb-icon> <tb-icon color="primary" matButtonIcon>mdi:broom</tb-icon>
</button> </button>
<div tb-help="mobileLayout"></div> <!-- <div tb-help="mobileLayout"></div>-->
</div> </div>
<div #mobilePagesContainer class="tb-drop-list tb-mobile-items-container" <div #mobilePagesContainer class="tb-drop-list tb-mobile-items-container"
cdkDropList cdkDropList

View File

@ -18,7 +18,7 @@
<mat-toolbar color="primary"> <mat-toolbar color="primary">
<h2>{{ dialogTitle | translate }}</h2> <h2>{{ dialogTitle | translate }}</h2>
<span class="flex-1"></span> <span class="flex-1"></span>
<div tb-help="ruleNotifications"></div> <div tb-help="mobileBundle"></div>
<button mat-icon-button <button mat-icon-button
(click)="cancel()" (click)="cancel()"
type="button"> type="button">
@ -49,7 +49,7 @@
allowCreateNew allowCreateNew
useFullEntityId useFullEntityId
appearance="outline" appearance="outline"
labelText="{{ 'mobile.android-application' | translate }}" labelText="mobile.android-application"
[entityType]="entityType.MOBILE_APP" [entityType]="entityType.MOBILE_APP"
[entitySubtype]="platformType.ANDROID" [entitySubtype]="platformType.ANDROID"
(createNew)="createApplication('androidAppId', platformType.ANDROID)" (createNew)="createApplication('androidAppId', platformType.ANDROID)"
@ -59,7 +59,7 @@
allowCreateNew allowCreateNew
useFullEntityId useFullEntityId
appearance="outline" appearance="outline"
labelText="{{ 'mobile.ios-application' | translate }}" labelText="mobile.ios-application"
[entityType]="entityType.MOBILE_APP" [entityType]="entityType.MOBILE_APP"
[entitySubtype]="platformType.IOS" [entitySubtype]="platformType.IOS"
(createNew)="createApplication('iosAppId', platformType.IOS)" (createNew)="createApplication('iosAppId', platformType.IOS)"

View File

@ -18,7 +18,7 @@
<div class="flex flex-full items-center justify-between"> <div class="flex flex-full items-center justify-between">
<section class="flex items-center xs:!hidden"> <section class="flex items-center xs:!hidden">
<div tbTruncateWithTooltip translate>mobile.bundles</div> <div tbTruncateWithTooltip translate>mobile.bundles</div>
<div tb-help="oauth2Settings"></div> <div tb-help="mobileBundle"></div>
</section> </section>
<button mat-stroked-button color="primary" (click)="createBundle($event)"> <button mat-stroked-button color="primary" (click)="createBundle($event)">
<mat-icon>add</mat-icon>{{ 'mobile.add-bundle' | translate }} <mat-icon>add</mat-icon>{{ 'mobile.add-bundle' | translate }}

View File

@ -0,0 +1,34 @@
///
/// 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 { NgModule } from '@angular/core';
import { EditorPanelComponent } from '@home/pages/mobile/common/editor-panel.component';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
@NgModule({
declarations: [
EditorPanelComponent
],
imports: [
CommonModule,
SharedModule
],
exports: [
EditorPanelComponent
]
})
export class CommMobileModule {}

View File

@ -15,10 +15,10 @@
limitations under the License. limitations under the License.
--> -->
<div class="tb-release-notes-panel"> <div class="tb-editor-panel">
<div class="tb-release-notes-title">{{ title | translate }}</div> <div class="tb-editor-title">{{ title | translate }}</div>
<editor [init]="tinyMceOptions" [formControl]="releaseNotesControl"></editor> <editor class="tb-editor" [init]="tinyMceOptions" [formControl]="editorControl"></editor>
<div class="tb-release-notes-panel-buttons"> <div class="tb-editor-buttons">
<button mat-button <button mat-button
color="primary" color="primary"
type="button" type="button"
@ -29,7 +29,7 @@
color="primary" color="primary"
type="button" type="button"
(click)="apply()" (click)="apply()"
[disabled]="releaseNotesControl.invalid || !releaseNotesControl.dirty"> [disabled]="editorControl.invalid || !editorControl.dirty">
{{ 'action.apply' | translate }} {{ 'action.apply' | translate }}
</button> </button>
</div> </div>

View File

@ -15,7 +15,7 @@
*/ */
@import '../../../../../../scss/constants'; @import '../../../../../../scss/constants';
.tb-release-notes-panel { .tb-editor-panel {
width: 600px; width: 600px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -23,14 +23,17 @@
@media #{$mat-lt-md} { @media #{$mat-lt-md} {
width: 90vw; width: 90vw;
} }
.tb-release-notes-title { .tb-editor-title {
font-size: 16px; font-size: 16px;
font-weight: 500; font-weight: 500;
line-height: 24px; line-height: 24px;
letter-spacing: 0.25px; letter-spacing: 0.25px;
color: rgba(0, 0, 0, 0.87); color: rgba(0, 0, 0, 0.87);
} }
.tb-release-notes-panel-buttons { .tb-editor {
height: 400px;
}
.tb-editor-buttons {
height: 40px; height: 40px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -20,30 +20,28 @@ import { TbPopoverComponent } from '@shared/components/popover.component';
@Component({ @Component({
selector: 'tb-release-notes-panel', selector: 'tb-release-notes-panel',
templateUrl: './release-notes-panel.component.html', templateUrl: './editor-panel.component.html',
styleUrls: ['./release-notes-panel.component.scss'], styleUrls: ['./editor-panel.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ReleaseNotesPanelComponent implements OnInit { export class EditorPanelComponent implements OnInit {
@Input() @Input()
disabled: boolean; disabled: boolean;
@Input() @Input()
releaseNotes: string; content: string;
@Input() @Input()
isLatest: boolean;
@Input()
popover: TbPopoverComponent<ReleaseNotesPanelComponent>;
@Output()
releaseNotesApplied = new EventEmitter<string>();
title: string; title: string;
releaseNotesControl: FormControl<string>; @Input()
popover: TbPopoverComponent<EditorPanelComponent>;
@Output()
editorContentApplied = new EventEmitter<string>();
editorControl: FormControl<string>;
tinyMceOptions: Record<string, any> = { tinyMceOptions: Record<string, any> = {
base_url: '/assets/tinymce', base_url: '/assets/tinymce',
@ -63,10 +61,9 @@ export class ReleaseNotesPanelComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
this.releaseNotesControl = this.fb.control(this.releaseNotes); this.editorControl = this.fb.control(this.content);
this.title = this.isLatest ? 'mobile.latest-version-release-notes' : 'mobile.min-version-release-notes';
if (this.disabled) { if (this.disabled) {
this.releaseNotesControl.disable({emitEvent: false}); this.editorControl.disable({emitEvent: false});
} }
} }
@ -75,8 +72,8 @@ export class ReleaseNotesPanelComponent implements OnInit {
} }
apply() { apply() {
if (this.releaseNotesControl.valid) { if (this.editorControl.valid) {
this.releaseNotesApplied.emit(this.releaseNotesControl.value); this.editorContentApplied.emit(this.editorControl.value);
} }
} }
} }

View File

@ -16,10 +16,11 @@
--> -->
<mat-card appearance="outlined" class="settings-card"> <mat-card appearance="outlined" class="settings-card">
<mat-card-header> <mat-card-header class="items-center">
<mat-card-title> <mat-card-title>
<span class="mat-headline-5" translate>admin.mobile-app.mobile-app-qr-code-widget-settings</span> <span class="mat-headline-5" translate>admin.mobile-app.mobile-app-qr-code-widget-settings</span>
</mat-card-title> </mat-card-title>
<div tb-help="mobileQrCode"></div>
</mat-card-header> </mat-card-header>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar> </mat-progress-bar>
@ -51,110 +52,16 @@
formControlName="mobileAppBundleId"> formControlName="mobileAppBundleId">
</tb-entity-autocomplete> </tb-entity-autocomplete>
</div> </div>
<!-- <div class="tb-form-panel stroked no-padding no-gap" formGroupName="androidConfig">--> <div class="tb-form-row stroked no-padding-bottom">
<!-- <div class="tb-form-row no-border no-padding-bottom">--> <mat-slide-toggle class="mat-slide" formControlName="androidEnabled" (click)="$event.stopPropagation()">
<!-- <mat-slide-toggle class="mat-slide" formControlName="enabled" (click)="$event.stopPropagation()">--> {{ 'admin.mobile-app.android' | translate }}
<!-- {{ 'admin.mobile-app.android' | translate }}--> </mat-slide-toggle>
<!-- </mat-slide-toggle>--> </div>
<!-- </div>--> <div class="tb-form-row stroked no-padding-bottom">
<!-- <div class="tb-form-panel no-border no-padding-top"--> <mat-slide-toggle class="mat-slide" formControlName="iosEnabled" (click)="$event.stopPropagation()">
<!-- *ngIf="!mobileAppSettingsForm.get('useDefaultApp').value && mobileAppSettingsForm.get('androidConfig.enabled').value">--> {{ 'admin.mobile-app.ios' | translate }}
<!-- <div class="tb-form-row column-xs">--> </mat-slide-toggle>
<!-- <div class="fixed-title-width-230">{{ 'admin.mobile-app.app-package-name' | translate }}</div>--> </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="mobileAppSettingsForm.get('androidConfig.appPackage').hasError('required')-->
<!-- && mobileAppSettingsForm.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="!mobileAppSettingsForm.get('useDefaultApp').value && mobileAppSettingsForm.get('androidConfig.enabled').value">-->
<!-- <div class="tb-form-row column-xs">-->
<!-- <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-->
<!-- matTooltipPosition="above"-->
<!-- matTooltipClass="tb-error-tooltip"-->
<!-- [matTooltip]="'admin.mobile-app.sha256-certificate-fingerprints-required' | translate"-->
<!-- *ngIf="mobileAppSettingsForm.get('androidConfig.sha256CertFingerprints').hasError('required')-->
<!-- && mobileAppSettingsForm.get('androidConfig.sha256CertFingerprints').touched"-->
<!-- class="tb-error">-->
<!-- warning-->
<!-- </mat-icon>-->
<!-- </mat-form-field>-->
<!-- </div>-->
<!-- </div>-->
<!-- <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="fixed-title-width-230">{{ 'admin.mobile-app.google-play-link' | translate }}</div>-->
<!-- <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">-->
<!-- <input matInput formControlName="storeLink" placeholder="{{'admin.mobile-app.set' | translate}}">-->
<!-- <mat-icon matSuffix-->
<!-- matTooltipPosition="above"-->
<!-- matTooltipClass="tb-error-tooltip"-->
<!-- [matTooltip]="'admin.mobile-app.google-play-link-required' | translate"-->
<!-- *ngIf="mobileAppSettingsForm.get('androidConfig.storeLink').hasError('required')-->
<!-- && mobileAppSettingsForm.get('androidConfig.storeLink').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="!mobileAppSettingsForm.get('useDefaultApp').value && mobileAppSettingsForm.get('iosConfig.enabled').value">-->
<!-- <div class="tb-form-row column-xs">-->
<!-- <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-->
<!-- matTooltipPosition="above"-->
<!-- matTooltipClass="tb-error-tooltip"-->
<!-- [matTooltip]="'admin.mobile-app.app-id-required' | translate"-->
<!-- *ngIf="mobileAppSettingsForm.get('iosConfig.appId').hasError('required')-->
<!-- && mobileAppSettingsForm.get('iosConfig.appId').touched"-->
<!-- class="tb-error">-->
<!-- warning-->
<!-- </mat-icon>-->
<!-- </mat-form-field>-->
<!-- </div>-->
<!-- </div>-->
<!-- <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="fixed-title-width-230">{{ 'admin.mobile-app.app-store-link' | translate }}</div>-->
<!-- <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">-->
<!-- <input matInput formControlName="storeLink" placeholder="{{'admin.mobile-app.set' | translate}}">-->
<!-- <mat-icon matSuffix-->
<!-- matTooltipPosition="above"-->
<!-- matTooltipClass="tb-error-tooltip"-->
<!-- [matTooltip]="'admin.mobile-app.app-store-link-required' | translate"-->
<!-- *ngIf="mobileAppSettingsForm.get('iosConfig.storeLink').hasError('required')-->
<!-- && mobileAppSettingsForm.get('iosConfig.storeLink').touched"-->
<!-- class="tb-error">-->
<!-- warning-->
<!-- </mat-icon>-->
<!-- </mat-form-field>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div> </div>
<div class="tb-form-panel" formGroupName="qrCodeConfig" *ngIf="!mobileAppSettingsForm.get('useSystemSettings').value"> <div class="tb-form-panel" formGroupName="qrCodeConfig" *ngIf="!mobileAppSettingsForm.get('useSystemSettings').value">
<div class="tb-form-row column-xs no-border no-padding space-between"> <div class="tb-form-row column-xs no-border no-padding space-between">

View File

@ -35,70 +35,68 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
}) })
export class MobileQrCodeWidgetSettingsComponent extends PageComponent implements HasConfirmForm { export class MobileQrCodeWidgetSettingsComponent extends PageComponent implements HasConfirmForm {
mobileAppSettingsForm: FormGroup;
mobileAppSettings: QrCodeSettings;
readonly badgePositionTranslationsMap = badgePositionTranslationsMap; readonly badgePositionTranslationsMap = badgePositionTranslationsMap;
readonly entityType = EntityType; readonly entityType = EntityType;
mobileAppSettingsForm = this.fb.group({
useSystemSettings: [false],
useDefaultApp: [true],
mobileAppBundleId: [{value: null, disabled: true}, Validators.required],
androidEnabled: [true],
iosEnabled: [true],
qrCodeConfig: this.fb.group({
showOnHomePage: [true],
badgeEnabled: [true],
badgePosition: [BadgePosition.RIGHT],
qrCodeLabelEnabled: [true],
qrCodeLabel: ['', [Validators.required, Validators.maxLength(50)]]
})
});
private authUser = getCurrentAuthUser(this.store); private authUser = getCurrentAuthUser(this.store);
private mobileAppSettings: QrCodeSettings;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private mobileAppService: MobileApplicationService, private mobileAppService: MobileApplicationService,
private fb: FormBuilder) { private fb: FormBuilder) {
super(store); super(store);
this.buildMobileAppSettingsForm();
this.mobileAppService.getMobileAppSettings() this.mobileAppService.getMobileAppSettings()
.subscribe(settings => this.processMobileAppSettings(settings)); .subscribe(settings => this.processMobileAppSettings(settings));
if (this.isTenantAdmin()) { if (this.isTenantAdmin()) {
// this.mobileAppSettingsForm.get('useSystemSettings').valueChanges.pipe( this.mobileAppSettingsForm.get('useSystemSettings').valueChanges.pipe(
// takeUntilDestroyed() takeUntilDestroyed()
// ).subscribe(value => { ).subscribe(value => {
// if (value) { if (value) {
// this.mobileAppSettingsForm.get('androidConfig.enabled').disable(); this.mobileAppSettingsForm.get('mobileAppBundleId').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('iosConfig.enabled').disable(); this.mobileAppSettingsForm.get('qrCodeConfig.qrCodeLabel').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('qrCodeConfig.qrCodeLabelEnabled').disable(); } else {
// } else { this.mobileAppSettingsForm.get('mobileAppBundleId').enable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.enabled').enable(); if (this.mobileAppSettingsForm.get('qrCodeConfig.qrCodeLabelEnabled').value &&
// this.mobileAppSettingsForm.get('iosConfig.enabled').enable(); this.mobileAppSettingsForm.get('qrCodeConfig.showOnHomePage').value) {
// this.mobileAppSettingsForm.get('qrCodeConfig.qrCodeLabelEnabled').enable(); this.mobileAppSettingsForm.get('qrCodeConfig.qrCodeLabel').enable({emitEvent: false});
// } }
// }); }
});
} }
this.mobileAppSettingsForm.get('useDefaultApp').valueChanges.pipe( this.mobileAppSettingsForm.get('useDefaultApp').valueChanges.pipe(
takeUntilDestroyed() takeUntilDestroyed()
).subscribe(value => { ).subscribe(value => {
if (value) { if (value) {
this.mobileAppSettingsForm.get('mobileAppBundleId').disable({emitEvent: false}); this.mobileAppSettingsForm.get('mobileAppBundleId').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.appPackage').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.sha256CertFingerprints').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.storeLink').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('iosConfig.appId').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('iosConfig.storeLink').disable({emitEvent: false});
} else { } else {
this.mobileAppSettingsForm.get('mobileAppBundleId').enable({emitEvent: false}); this.mobileAppSettingsForm.get('mobileAppBundleId').enable({emitEvent: false});
// if (this.mobileAppSettingsForm.get('androidConfig.enabled').value) {
// this.mobileAppSettingsForm.get('androidConfig.appPackage').enable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.sha256CertFingerprints').enable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.storeLink').enable({emitEvent: false});
// }
// if (this.mobileAppSettingsForm.get('iosConfig.enabled').value) {
// this.mobileAppSettingsForm.get('iosConfig.appId').enable({emitEvent: false});
// this.mobileAppSettingsForm.get('iosConfig.storeLink').enable({emitEvent: false});
// }
} }
}); });
// this.mobileAppSettingsForm.get('androidConfig.enabled').valueChanges.pipe( this.mobileAppSettingsForm.get('androidEnabled').valueChanges.pipe(
// takeUntilDestroyed() takeUntilDestroyed()
// ).subscribe(value => { ).subscribe(() => {
// this.androidEnableChanged(value); this.mobileAppSettingsForm.get('qrCodeConfig.badgeEnabled').updateValueAndValidity({onlySelf: true});
// }); });
// this.mobileAppSettingsForm.get('iosConfig.enabled').valueChanges.pipe( this.mobileAppSettingsForm.get('iosEnabled').valueChanges.pipe(
// takeUntilDestroyed() takeUntilDestroyed()
// ).subscribe(value => { ).subscribe(() => {
// this.iosEnableChanged(value); this.mobileAppSettingsForm.get('qrCodeConfig.badgeEnabled').updateValueAndValidity({onlySelf: true});
// }); });
this.mobileAppSettingsForm.get('qrCodeConfig.showOnHomePage').valueChanges.pipe( this.mobileAppSettingsForm.get('qrCodeConfig.showOnHomePage').valueChanges.pipe(
takeUntilDestroyed() takeUntilDestroyed()
).subscribe(value => { ).subscribe(value => {
@ -115,13 +113,14 @@ export class MobileQrCodeWidgetSettingsComponent extends PageComponent implement
takeUntilDestroyed() takeUntilDestroyed()
).subscribe(value => { ).subscribe(value => {
if (value) { if (value) {
// if (this.mobileAppSettingsForm.get('androidConfig.enabled').value || this.mobileAppSettingsForm.get('iosConfig.enabled').value) { const formValue = this.mobileAppSettingsForm.getRawValue();
// this.mobileAppSettingsForm.get('qrCodeConfig.badgeEnabled').enable({emitEvent: false}); if (formValue.androidEnabled || formValue.iosEnabled) {
// this.mobileAppSettingsForm.get('qrCodeConfig.badgePosition').enable({emitEvent: false}); this.mobileAppSettingsForm.get('qrCodeConfig.badgeEnabled').enable({emitEvent: false});
// } else { this.mobileAppSettingsForm.get('qrCodeConfig.badgePosition').enable({emitEvent: false});
// this.mobileAppSettingsForm.get('qrCodeConfig.badgeEnabled').disable({emitEvent: false}); } else {
// this.mobileAppSettingsForm.get('qrCodeConfig.badgePosition').disable({emitEvent: false}); this.mobileAppSettingsForm.get('qrCodeConfig.badgeEnabled').disable({emitEvent: false});
// } this.mobileAppSettingsForm.get('qrCodeConfig.badgePosition').disable({emitEvent: false});
}
} else { } else {
this.mobileAppSettingsForm.get('qrCodeConfig.badgePosition').disable({emitEvent: false}); this.mobileAppSettingsForm.get('qrCodeConfig.badgePosition').disable({emitEvent: false});
} }
@ -141,32 +140,6 @@ export class MobileQrCodeWidgetSettingsComponent extends PageComponent implement
return this.authUser.authority === Authority.TENANT_ADMIN; return this.authUser.authority === Authority.TENANT_ADMIN;
} }
private buildMobileAppSettingsForm() {
this.mobileAppSettingsForm = this.fb.group({
useSystemSettings: [false],
useDefaultApp: [true],
mobileAppBundleId: [{value: null, disabled: true}, Validators.required],
// androidConfig: this.fb.group({
// enabled: [true],
// appPackage: [{value: '', disabled: true}, [Validators.required]],
// sha256CertFingerprints: [{value: '', disabled: true}, [Validators.required]],
// storeLink: ['', [Validators.required]]
// }),
// iosConfig: this.fb.group({
// enabled: [true],
// appId: [{value: '', disabled: true}, [Validators.required]],
// storeLink: ['', [Validators.required]]
// }),
qrCodeConfig: this.fb.group({
showOnHomePage: [true],
badgeEnabled: [true],
badgePosition: [BadgePosition.RIGHT],
qrCodeLabelEnabled: [true],
qrCodeLabel: ['', [Validators.required, Validators.maxLength(50)]]
})
});
}
private processMobileAppSettings(mobileAppSettings: QrCodeSettings): void { private processMobileAppSettings(mobileAppSettings: QrCodeSettings): void {
this.mobileAppSettings = {...mobileAppSettings}; this.mobileAppSettings = {...mobileAppSettings};
if (!this.isTenantAdmin()) { if (!this.isTenantAdmin()) {
@ -175,34 +148,6 @@ export class MobileQrCodeWidgetSettingsComponent extends PageComponent implement
this.mobileAppSettingsForm.reset(this.mobileAppSettings); this.mobileAppSettingsForm.reset(this.mobileAppSettings);
} }
// private androidEnableChanged(value: boolean): void {
// if (value) {
// if (!this.mobileAppSettingsForm.get('useDefaultApp').value) {
// this.mobileAppSettingsForm.get('androidConfig.appPackage').enable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.sha256CertFingerprints').enable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.storeLink').enable({emitEvent: false});
// }
// } else {
// this.mobileAppSettingsForm.get('androidConfig.appPackage').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.sha256CertFingerprints').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('androidConfig.storeLink').disable({emitEvent: false});
// }
// this.mobileAppSettingsForm.get('qrCodeConfig.badgeEnabled').updateValueAndValidity({onlySelf: true});
// }
//
// private iosEnableChanged(value: boolean): void {
// if (value) {
// if (!this.mobileAppSettingsForm.get('useDefaultApp').value) {
// this.mobileAppSettingsForm.get('iosConfig.appId').enable({emitEvent: false});
// this.mobileAppSettingsForm.get('iosConfig.storeLink').enable({emitEvent: false});
// }
// } else {
// this.mobileAppSettingsForm.get('iosConfig.appId').disable({emitEvent: false});
// this.mobileAppSettingsForm.get('iosConfig.storeLink').disable({emitEvent: false});
// }
// this.mobileAppSettingsForm.get('qrCodeConfig.badgeEnabled').updateValueAndValidity({onlySelf: true});
// }
save(): void { save(): void {
const showOnHomePagePreviousValue = this.mobileAppSettings.qrCodeConfig.showOnHomePage; const showOnHomePagePreviousValue = this.mobileAppSettings.qrCodeConfig.showOnHomePage;
this.mobileAppSettings = {...this.mobileAppSettings, ...this.mobileAppSettingsForm.getRawValue()}; this.mobileAppSettings = {...this.mobileAppSettings, ...this.mobileAppSettingsForm.getRawValue()};

View File

@ -187,7 +187,10 @@ export const HelpLinks = {
gatewayInstall: `${helpBaseUrl}/docs/iot-gateway/install/docker-installation`, gatewayInstall: `${helpBaseUrl}/docs/iot-gateway/install/docker-installation`,
scada: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/scada`, scada: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/scada`,
scadaSymbolDev: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/scada/symbols-dev-guide`, scadaSymbolDev: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/scada/symbols-dev-guide`,
scadaSymbolDevAnimation: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/scada/scada-symbols-dev-guide/#scadasymbolanimation` scadaSymbolDevAnimation: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/scada/scada-symbols-dev-guide/#scadasymbolanimation`,
mobileApplication: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/mobile-qr-code/`,
mobileBundle: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/mobile-qr-code/`,
mobileQrCode: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/mobile-qr-code/`,
} }
}; };
/* eslint-enable max-len */ /* eslint-enable max-len */

View File

@ -597,13 +597,13 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa
[ [
EntityType.MOBILE_APP, EntityType.MOBILE_APP,
{ {
helpLinkId: 'oauth2Settings' helpLinkId: 'mobileApplication'
} }
], ],
[ [
EntityType.MOBILE_APP_BUNDLE, EntityType.MOBILE_APP_BUNDLE,
{ {
helpLinkId: 'mobileBundles' helpLinkId: 'mobileBundle'
} }
] ]
] ]

View File

@ -25,11 +25,11 @@ export interface QrCodeSettings extends HasTenantId {
useSystemSettings: boolean; useSystemSettings: boolean;
useDefaultApp: boolean; useDefaultApp: boolean;
mobileAppBundleId: MobileAppBundleId mobileAppBundleId: MobileAppBundleId
androidConfig: any; //TODO: need remove androidEnabled: boolean;
iosConfig: any; //TODO: need remove iosEnabled: boolean;
qrCodeConfig: QRCodeConfig; qrCodeConfig: QRCodeConfig;
defaultGooglePlayLink: string; readonly googlePlayLink: string;
defaultAppStoreLink: string; readonly appStoreLink: string;
id: { id: {
id: string; id: string;
} }

View File

@ -464,17 +464,7 @@
"default": "Default", "default": "Default",
"custom": "Custom", "custom": "Custom",
"android": "Android", "android": "Android",
"app-package-name": "App package name",
"app-package-name-required": "App package name is required",
"sha256-certificate-fingerprints": "SHA256 certificate fingerprints",
"sha256-certificate-fingerprints-required": "SHA256 certificate fingerprints is required",
"ios": "iOS", "ios": "iOS",
"app-id": "App ID",
"app-id-required": "App ID is required",
"google-play-link": "Google Play link",
"google-play-link-required": "Google Play link is required",
"app-store-link": "App Store link",
"app-store-link-required": "App Store link is required",
"appearance": "Appearance", "appearance": "Appearance",
"appearance-on-home-page": "Appearance on Home page", "appearance-on-home-page": "Appearance on Home page",
"enabled": "Enabled", "enabled": "Enabled",