@c8y/ngx-components 1017.0.3 → 1017.0.5

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.
@@ -642,7 +642,7 @@ class AppStateService extends StateService {
642
642
  this.currentUser = new BehaviorSubject(null);
643
643
  this.currentTenant = new BehaviorSubject(null);
644
644
  this.currentApplication = new BehaviorSubject(null);
645
- this.currentApplicationConfig = this.currentApplication.pipe(map(app => app?.config || null));
645
+ this.currentApplicationConfig = this.currentApplication.pipe(filter(app => !!app), map(app => app?.config || null));
646
646
  this.apiService.calls
647
647
  .pipe(filter(({ url }) => !/notification\/realtime/.test(url)), map(({ phase }) => (phase === 'start' ? 1 : -1)), scan((count, item) => count + item, 0), map(count => count > 0), distinctUntilChanged())
648
648
  .subscribe(isLoading => (this.state.isLoading = isLoading));
@@ -686,6 +686,7 @@ class AppStateService extends StateService {
686
686
  await this.loadDefaultOptions();
687
687
  }
688
688
  catch (ex) {
689
+ this.currentApplication.next({});
689
690
  throw ex;
690
691
  }
691
692
  }
@@ -9292,11 +9293,13 @@ class DynamicComponentService extends StateService {
9292
9293
  */
9293
9294
  this.factories = [];
9294
9295
  this.injectors = [this.rootInjector];
9296
+ this.remotePluginsLoaded$ = new BehaviorSubject(false);
9297
+ const remotesLoaded$ = this.remotePluginsLoaded$.pipe(filter(loaded => !!loaded), take(1));
9295
9298
  this.items$ = fromTriggerOnce(router, this.refreshTrigger, [
9296
9299
  getInjectedHooks(HOOK_COMPONENTS, this.injectors),
9297
9300
  () => this.factories,
9298
9301
  stateToFactory(this.state$)
9299
- ]).pipe(distinctUntilChanged(), takeUntil(timer(waitTimeout || this.DEFAULT_WAIT_TIMEOUT)), shareReplay(1));
9302
+ ]).pipe(distinctUntilChanged(), takeUntil(combineLatest([timer(waitTimeout || this.DEFAULT_WAIT_TIMEOUT), remotesLoaded$])), shareReplay(1));
9300
9303
  }
9301
9304
  refresh() {
9302
9305
  this.refreshTrigger.next(1);
@@ -9333,6 +9336,9 @@ class DynamicComponentService extends StateService {
9333
9336
  const dynamicDef = await Promise.all(componentIdAndConfig.map(({ componentId }) => this.getById(componentId)));
9334
9337
  return this.dynamicResolver.serialize(componentIdAndConfig, dynamicDef);
9335
9338
  }
9339
+ markPluginsAsLoaded() {
9340
+ this.remotePluginsLoaded$.next(true);
9341
+ }
9336
9342
  }
9337
9343
  DynamicComponentService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: DynamicComponentService, deps: [{ token: i0.Injector }, { token: i1.Router }, { token: RESOLVING_COMPONENT_WAIT_TIME, optional: true }, { token: DynamicResolverService }], target: i0.ɵɵFactoryTarget.Injectable });
9338
9344
  DynamicComponentService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: DynamicComponentService, providedIn: 'root' });
@@ -10164,6 +10170,7 @@ class PluginsResolveService {
10164
10170
  .map(({ name, factory }) => factory[name]);
10165
10171
  this.loadModulesDynamically(remoteNgModules);
10166
10172
  this.refreshHooks();
10173
+ this.markPluginsAsLoaded();
10167
10174
  }
10168
10175
  /**
10169
10176
  * Loads modules and handles hooking correctly.
@@ -10200,6 +10207,9 @@ class PluginsResolveService {
10200
10207
  }
10201
10208
  });
10202
10209
  }
10210
+ markPluginsAsLoaded() {
10211
+ this.dynamicComponent.markPluginsAsLoaded();
10212
+ }
10203
10213
  /**
10204
10214
  * Loads a list of remotes so that a particular application can use them.
10205
10215
  * The request is made to the following address: /apps/<contextPath>/remoteEntry.js
@@ -10216,15 +10226,20 @@ class PluginsResolveService {
10216
10226
  if (remotes.hasOwnProperty(pluginId)) {
10217
10227
  const moduleNames = remotes[pluginId];
10218
10228
  const url = `/apps/${pluginId}/remoteEntry.js?nocache=${date.getTime()}`;
10229
+ let atLeastOneModuleLoadedSuccessfully = false;
10219
10230
  for (const moduleName of moduleNames) {
10220
10231
  try {
10221
10232
  remoteModules.push(await this.loadRemoteModule(url, pluginId, moduleName));
10233
+ atLeastOneModuleLoadedSuccessfully = true;
10222
10234
  }
10223
10235
  catch (ex) {
10224
10236
  console.warn(`Could not load remote module '${moduleName}' from url:`, url);
10225
10237
  }
10226
10238
  }
10227
- await this.loadRemoteTranslations(pluginId);
10239
+ // no need to load translations if we were unable to load a single module..
10240
+ if (atLeastOneModuleLoadedSuccessfully) {
10241
+ await this.loadRemoteTranslations(pluginId);
10242
+ }
10228
10243
  }
10229
10244
  }
10230
10245
  return remoteModules;
@@ -16361,6 +16376,7 @@ class BootstrapComponent {
16361
16376
  }
16362
16377
  async loadRemotes(remotes) {
16363
16378
  if (!remotes) {
16379
+ this.ensureWeMarkPluginsAsLoaded();
16364
16380
  return;
16365
16381
  }
16366
16382
  const remoteModules = await this.pluginsResolve.loadRemotes(remotes);
@@ -16372,12 +16388,17 @@ class BootstrapComponent {
16372
16388
  }
16373
16389
  subscribeToLoadRemotes() {
16374
16390
  if (this.options.get('noPlugins', false)) {
16391
+ this.ensureWeMarkPluginsAsLoaded();
16375
16392
  return;
16376
16393
  }
16377
16394
  this.ui.currentApplicationConfig
16378
16395
  .pipe(takeUntil(this.destroy$))
16379
16396
  .subscribe((config) => this.loadRemotes(this.getRemotes(config)));
16380
16397
  }
16398
+ ensureWeMarkPluginsAsLoaded() {
16399
+ // ensure we call markPluginsAsLoaded on the DynamicComponentService
16400
+ this.pluginsResolve.markPluginsAsLoaded();
16401
+ }
16381
16402
  }
16382
16403
  BootstrapComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: BootstrapComponent, deps: [{ token: TabsService }, { token: AppStateService }, { token: NavigatorService }, { token: ActionBarService }, { token: HeaderService }, { token: OptionsService }, { token: PluginsResolveService }, { token: SetupService }], target: i0.ɵɵFactoryTarget.Component });
16383
16404
  BootstrapComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: BootstrapComponent, selector: "c8y-bootstrap", ngImport: i0, template: "<c8y-login *ngIf=\"!noLogin && !(ui.currentUser | async)\"></c8y-login>\n\n<div\n *ngIf=\"noLogin || ((ui.currentUser | async) && !(setupService.isSetupNeeded$ | async))\"\n [class.head-open]=\"headerService.headerOpen\"\n>\n <c8y-header-bar #header></c8y-header-bar>\n <c8y-navigator-outlet\n [nodes]=\"navigator.items$ | async\"\n [open]=\"headerService.navigatorOpen$ | async\"\n role=\"region\"\n title=\"{{ 'Navigator menu' | translate }}\"\n >\n <header class=\"title navigator-slot-top\">\n <div class=\"tenant-brand\"></div>\n <c8y-app-icon\n [name]=\"(ui.state$ | async).app.name\"\n [contextPath]=\"(ui.state$ | async).app.contextPath\"\n ></c8y-app-icon>\n <span>{{ (ui.state$ | async).app | humanizeAppName | async }}</span>\n </header>\n <div class=\"powered-by navigator-slot-bottom\" *ngIf=\"showPoweredBy\">\n <p translate>powered by Cumulocity</p>\n </div>\n </c8y-navigator-outlet>\n\n <div class=\"alerts\">\n <c8y-alert-outlet></c8y-alert-outlet>\n </div>\n <c8y-tabs-outlet\n #tabsComponent\n [tabs]=\"tabs.items$ | async\"\n [navigatorOpen]=\"headerService.navigatorOpen$ | async\"\n [orientation]=\"tabs.orientation$ | async\"\n role=\"navigation\"\n ></c8y-tabs-outlet>\n <c8y-action-bar\n #actionBarComponent\n [navigatorOpen]=\"headerService.navigatorOpen$ | async\"\n [hasTabs]=\"tabsComponent.hasTabs\"\n [isTabsHorizontal]=\"tabsComponent?.isHorizontal\"\n [items$]=\"actionBar.items$\"\n role=\"group\"\n ></c8y-action-bar>\n\n <div\n class=\"mcontainer\"\n [ngClass]=\"{\n open: headerService.navigatorOpen$ | async,\n 'no-apps-margin': noAppsMargin$ | async,\n 'horizontal-tabs': tabsComponent.isHorizontal,\n 'vertical-tabs': !tabsComponent.isHorizontal,\n 'has-tabs': tabsComponent.hasTabs,\n 'has-action-bar': !actionBarComponent?.hidden\n }\"\n >\n <main id=\"main-content\" class=\"container-fluid\" tabindex=\"-1\">\n <router-outlet></router-outlet>\n <ng-content select=\"#c8y-legacy-view\"></ng-content>\n <!-- legacy ng-view, will not be migrated atm -->\n </main>\n </div>\n</div>\n\n<div *ngIf=\"(ui.currentUser | async) && (setupService.isSetupNeeded$ | async)\">\n <c8y-header-bar [simple]=\"true\"></c8y-header-bar>\n <div class=\"mcontainer\" role=\"main\">\n <div class=\"container-fluid\">\n <c8y-setup></c8y-setup>\n </div>\n </div>\n</div>\n\n<c8y-cookie-banner></c8y-cookie-banner>\n", dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1$5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: HeaderBarComponent, selector: "c8y-header-bar", inputs: ["simple"] }, { kind: "component", type: AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "component", type: LoginComponent, selector: "c8y-login", inputs: ["name"] }, { kind: "directive", type: i1.RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: TabsOutletComponent, selector: "c8y-tabs-outlet,c8y-ui-tabs", inputs: ["tabs", "orientation", "navigatorOpen"] }, { kind: "component", type: ActionBarComponent, selector: "c8y-action-bar", inputs: ["navigatorOpen", "hasTabs", "isTabsHorizontal", "items$"] }, { kind: "component", type: AlertOutletComponent, selector: "c8y-alert-outlet" }, { kind: "component", type: NavigatorOutletComponent, selector: "c8y-navigator-outlet, c8y-ui-navigator", inputs: ["nodes", "open"] }, { kind: "component", type: SetupComponent, selector: "c8y-setup" }, { kind: "component", type: CookieBannerComponent, selector: "c8y-cookie-banner" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i1$5.AsyncPipe, name: "async" }, { kind: "pipe", type: HumanizeAppNamePipe, name: "humanizeAppName" }] });