@sumaris-net/ngx-components 1.3.0 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4138,7 +4138,7 @@
4138
4138
  this.translate = translate;
4139
4139
  this.errorI18nKeys = Object.assign(Object.assign({}, SharedValidators.I18N_ERROR_KEYS), errorI18nKeys);
4140
4140
  }
4141
- FormErrorTranslator.prototype.translateErrors = function (control, opts) {
4141
+ FormErrorTranslator.prototype.translateFormErrors = function (control, opts) {
4142
4142
  var _this = this;
4143
4143
  if (!control || !control.invalid)
4144
4144
  return '';
@@ -4167,6 +4167,31 @@
4167
4167
  return res + (res.length ? separator : '') + formError;
4168
4168
  }, "");
4169
4169
  };
4170
+ FormErrorTranslator.prototype.translateErrors = function (errors, opts) {
4171
+ var _this = this;
4172
+ var separator = opts && opts.separator || ', ';
4173
+ return errors && Object.keys(errors).reduce(function (res, path) {
4174
+ var pathErrors = errors[path];
4175
+ // Should be a control map of errors
4176
+ if (pathErrors) {
4177
+ // Try to convert the control path
4178
+ var i18nPath = _this.translateControlPath(path, opts);
4179
+ // OK, we have a field name: use it
4180
+ var columnErrors = Object.keys(pathErrors).map(function (errorKey) { return _this.translateError(errorKey, pathErrors[errorKey]); });
4181
+ if (isEmptyArray(columnErrors))
4182
+ return res;
4183
+ // Add separator
4184
+ if (res.length)
4185
+ res += separator;
4186
+ return res + i18nPath + ": " + columnErrors.join(separator);
4187
+ }
4188
+ // Or try as global form error
4189
+ var formError = _this.translateError(path, pathErrors);
4190
+ if (isNil(formError))
4191
+ return res;
4192
+ return res + (res.length ? separator : '') + formError;
4193
+ }, "");
4194
+ };
4170
4195
  FormErrorTranslator.prototype.translateControlPath = function (path, opts) {
4171
4196
  if (opts === null || opts === void 0 ? void 0 : opts.controlPathTranslator) {
4172
4197
  return opts === null || opts === void 0 ? void 0 : opts.controlPathTranslator.translateControlPath(path);
@@ -4241,7 +4266,7 @@
4241
4266
  };
4242
4267
  FormErrorTranslatePipe.prototype._updateValue = function (form, opts, status) {
4243
4268
  if (status === 'INVALID' || form.invalid) {
4244
- this.value = this.adapter.translateErrors(form, opts);
4269
+ this.value = this.adapter.translateFormErrors(form, opts);
4245
4270
  this._ref.markForCheck();
4246
4271
  }
4247
4272
  else if (this.value !== undefined) {
@@ -16762,11 +16787,11 @@
16762
16787
  return !this.platform.is('mobile') || this.platform.is('mobileweb');
16763
16788
  };
16764
16789
  PlatformService.prototype.isAndroidCordova = function () {
16765
- return this._android && this._cordova;
16790
+ return this._android && this._cordova || false;
16766
16791
  };
16767
16792
  Object.defineProperty(PlatformService.prototype, "canDownload", {
16768
16793
  get: function () {
16769
- return this.isAndroidCordova && isNotNil(this.downloader);
16794
+ return this._android && this._cordova && isNotNil(this.downloader);
16770
16795
  },
16771
16796
  enumerable: false,
16772
16797
  configurable: true
@@ -16786,7 +16811,7 @@
16786
16811
  };
16787
16812
  PlatformService.prototype.ngOnStart = function () {
16788
16813
  return __awaiter(this, void 0, void 0, function () {
16789
- var now, forage, err_1;
16814
+ var now, storage, err_1;
16790
16815
  var _this = this;
16791
16816
  return __generator(this, function (_b) {
16792
16817
  switch (_b.label) {
@@ -16814,8 +16839,8 @@
16814
16839
  _b.sent();
16815
16840
  return [4 /*yield*/, this.storageReady()];
16816
16841
  case 3:
16817
- forage = _b.sent();
16818
- return [4 /*yield*/, this.migrateStorage(forage)];
16842
+ storage = _b.sent();
16843
+ return [4 /*yield*/, this.migrateStorage(storage)];
16819
16844
  case 4:
16820
16845
  _b.sent();
16821
16846
  // Start root services
@@ -17007,28 +17032,28 @@
17007
17032
  });
17008
17033
  });
17009
17034
  };
17010
- PlatformService.prototype.migrateStorage = function (forage) {
17035
+ PlatformService.prototype.migrateStorage = function (storage) {
17011
17036
  return __awaiter(this, void 0, void 0, function () {
17012
17037
  var canMigrate, oldForage, keys, now, toast_1, duration, err_2;
17013
17038
  return __generator(this, function (_b) {
17014
17039
  switch (_b.label) {
17015
17040
  case 0:
17016
- canMigrate = forage &&
17017
- ((forage.driver() === 'cordovaSQLiteDriver' && (forage.supports(forage.INDEXEDDB) || forage.supports(forage.WEBSQL))) ||
17018
- (forage.driver() === forage.WEBSQL && forage.supports(forage.INDEXEDDB)));
17041
+ canMigrate = storage &&
17042
+ ((storage.driver() === 'cordovaSQLiteDriver' && (storage.supports(storage.INDEXEDDB) || storage.supports(storage.WEBSQL))) ||
17043
+ (storage.driver() === storage.WEBSQL && storage.supports(storage.INDEXEDDB)));
17019
17044
  if (!canMigrate)
17020
17045
  return [2 /*return*/]; // Skip
17021
- oldForage = forage.createInstance({
17022
- name: forage.config().name,
17023
- storeName: forage.config().storeName,
17024
- driver: [forage.INDEXEDDB, forage.WEBSQL]
17046
+ oldForage = storage.createInstance({
17047
+ name: storage.config().name,
17048
+ storeName: storage.config().storeName,
17049
+ driver: [storage.INDEXEDDB, storage.WEBSQL]
17025
17050
  });
17026
17051
  return [4 /*yield*/, oldForage.keys()];
17027
17052
  case 1:
17028
17053
  keys = _b.sent();
17029
17054
  if (!isEmptyArray(keys)) return [3 /*break*/, 3];
17030
17055
  // Drop the old instance (not need anymore)
17031
- console.debug("[platform] Old storage is empty: dropping unused instance {name: '" + forage.config().name + "', driver: '" + oldForage.driver() + "'}");
17056
+ console.debug("[platform] Old storage is empty: dropping unused instance {name: '" + storage.config().name + "', driver: '" + oldForage.driver() + "'}");
17032
17057
  return [4 /*yield*/, oldForage.dropInstance()];
17033
17058
  case 2:
17034
17059
  _b.sent();
@@ -17043,7 +17068,7 @@
17043
17068
  _b.label = 5;
17044
17069
  case 5:
17045
17070
  _b.trys.push([5, 9, , 12]);
17046
- return [4 /*yield*/, StorageUtils.copy(oldForage, forage, { keys: keys, deleteAfterCopy: false })];
17071
+ return [4 /*yield*/, StorageUtils.copy(oldForage, storage, { keys: keys, deleteAfterCopy: false })];
17047
17072
  case 6:
17048
17073
  _b.sent();
17049
17074
  duration = Date.now() - now;
@@ -17056,7 +17081,7 @@
17056
17081
  _b.sent();
17057
17082
  console.info('[platform] Starting storage migration [OK]');
17058
17083
  // Drop the old instance
17059
- console.info("[platform] Drop old storage {name: '" + forage.config().name + "', driver: '" + oldForage.driver() + "'}");
17084
+ console.info("[platform] Drop old storage {name: '" + storage.config().name + "', driver: '" + oldForage.driver() + "'}");
17060
17085
  return [4 /*yield*/, oldForage.dropInstance()];
17061
17086
  case 8:
17062
17087
  _b.sent();
@@ -19578,7 +19603,7 @@
19578
19603
  AppForm.prototype.getFormError = function (form, opts) {
19579
19604
  if (!form || !this.errorTranslator)
19580
19605
  return undefined;
19581
- return this.errorTranslator.translateErrors(this.form, Object.assign({ controlPathTranslator: this }, opts));
19606
+ return this.errorTranslator.translateFormErrors(this.form, Object.assign({ controlPathTranslator: this }, opts));
19582
19607
  };
19583
19608
  AppForm.prototype.getI18nFieldName = function (path) {
19584
19609
  return (this.i18nFieldPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
@@ -20185,7 +20210,7 @@
20185
20210
  { type: i0.Component, args: [{
20186
20211
  moduleId: module.id.toString(),
20187
20212
  selector: 'app-page-home',
20188
- template: "<app-toolbar [canGoBack]=\"false\"\n visible-xs visible-sm visible-mobile>\n\n <!-- change locale button -->\n <ion-button slot=\"end\" *ngIf=\"currentLocaleCode; let code\"\n [matMenuTriggerFor]=\"localeMenu\">\n <ion-label class=\"ion-text-uppercase\">&nbsp;{{ code }}</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n</app-toolbar>\n\n<!-- change locale menu -->\n<mat-menu #localeMenu=\"matMenu\">\n <button *ngFor=\"let item of locales\"\n mat-menu-item\n (click)=\"changeLanguage(item.key)\">\n <ion-label>{{item.value}}</ion-label>\n </button>\n</mat-menu>\n\n<ion-content [ngStyle]=\"contentStyle\" no-padding-xs>\n\n <!-- loading spinner -->\n <div class=\"loading-page\" [class.cdk-visually-hidden]=\"!loading\">\n <div class=\"spinner\" *ngIf=\"loading && showSpinner\">\n <p>Loading...</p>\n <div class=\"sk-cube1 sk-cube\"></div>\n <div class=\"sk-cube2 sk-cube\"></div>\n <div class=\"sk-cube4 sk-cube\"></div>\n <div class=\"sk-cube3 sk-cube\"></div>\n </div>\n </div>\n\n <!-- Desktop: translucent top toolbar -->\n <div hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar translucent>\n <ion-buttons slot=\"start\">\n <ion-menu-toggle>\n <ion-button color=\"light\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n </ion-buttons>\n\n <ion-buttons slot=\"end\">\n <!-- change locale button -->\n <ion-button color=\"secondary\" fill=\"solid\"\n *ngIf=\"currentLocaleCode; let code\"\n [matMenuTriggerFor]=\"localeMenu\">\n <ion-label class=\"ion-text-uppercase\">&nbsp;{{ code }}</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </div>\n\n <!-- Install (and upgrade) card -->\n <app-install-upgrade-card [isLogin]=\"isLogin\"\n showInstallButton=\"true\">\n </app-install-upgrade-card>\n\n <!-- Welcome card -->\n <ion-card *ngIf=\"!loading\"\n class=\"main welcome ion-padding ion-text-center ion-align-self-center\"\n @fadeInAnimation>\n <ion-card-header>\n <ion-card-title class=\"ion-text-center\">\n <span *ngIf=\"isWeb\" [innerHTML]=\"'HOME.WELCOME_WEB'|translate: {appName: appName}\"></span>\n <span *ngIf=\"!isWeb\" [innerHTML]=\"'HOME.WELCOME_APP'|translate: {appName: appName}\"></span>\n </ion-card-title>\n <ion-card-subtitle [innerHTML]=\"description\">\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content class=\"ion-no-padding\">\n <ion-text color=\"primary\">\n <img class=\"logo\" *ngIf=\"logo\" src=\"{{ logo }}\">\n </ion-text>\n <!-- register help text -->\n <ion-text *ngIf=\"!isLogin && canRegister\">\n <br/>\n <span translate>HOME.REGISTER_HELP</span>\n </ion-text>\n </ion-card-content>\n\n <ion-footer class=\"ion-padding-top\">\n\n <!-- If NOT login -->\n <ng-container *ngIf=\"!isLogin; else loginButtons;\">\n\n <ion-button *ngIf=\"canRegister\" expand=\"block\" color=\"tertiary\" (click)=\"register()\">\n <span translate>HOME.BTN_REGISTER</span>\n </ion-button>\n <ion-button expand=\"block\" color=\"light\" [routerLink]=\"['/']\" (click)=\"login()\">\n <span translate>AUTH.BTN_LOGIN</span>\n </ion-button>\n\n </ng-container>\n\n <!-- If user login -->\n <ng-template #loginButtons>\n\n <!-- Feature buttons -->\n <ng-container *ngIf=\"$filteredButtons | async as buttons\">\n <ng-container *ngFor=\"let item of buttons\">\n <ion-button *ngIf=\"item.path\"\n expand=\"block\" color=\"tertiary\"\n [class]=\"item.cssClass\"\n [routerLink]=\"item.path\"\n routerDirection=\"root\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-text>{{'HOME.BTN_DATA_ENTRY'|translate: {name: (item.title | translate) } }}</ion-text>\n </ion-button>\n\n <!-- divider -->\n <div *ngIf=\"!item.path && !item.action\" [class]=\"item.cssClass\">\n <ion-label translate>{{item.title}}&nbsp;</ion-label>\n </div>\n </ng-container>\n\n <!--<p *ngIf=\"buttons.length\" class=\"visible-mobile\">&nbsp;</p>-->\n </ng-container>\n\n <ion-button expand=\"block\" color=\"secondary\" [routerLink]=\"['/account']\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" name=\"person-circle\"></ion-icon>\n <ion-text translate>HOME.BTN_MY_ACCOUNT</ion-text>\n </ion-button>\n\n <p hidden-xs hidden-sm hidden-mobile>\n <ion-text [innerHTML]=\"'HOME.NOT_THIS_ACCOUNT_QUESTION' | translate: {displayName: accountName }\"></ion-text>\n <br/>\n <ion-text>\n <a href=\"#\" (click)=\"logout($event)\">\n <span translate>HOME.BTN_DISCONNECT</span>\n </a>\n </ion-text>\n </p>\n\n\n </ng-template>\n\n </ion-footer>\n </ion-card>\n\n <!-- Page history -->\n <ion-grid *ngIf=\"!loading && isLogin && pageHistory.length; else bottomBanner\"\n class=\"history-container ion-align-self-center\">\n <ion-row>\n <ion-col size=\"12\" size-xl=\"\" *ngFor=\"let page of pageHistory; trackBy: getPagePath\"\n class=\"ion-text-center\">\n <ion-card class=\"ion-align-self-start ion-text-start\" @fadeInAnimation>\n <ion-card-header class=\"ion-no-padding\">\n <!-- top bar -->\n <ion-card-subtitle>\n <button type=\"button\" tabindex=\"-1\"\n (click)=\"settings.removePageHistory(page.path)\"\n mat-icon-button class=\"ion-float-start ion-no-margin\">\n <mat-icon>close</mat-icon>\n </button>\n <ion-label [innerHTML]=\"page.subtitle|translate\"></ion-label>\n <ion-text class=\"ion-float-end\" [title]=\"page.time|dateFormat:{time: true}\">\n <small><ion-icon name=\"time-outline\"></ion-icon>&nbsp;{{ page.time|dateFromNow }}</small>&nbsp;\n </ion-text>\n </ion-card-subtitle>\n\n <!-- main page -->\n <ion-card-title class=\"ion-no-margin ion-no-padding\">\n <ion-item detail=\"true\"\n tappable class=\"text-1x\"\n [routerLink]=\"page.path\"\n routerDirection=\"root\" lines=\"none\">\n <!-- page icon-->\n <ion-icon *ngIf=\"page.icon\" slot=\"start\" [name]=\"page.icon\"></ion-icon>\n <mat-icon *ngIf=\"page.matIcon\" slot=\"start\">{{page.matIcon}}</mat-icon>\n\n <ion-label color=\"primary\" [title]=\"page.title\">{{page.title}}</ion-label>\n </ion-item>\n </ion-card-title>\n </ion-card-header>\n\n <!-- children pages -->\n <ion-card-content class=\"ion-no-padding ion-padding-start\" *ngIf=\"page.children?.length\">\n <ion-list class=\"ion-no-padding\">\n <ion-item detail=\"true\"\n *ngFor=\"let childPage of page.children\"\n tappable class=\"text-1x\"\n [routerLink]=\"childPage.path\"\n routerDirection=\"root\">\n <!-- page icon-->\n <ion-icon *ngIf=\"childPage.icon\" slot=\"start\" color=\"dark\" [name]=\"childPage.icon\"></ion-icon>\n <mat-icon *ngIf=\"childPage.matIcon\" slot=\"start\" color=\"dark\">{{childPage.matIcon}}</mat-icon>\n\n <ion-label color=\"dark\" [innerHTML]=\"childPage.title\"></ion-label>\n </ion-item>\n </ion-list>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Display configured Departments logos -->\n <ng-template #bottomBanner>\n <div class=\"bottom-banner ion-text-center ion-padding\" *ngIf=\"!loadingBanner\" @fadeInAnimation>\n <a href=\"{{ item.siteUrl }}\" *ngFor=\"let item of $partners | async \">\n <img class=\"logo\" src=\"{{ item.logo }}\" alt=\"{{item.label}}\" [title]=\"item.label\" />\n </a>\n </div>\n </ng-template>\n\n\n</ion-content>\n",
20213
+ template: "<app-toolbar [canGoBack]=\"false\"\n visible-xs visible-sm visible-mobile>\n\n <!-- change locale button -->\n <ion-button slot=\"end\" *ngIf=\"currentLocaleCode; let code\"\n [matMenuTriggerFor]=\"localeMenu\">\n <ion-label class=\"ion-text-uppercase\">&nbsp;{{ code }}</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n</app-toolbar>\n\n<!-- change locale menu -->\n<mat-menu #localeMenu=\"matMenu\">\n <button *ngFor=\"let item of locales\"\n mat-menu-item\n (click)=\"changeLanguage(item.key)\">\n <ion-label>{{item.value}}</ion-label>\n </button>\n</mat-menu>\n\n<ion-content [ngStyle]=\"contentStyle\" no-padding-xs>\n\n <!-- loading spinner -->\n <div class=\"loading-page\" [class.cdk-visually-hidden]=\"!loading\">\n <div class=\"spinner\" *ngIf=\"loading && showSpinner\">\n <p>Loading...</p>\n <div class=\"sk-cube1 sk-cube\"></div>\n <div class=\"sk-cube2 sk-cube\"></div>\n <div class=\"sk-cube4 sk-cube\"></div>\n <div class=\"sk-cube3 sk-cube\"></div>\n </div>\n </div>\n\n <!-- Desktop: translucent top toolbar -->\n <div hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar translucent>\n <ion-buttons slot=\"start\">\n <ion-menu-toggle>\n <ion-button color=\"light\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n </ion-buttons>\n\n <ion-buttons slot=\"end\">\n <!-- change locale button -->\n <ion-button color=\"secondary\" fill=\"solid\"\n *ngIf=\"currentLocaleCode; let code\"\n [matMenuTriggerFor]=\"localeMenu\">\n <ion-label class=\"ion-text-uppercase\">&nbsp;{{ code }}</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </div>\n\n <!-- Install (and upgrade) card -->\n <app-install-upgrade-card [isLogin]=\"isLogin\"\n showInstallButton=\"true\">\n </app-install-upgrade-card>\n\n <!-- Welcome card -->\n <ion-card *ngIf=\"!loading\"\n class=\"main welcome ion-padding ion-text-center ion-align-self-center\"\n @fadeInAnimation>\n <ion-card-header>\n <ion-card-title class=\"ion-text-center\">\n <span *ngIf=\"isWeb\" [innerHTML]=\"'HOME.WELCOME_WEB'|translate: {appName: appName}\"></span>\n <span *ngIf=\"!isWeb\" [innerHTML]=\"'HOME.WELCOME_APP'|translate: {appName: appName}\"></span>\n </ion-card-title>\n <ion-card-subtitle [innerHTML]=\"description\">\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content class=\"ion-no-padding\">\n <ion-text color=\"primary\">\n <img class=\"logo\" *ngIf=\"logo\" src=\"{{ logo }}\">\n </ion-text>\n <!-- register help text -->\n <ion-text *ngIf=\"!isLogin && canRegister\">\n <br/>\n <span translate>HOME.REGISTER_HELP</span>\n </ion-text>\n </ion-card-content>\n\n <ion-footer class=\"ion-padding-top\">\n\n <!-- If NOT login -->\n <ng-container *ngIf=\"!isLogin; else loginButtons;\">\n\n <ion-button *ngIf=\"canRegister\" expand=\"block\" color=\"tertiary\" (click)=\"register()\">\n <span translate>HOME.BTN_REGISTER</span>\n </ion-button>\n <ion-button expand=\"block\" color=\"light\" [routerLink]=\"['/']\" (click)=\"login()\">\n <span translate>AUTH.BTN_LOGIN</span>\n </ion-button>\n\n </ng-container>\n\n <!-- If user login -->\n <ng-template #loginButtons>\n\n <!-- Feature buttons -->\n <ng-container *ngIf=\"$filteredButtons | async as buttons\">\n <ng-container *ngFor=\"let item of buttons\">\n <ion-button *ngIf=\"item.path\"\n expand=\"block\" color=\"tertiary\"\n [class]=\"item.cssClass\"\n [routerLink]=\"item.path\"\n routerDirection=\"root\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-text>{{'HOME.BTN_DATA_ENTRY'|translate: {name: (item.title | translate) } }}</ion-text>\n </ion-button>\n\n <!-- divider -->\n <div *ngIf=\"!item.path && !item.action\" [class]=\"item.cssClass\">\n <ion-label translate>{{item.title}}&nbsp;</ion-label>\n </div>\n </ng-container>\n\n <!--<p *ngIf=\"buttons.length\" class=\"visible-mobile\">&nbsp;</p>-->\n </ng-container>\n\n <ion-button expand=\"block\" color=\"secondary\" [routerLink]=\"['/account']\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" name=\"person-circle\"></ion-icon>\n <ion-text translate>HOME.BTN_MY_ACCOUNT</ion-text>\n </ion-button>\n\n <p hidden-xs hidden-sm hidden-mobile>\n <ion-text [innerHTML]=\"'HOME.NOT_THIS_ACCOUNT_QUESTION' | translate: {displayName: accountName }\"></ion-text>\n <br/>\n <ion-text>\n <a href=\"#\" (click)=\"logout($event)\">\n <span translate>HOME.BTN_DISCONNECT</span>\n </a>\n </ion-text>\n </p>\n\n\n </ng-template>\n\n </ion-footer>\n </ion-card>\n\n <!-- Page history -->\n <ion-grid *ngIf=\"!loading && isLogin && pageHistory.length; else bottomBanner\"\n class=\"history-container ion-align-self-center\">\n <ion-row>\n <ion-col size=\"12\" size-xl=\"\" *ngFor=\"let page of pageHistory; trackBy: getPagePath\"\n class=\"ion-text-center\">\n <ion-card class=\"ion-align-self-start ion-text-start\" @fadeInAnimation>\n <ion-card-header class=\"ion-no-padding\">\n <!-- top bar -->\n <ion-card-subtitle>\n <button type=\"button\" tabindex=\"-1\"\n (click)=\"settings.removePageHistory(page.path)\"\n mat-icon-button class=\"ion-float-start ion-no-margin\">\n <mat-icon>close</mat-icon>\n </button>\n <ion-label [innerHTML]=\"page.subtitle|translate\"></ion-label>\n <ion-text class=\"ion-float-end\" [title]=\"page.time|dateFormat:{time: true}\">\n <small><ion-icon name=\"time-outline\"></ion-icon>&nbsp;{{ page.time|dateFromNow }}</small>&nbsp;\n </ion-text>\n </ion-card-subtitle>\n\n <!-- main page -->\n <ion-card-title class=\"ion-no-margin ion-no-padding\">\n <ion-item detail=\"true\"\n tappable class=\"text-1x\"\n [routerLink]=\"page.path\"\n routerDirection=\"root\" lines=\"none\">\n <!-- page icon-->\n <ion-icon *ngIf=\"page.icon\" slot=\"start\" [name]=\"page.icon\"></ion-icon>\n <mat-icon *ngIf=\"page.matIcon\" slot=\"start\">{{page.matIcon}}</mat-icon>\n\n <ion-label color=\"primary\" [innerHTML]=\"page.title\"></ion-label>\n </ion-item>\n </ion-card-title>\n </ion-card-header>\n\n <!-- children pages -->\n <ion-card-content class=\"ion-no-padding ion-padding-start\" *ngIf=\"page.children?.length\">\n <ion-list class=\"ion-no-padding\">\n <ion-item detail=\"true\"\n *ngFor=\"let childPage of page.children\"\n tappable class=\"text-1x\"\n [routerLink]=\"childPage.path\"\n routerDirection=\"root\">\n <!-- page icon-->\n <ion-icon *ngIf=\"childPage.icon\" slot=\"start\" color=\"dark\" [name]=\"childPage.icon\"></ion-icon>\n <mat-icon *ngIf=\"childPage.matIcon\" slot=\"start\" color=\"dark\">{{childPage.matIcon}}</mat-icon>\n\n <ion-label color=\"dark\" [innerHTML]=\"childPage.title\"></ion-label>\n </ion-item>\n </ion-list>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Display configured Departments logos -->\n <ng-template #bottomBanner>\n <div class=\"bottom-banner ion-text-center ion-padding\" *ngIf=\"!loadingBanner\" @fadeInAnimation>\n <a href=\"{{ item.siteUrl }}\" *ngFor=\"let item of $partners | async \">\n <img class=\"logo\" src=\"{{ item.logo }}\" alt=\"{{item.label}}\" [title]=\"item.label\" />\n </a>\n </div>\n </ng-template>\n\n\n</ion-content>\n",
20189
20214
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
20190
20215
  animations: [fadeInAnimation, slideUpDownAnimation],
20191
20216
  styles: ["h1,h2,h3,h4,h5{white-space:normal}.center,ion-content ion-card.welcome img{text-align:center;display:inline-block}ion-content{--background:transparent;background-size:cover;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;display:inline-block;padding:15px}ion-content,ion-content .loading-page{background-color:var(--ion-color-primary)}ion-content .loading-page{display:block;height:100%;width:100%;position:absolute;z-index:5;transition:background .5s linear;-webkit-transition:background 1.5s linear}ion-content .loading-page.hidden{background-color:rgba(var(--ion-color-primary),0)}ion-content ion-card{z-index:9}ion-content ion-card ion-card-header{display:block}ion-content ion-card ion-card-header ion-card-subtitle,ion-content ion-card ion-card-header ion-card-title{display:block;width:100%}ion-content ion-card.main{min-width:240px;max-width:400px;margin-left:auto;margin-right:auto}ion-content ion-card.welcome{background-color:hsla(0,0%,100%,.7)}ion-content ion-card.welcome button{margin-top:16px}ion-content ion-card.welcome img{max-width:250px}ion-content .history-container{margin-left:auto;margin-right:auto}ion-content .history-container ion-card{display:inline-block;box-sizing:border-box;z-index:8;min-width:240px;max-width:400px;width:100%;margin-left:auto;margin-right:auto;background-color:hsla(0,0%,100%,.7)}ion-content .history-container ion-card ion-card-header ion-card-subtitle{height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle button[float-start]{z-index:99;margin:0}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label{line-height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label[float-end]{padding-right:16px;font-weight:400}ion-content .history-container ion-card ion-card-header ion-card-title ion-item{--ion-item-background:$transparent;--ion-item-icon-color:var(--ion-color-primary);--ion-item-text-color:var(--ion-color-primary)}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-header ion-card-title ion-item mat-icon[slot=start]{margin-right:unset;-webkit-margin-end:16px!important;margin-inline-end:16px!important;color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-label,ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-text{color:var(--ion-item-text-color)!important;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}ion-content .history-container ion-card ion-card-content ion-list{--ion-item-background:var(--ion-color-transparent)}ion-content .history-container ion-card ion-card-content ion-list ion-item{--ion-item-icon-color:var(--ion-color-dark);--ion-item-text-color:var(--ion-color-dark)}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-content ion-list ion-item mat-icon[slot=start]{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor;margin-right:unset;-webkit-margin-end:16px!important;margin-inline-end:16px!important}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-label,ion-content .history-container ion-card ion-card-content ion-list ion-item ion-text{color:var(--ion-item-text-color)!important}ion-content .bottom-banner{background-color:hsla(0,0%,100%,.7);min-width:240px;z-index:0;position:absolute;left:16px;right:16px;bottom:16px}ion-content .bottom-banner img.logo{max-height:50px;margin-left:8px}ion-content ion-text{text-align:center}@media screen and (max-width:575px){ion-content ion-card{min-width:160px;width:calc(100% - 20px);max-width:100%;margin-left:10px;margin-right:10px}ion-content ion-card h1{margin-top:0;font-size:20px}ion-content ion-card button{margin-top:8px}ion-content .bottom-banner{display:block;position:unset}ion-content .bottom-banner img.logo{max-height:30px}}@media screen and (max-width:767px) and (min-width:576px){ion-content{min-height:555px}ion-content .bottom-banner img.logo{max-height:40px}}@media screen and (min-width:768px){ion-content{min-height:calc(100% - 100px)}}"]
@@ -21171,6 +21196,7 @@
21171
21196
  case 0:
21172
21197
  if (this.saving)
21173
21198
  return [2 /*return*/]; // Skip
21199
+ event === null || event === void 0 ? void 0 : event.preventDefault();
21174
21200
  // Remove all empty controls
21175
21201
  this.propertiesFormHelper.removeAllEmpty();
21176
21202
  if (this.form.invalid && this.debug) {
@@ -21308,7 +21334,7 @@
21308
21334
  _a.label = 3;
21309
21335
  case 3:
21310
21336
  // Back to home
21311
- return [2 /*return*/, this.router.navigateByUrl('/', { skipLocationChange: true })];
21337
+ return [2 /*return*/, this.router.navigateByUrl('/', { replaceUrl: true })]; // back to home
21312
21338
  }
21313
21339
  });
21314
21340
  });
@@ -21854,7 +21880,6 @@
21854
21880
  this.showOfflineWarning = true;
21855
21881
  this.showInstallButton = false;
21856
21882
  this.onUpdateOfflineModeClick = new i0.EventEmitter();
21857
- this.hasDownloader = this.platform.canDownload;
21858
21883
  }
21859
21884
  Object.defineProperty(AppInstallUpgradeCard.prototype, "showUpdateOfflineFeature", {
21860
21885
  get: function () {
@@ -22000,6 +22025,7 @@
22000
22025
  if (!config)
22001
22026
  return [2 /*return*/]; // Skip
22002
22027
  console.info('[install-upgrade-card] Check if need to install or upgrade...');
22028
+ this.hasDownloader = this.platform.canDownload;
22003
22029
  _a.label = 1;
22004
22030
  case 1:
22005
22031
  _a.trys.push([1, , 5, 6]);
@@ -25479,7 +25505,7 @@
25479
25505
  row = row || this.editedRow;
25480
25506
  if (!row || !this.formErrorAdapter)
25481
25507
  return undefined;
25482
- return this.formErrorAdapter.translateErrors(row.validator, Object.assign(Object.assign({}, this.errorTranslatorOptions), opts));
25508
+ return this.formErrorAdapter.translateFormErrors(row.validator, Object.assign(Object.assign({}, this.errorTranslatorOptions), opts));
25483
25509
  };
25484
25510
  AppTable.prototype.setError = function (value, opts) {
25485
25511
  if (this.errorSubject.value !== value) {
@@ -26404,7 +26430,7 @@
26404
26430
  enableListenChanges: (injector.get(ENVIRONMENT).listenRemoteChanges === true), pathIdAttribute: 'id', autoLoad: true, autoUpdateRoute: true, i18nPrefix: ''
26405
26431
  }, options);
26406
26432
  _this.settings = injector.get(LocalSettingsService);
26407
- _this.formErrorAdapter = injector.get(FormErrorTranslator);
26433
+ _this.errorTranslator = injector.get(FormErrorTranslator);
26408
26434
  _this.cd = injector.get(i0.ChangeDetectorRef);
26409
26435
  _this.dateFormat = injector.get(DateFormatPipe);
26410
26436
  _this.toastController = injector.get(i1$5.ToastController);
@@ -26966,7 +26992,7 @@
26966
26992
  var userMessage = err && err.message && this.translate.instant(err.message) || err;
26967
26993
  // Add details error (if any) under the main message
26968
26994
  var detailMessage = err && err.details && (err.details.message || err.details) || undefined;
26969
- if (detailMessage) {
26995
+ if (isNotNilString(detailMessage)) {
26970
26996
  userMessage += "<br/><small class=\"hidden-xs hidden-sm\" title=\"" + detailMessage + "\">";
26971
26997
  userMessage += detailMessage.length < 70 ? detailMessage : detailMessage.substring(0, 67) + '...';
26972
26998
  userMessage += '</small>';