Add support mobile application title in predefined config

This commit is contained in:
Vladyslav_Prykhodko 2025-07-16 11:37:33 +03:00
parent 2e4ccac9f6
commit 5a848477fc
12 changed files with 35 additions and 5 deletions

View File

@ -35,3 +35,5 @@ DROP INDEX IF EXISTS idx_customer_external_id;
DROP INDEX IF EXISTS idx_widgets_bundle_external_id; DROP INDEX IF EXISTS idx_widgets_bundle_external_id;
-- DROP INDEXES THAT DUPLICATE UNIQUE CONSTRAINT END -- DROP INDEXES THAT DUPLICATE UNIQUE CONSTRAINT END
ALTER TABLE mobile_app ADD COLUMN IF NOT EXISTS pkg_title varchar(255);

View File

@ -43,6 +43,9 @@ public class MobileApp extends BaseData<MobileAppId> implements HasTenantId, Has
@NotBlank @NotBlank
@Length(fieldName = "pkgName") @Length(fieldName = "pkgName")
private String pkgName; private String pkgName;
@Schema(description = "Application package title")
@Length(fieldName = "pkgTitle")
private String pkgTitle;
@Schema(description = "Application secret. The length must be at least 16 characters", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "Application secret. The length must be at least 16 characters", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty @NotEmpty
@Length(fieldName = "appSecret", min = 16, max = 2048, message = "must be at least 16 and max 2048 characters") @Length(fieldName = "appSecret", min = 16, max = 2048, message = "must be at least 16 and max 2048 characters")
@ -72,6 +75,7 @@ public class MobileApp extends BaseData<MobileAppId> implements HasTenantId, Has
super(mobile); super(mobile);
this.tenantId = mobile.tenantId; this.tenantId = mobile.tenantId;
this.pkgName = mobile.pkgName; this.pkgName = mobile.pkgName;
this.pkgTitle = mobile.pkgTitle;
this.appSecret = mobile.appSecret; this.appSecret = mobile.appSecret;
this.platformType = mobile.platformType; this.platformType = mobile.platformType;
this.status = mobile.status; this.status = mobile.status;

View File

@ -457,6 +457,7 @@ public class ModelConstants {
*/ */
public static final String MOBILE_APP_TABLE_NAME = "mobile_app"; public static final String MOBILE_APP_TABLE_NAME = "mobile_app";
public static final String MOBILE_APP_PKG_NAME_PROPERTY = "pkg_name"; public static final String MOBILE_APP_PKG_NAME_PROPERTY = "pkg_name";
public static final String MOBILE_APP_PKG_TITLE_PROPERTY = "pkg_title";
public static final String MOBILE_APP_APP_SECRET_PROPERTY = "app_secret"; public static final String MOBILE_APP_APP_SECRET_PROPERTY = "app_secret";
public static final String MOBILE_APP_PLATFORM_TYPE_PROPERTY = "platform_type"; public static final String MOBILE_APP_PLATFORM_TYPE_PROPERTY = "platform_type";
public static final String MOBILE_APP_STATUS_PROPERTY = "status"; public static final String MOBILE_APP_STATUS_PROPERTY = "status";

View File

@ -53,6 +53,9 @@ public class MobileAppEntity extends BaseSqlEntity<MobileApp> {
@Column(name = ModelConstants.MOBILE_APP_PKG_NAME_PROPERTY) @Column(name = ModelConstants.MOBILE_APP_PKG_NAME_PROPERTY)
private String pkgName; private String pkgName;
@Column(name = ModelConstants.MOBILE_APP_PKG_TITLE_PROPERTY)
private String pkgTitle;
@Column(name = ModelConstants.MOBILE_APP_APP_SECRET_PROPERTY) @Column(name = ModelConstants.MOBILE_APP_APP_SECRET_PROPERTY)
private String appSecret; private String appSecret;
@ -82,6 +85,7 @@ public class MobileAppEntity extends BaseSqlEntity<MobileApp> {
this.tenantId = mobile.getTenantId().getId(); this.tenantId = mobile.getTenantId().getId();
} }
this.pkgName = mobile.getPkgName(); this.pkgName = mobile.getPkgName();
this.pkgTitle = mobile.getPkgTitle();
this.appSecret = mobile.getAppSecret(); this.appSecret = mobile.getAppSecret();
this.platformType = mobile.getPlatformType(); this.platformType = mobile.getPlatformType();
this.status = mobile.getStatus(); this.status = mobile.getStatus();
@ -98,6 +102,7 @@ public class MobileAppEntity extends BaseSqlEntity<MobileApp> {
} }
mobile.setCreatedTime(createdTime); mobile.setCreatedTime(createdTime);
mobile.setPkgName(pkgName); mobile.setPkgName(pkgName);
mobile.setPkgTitle(pkgTitle);
mobile.setAppSecret(appSecret); mobile.setAppSecret(appSecret);
mobile.setPlatformType(platformType); mobile.setPlatformType(platformType);
mobile.setStatus(status); mobile.setStatus(status);

View File

@ -626,6 +626,7 @@ CREATE TABLE IF NOT EXISTS mobile_app (
created_time bigint NOT NULL, created_time bigint NOT NULL,
tenant_id uuid, tenant_id uuid,
pkg_name varchar(255), pkg_name varchar(255),
pkg_title varchar(255),
app_secret varchar(2048), app_secret varchar(2048),
platform_type varchar(32), platform_type varchar(32),
status varchar(32), status varchar(32),

View File

@ -83,6 +83,7 @@ export class MobileAppTableConfigResolver {
onAction: (_$event, entity) => entity.pkgName, onAction: (_$event, entity) => entity.pkgName,
type: CellActionDescriptorType.COPY_BUTTON type: CellActionDescriptorType.COPY_BUTTON
}), }),
new EntityTableColumn<MobileApp>('pkgTitle', 'mobile.mobile-package-title', '20%'),
new EntityTableColumn<MobileApp>('appSecret', 'mobile.application-secret', '15%', new EntityTableColumn<MobileApp>('appSecret', 'mobile.application-secret', '15%',
(entity) => this.truncatePipe.transform(entity.appSecret, true, 10, '…'), () => ({}), (entity) => this.truncatePipe.transform(entity.appSecret, true, 10, '…'), () => ({}),
true, () => ({}), () => undefined, false, true, () => ({}), () => undefined, false,

View File

@ -38,6 +38,14 @@
{{ 'mobile.mobile-package-pattern' | translate }} {{ 'mobile.mobile-package-pattern' | translate }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-label translate>mobile.mobile-package-title</mat-label>
<input matInput formControlName="pkgTitle">
<mat-hint></mat-hint>
<mat-error *ngIf="entityForm.get('pkgName').hasError('maxlength')">
{{ 'mobile.mobile-package-title-max-length' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field appearance="outline" class="flex"> <mat-form-field appearance="outline" class="flex">
<mat-label translate>mobile.platform-type</mat-label> <mat-label translate>mobile.platform-type</mat-label>
<mat-select formControlName="platformType"> <mat-select formControlName="platformType">

View File

@ -63,9 +63,10 @@ export class MobileAppComponent extends EntityComponent<MobileApp> {
buildForm(entity: MobileApp): FormGroup { buildForm(entity: MobileApp): FormGroup {
const form = this.fb.group({ const form = this.fb.group({
pkgName: [entity?.pkgName ? entity.pkgName : '', [Validators.required, Validators.maxLength(255), pkgName: [entity?.pkgName ?? '', [Validators.required, Validators.maxLength(255),
Validators.pattern(/^[a-zA-Z][a-zA-Z\d_]*(?:\.[a-zA-Z][a-zA-Z\d_]*)+$/)]], Validators.pattern(/^[a-zA-Z][a-zA-Z\d_]*(?:\.[a-zA-Z][a-zA-Z\d_]*)+$/)]],
platformType: [entity?.platformType ? entity.platformType : PlatformType.ANDROID], pkgTitle: [entity?.pkgTitle ?? '', [Validators.maxLength(255)]],
platformType: [entity?.platformType ?? PlatformType.ANDROID],
appSecret: [entity?.appSecret ? entity.appSecret : btoa(randomAlphanumeric(64)), [Validators.required, this.base64Format]], appSecret: [entity?.appSecret ? entity.appSecret : btoa(randomAlphanumeric(64)), [Validators.required, this.base64Format]],
status: [entity?.status ? entity.status : MobileAppStatus.DRAFT], status: [entity?.status ? entity.status : MobileAppStatus.DRAFT],
versionInfo: this.fb.group({ versionInfo: this.fb.group({

View File

@ -28,6 +28,7 @@ export interface MobileAppConfigurationDialogData {
afterAdd: boolean; afterAdd: boolean;
androidApp: MobileApp; androidApp: MobileApp;
iosApp: MobileApp; iosApp: MobileApp;
bundleTitle: string;
} }
@Component({ @Component({
@ -37,13 +38,13 @@ export interface MobileAppConfigurationDialogData {
}) })
export class MobileAppConfigurationDialogComponent extends DialogComponent<MobileAppConfigurationDialogComponent> { export class MobileAppConfigurationDialogComponent extends DialogComponent<MobileAppConfigurationDialogComponent> {
private fileName = 'configs.json'; private fileName = 'configs';
notShowAgain = false; notShowAgain = false;
showDontShowAgain: boolean; showDontShowAgain: boolean;
gitRepositoryLink = 'git clone -b master https://github.com/thingsboard/flutter_thingsboard_app.git'; gitRepositoryLink = 'git clone -b master https://github.com/thingsboard/flutter_thingsboard_app.git';
flutterRunCommand = `flutter run --dart-define-from-file ${this.fileName}`; flutterRunCommand = `flutter run --dart-define-from-file ${this.fileName}.json`;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected router: Router, protected router: Router,
@ -74,11 +75,13 @@ export class MobileAppConfigurationDialogComponent extends DialogComponent<Mobil
}; };
if (!!this.data.androidApp) { if (!!this.data.androidApp) {
settings.androidApplicationId = this.data.androidApp.pkgName; settings.androidApplicationId = this.data.androidApp.pkgName;
settings.androidApplicationName = this.data.androidApp.pkgTitle ?? this.data.bundleTitle;
settings.thingsboardOAuth2CallbackUrlScheme = this.data.androidApp.pkgName + '.auth'; settings.thingsboardOAuth2CallbackUrlScheme = this.data.androidApp.pkgName + '.auth';
settings.thingsboardAndroidAppSecret = this.data.androidApp.appSecret; settings.thingsboardAndroidAppSecret = this.data.androidApp.appSecret;
} }
if (!!this.data.iosApp) { if (!!this.data.iosApp) {
settings.iosApplicationId = this.data.iosApp.pkgName; settings.iosApplicationId = this.data.iosApp.pkgName;
settings.iosApplicationName = this.data.iosApp.pkgTitle ?? this.data.bundleTitle;
settings.thingsboardIOSAppSecret = this.data.iosApp.appSecret; settings.thingsboardIOSAppSecret = this.data.iosApp.appSecret;
} }
this.importExportService.exportJson(settings, this.fileName); this.importExportService.exportJson(settings, this.fileName);

View File

@ -182,7 +182,8 @@ export class MobileBundleTableConfigResolver {
data: { data: {
afterAdd, afterAdd,
androidApp: data.androidApp, androidApp: data.androidApp,
iosApp: data.iosApp iosApp: data.iosApp,
bundleTitle: entity.title
} }
}).afterClosed() }).afterClosed()
.subscribe(); .subscribe();

View File

@ -85,6 +85,7 @@ export interface StoreInfo {
export interface MobileApp extends BaseData<MobileAppId>, HasTenantId { export interface MobileApp extends BaseData<MobileAppId>, HasTenantId {
pkgName: string; pkgName: string;
pkgTitle?: string;
appSecret: string; appSecret: string;
platformType: PlatformType; platformType: PlatformType;
status: MobileAppStatus; status: MobileAppStatus;

View File

@ -3767,6 +3767,8 @@
"mobile-package-max-length": "Application package should be less than 256", "mobile-package-max-length": "Application package should be less than 256",
"mobile-package-required": "Application package is required.", "mobile-package-required": "Application package is required.",
"mobile-package-pattern": "Application package invalid format", "mobile-package-pattern": "Application package invalid format",
"mobile-package-title": "Application title",
"mobile-package-title-max-length": "Application title should be less than 256",
"no-application": "No applications found", "no-application": "No applications found",
"no-bundles": "No bundles found", "no-bundles": "No bundles found",
"platform-type": "Platform type", "platform-type": "Platform type",