@umbraco-cms/backoffice 17.5.0-rc → 17.5.0

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.
@@ -217,7 +217,7 @@ let UmbAppElement = class UmbAppElement extends UmbLitElement {
217
217
  onInit(this, umbExtensionsRegistry);
218
218
  // Register public extensions (login extensions)
219
219
  await new UmbServerExtensionRegistrator(this, umbExtensionsRegistry).registerPublicExtensions();
220
- new UmbAppEntryPointExtensionInitializer(this, umbExtensionsRegistry);
220
+ const entryPointInitializer = new UmbAppEntryPointExtensionInitializer(this, umbExtensionsRegistry);
221
221
  // Try to initialise the auth flow and get the runtime status
222
222
  try {
223
223
  // If the runtime level is "install" or ?status=false is set, we should clear any cached tokens
@@ -230,6 +230,11 @@ let UmbAppElement = class UmbAppElement extends UmbLitElement {
230
230
  else {
231
231
  await this.#setAuthStatus();
232
232
  }
233
+ // The login screen decides which auth provider to use from the registered
234
+ // `authProvider` extensions. App-entry-points may register or unregister those during
235
+ // their async onInit, so wait for them to settle before routing — otherwise on a slow
236
+ // connection the decision races and falls back to the local login.
237
+ await this.observe(entryPointInitializer.loaded).asPromise();
233
238
  // Initialise the router
234
239
  this.#redirect();
235
240
  }
@@ -967,7 +967,7 @@ export default {
967
967
  greeting5: 'Willkommen',
968
968
  greeting6: 'Willkommen',
969
969
  instruction: 'Hier anmelden:',
970
- signInWith: 'Anmelden mit',
970
+ signInWith: 'Anmelden mit {0}',
971
971
  timeout: 'Sitzung abgelaufen',
972
972
  bottomText: '<p style="text-align:right;">&copy; 2001 - %0% <br /><a href="https://umbraco.com" style="text-decoration: none" target="_blank" rel="noopener">umbraco.org</a></p> ',
973
973
  forgottenPassword: 'Kennwort vergessen?',
@@ -848,7 +848,7 @@ export default {
848
848
  greeting5: 'Bienvenue',
849
849
  greeting6: 'Bienvenue',
850
850
  instruction: 'Connectez-vous ci-dessous',
851
- signInWith: 'Identifiez-vous avec',
851
+ signInWith: 'Identifiez-vous avec {0}',
852
852
  timeout: 'La session a expiré',
853
853
  bottomText: '<p style="text-align:right;">&copy; 2001 - %0% <br /><a href="https://umbraco.com" style="text-decoration: none" target="_blank" rel="noopener">Umbraco.com</a></p> ',
854
854
  forgottenPassword: 'Mot de passe oublié?',
@@ -660,7 +660,7 @@ export default {
660
660
  greeting5: 'Velkommen',
661
661
  greeting6: 'Velkommen',
662
662
  instruction: 'Logg på nedenfor',
663
- signInWith: 'Logg på med',
663
+ signInWith: 'Logg på med {0}',
664
664
  timeout: 'Din sesjon er utløpt',
665
665
  bottomText: '<p style="text-align:right;">&copy; 2001 - %0% <br /><a href="https://umbraco.com" style="text-decoration: none" target="_blank" rel="noopener">umbraco.com</a></p> ',
666
666
  },
@@ -866,7 +866,7 @@ export default {
866
866
  greeting5: 'Welkom',
867
867
  greeting6: 'Welkom',
868
868
  instruction: 'log hieronder in',
869
- signInWith: 'Inloggen met',
869
+ signInWith: 'Inloggen met {0}',
870
870
  timeout: 'Sessie is verlopen',
871
871
  bottomText: '<p style="text-align:right;">&copy; 2001 - %0% <br /><a href="https://umbraco.com" style="text-decoration: none" target="_blank" rel="noopener">umbraco.com</a></p>',
872
872
  forgottenPassword: 'Wachtwoord vergeten?',
@@ -644,7 +644,7 @@ export default {
644
644
  greeting5: 'Välkommen',
645
645
  greeting6: 'Välkommen',
646
646
  instruction: 'Logga in nedan',
647
- signInWith: 'Logga in med',
647
+ signInWith: 'Logga in med {0}',
648
648
  timeout: 'Sessionen har nått sin maxgräns',
649
649
  },
650
650
  main: {
@@ -6,7 +6,7 @@
6
6
  "build": "vite build"
7
7
  },
8
8
  "dependencies": {
9
- "@umbraco-ui/uui": "^1.18.0",
10
- "@umbraco-ui/uui-css": "^1.18.0"
9
+ "@umbraco-ui/uui": "^1.18.1",
10
+ "@umbraco-ui/uui-css": "^1.18.1"
11
11
  }
12
12
  }
@@ -7,28 +7,52 @@ export class UmbExtensionInitializerBase extends UmbControllerBase {
7
7
  #extensionMap;
8
8
  // Use the value `undefined`, as that would not resolve a observation promise. [NL]
9
9
  #loaded;
10
+ // Identifies the current processing pass. The observer callback is async, so passes can
11
+ // overlap; only the latest pass is allowed to settle `loaded`, so a slower earlier pass
12
+ // cannot unblock waiters before the newest set of extensions has finished instantiating.
13
+ #loadPass;
10
14
  constructor(host, extensionRegistry, manifestType) {
11
15
  super(host);
12
16
  this.#extensionMap = new Map();
13
17
  // Use the value `undefined`, as that would not resolve a observation promise. [NL]
14
18
  this.#loaded = new UmbBooleanState(undefined);
15
19
  this.loaded = this.#loaded.asObservable();
20
+ // Identifies the current processing pass. The observer callback is async, so passes can
21
+ // overlap; only the latest pass is allowed to settle `loaded`, so a slower earlier pass
22
+ // cannot unblock waiters before the newest set of extensions has finished instantiating.
23
+ this.#loadPass = 0;
16
24
  this.host = host;
17
25
  this.extensionRegistry = extensionRegistry;
18
26
  this.observe(extensionRegistry.byType(manifestType), async (extensions) => {
27
+ const pass = ++this.#loadPass;
28
+ // Re-arm while this pass is in flight so a consumer awaiting `loaded` waits for it to
29
+ // finish instead of resolving on a stale `true` from a previous pass. `undefined`
30
+ // rather than `false` because `asPromise()` resolves on the first non-undefined value.
31
+ this.#loaded.setValue(undefined);
19
32
  this.#extensionMap.forEach((existingExt) => {
20
33
  if (!extensions.find((b) => b.alias === existingExt.alias)) {
21
34
  this.unloadExtension(existingExt);
22
35
  this.#extensionMap.delete(existingExt.alias);
23
36
  }
24
37
  });
25
- await Promise.all(extensions.map((extension) => {
38
+ // `allSettled` so a throwing/rejecting `instantiateExtension` cannot leave `loaded`
39
+ // stuck at `undefined` and hang a waiter (e.g. the app boot gate). Failures are
40
+ // surfaced rather than swallowed.
41
+ const results = await Promise.allSettled(extensions.map((extension) => {
26
42
  if (this.#extensionMap.has(extension.alias))
27
43
  return;
28
44
  this.#extensionMap.set(extension.alias, extension);
29
45
  return this.instantiateExtension(extension);
30
46
  }));
31
- if (extensions.length > 0) {
47
+ for (const result of results) {
48
+ if (result.status === 'rejected') {
49
+ console.error('[UmbExtensionInitializer] Failed to instantiate extension', result.reason);
50
+ }
51
+ }
52
+ // Only the latest pass settles `loaded`. Resolving unconditionally — including for
53
+ // zero extensions — so a consumer awaiting `loaded` (the app-entry-point boot gate,
54
+ // the bundle guard) never hangs on a default install that registers none of this type.
55
+ if (pass === this.#loadPass) {
32
56
  this.#loaded.setValue(true);
33
57
  }
34
58
  });