@backstage/core-app-api 1.2.1-next.1 → 1.2.1-next.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @backstage/core-app-api
2
2
 
3
+ ## 1.2.1-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - b4b5b02315: Tweak feature flag registration so that it happens immediately before the first rendering of the app, rather than just after.
8
+ - 203271b746: Prevent duplicate feature flag components from rendering in the settings when using <FeatureFlagged /> components
9
+ - 8015ff1258: Tweaked wording to use inclusive terminology
10
+ - 63310e3987: Apps will now rewrite the `app.baseUrl` configuration to match the current `location.origin`. The `backend.baseUrl` will also be rewritten in the same way when the `app.baseUrl` and `backend.baseUrl` have matching origins. This will reduce the need for separate frontend builds for different environments.
11
+ - Updated dependencies
12
+ - @backstage/core-plugin-api@1.2.0-next.2
13
+ - @backstage/config@1.0.5-next.1
14
+ - @backstage/types@1.0.2-next.1
15
+ - @backstage/version-bridge@1.0.3-next.0
16
+
3
17
  ## 1.2.1-next.1
4
18
 
5
19
  ### Patch Changes
package/dist/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useContext, Children, isValidElement, useEffect, useMemo, useState, createContext } from 'react';
1
+ import React, { useContext, Children, isValidElement, useEffect, useMemo, useState, createContext, useRef } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { createVersionedContext, createVersionedValueMap, getOrCreateGlobalSingleton } from '@backstage/version-bridge';
4
4
  import ObservableImpl from 'zen-observable';
@@ -2509,7 +2509,7 @@ function readBasePath(configApi) {
2509
2509
  var _a;
2510
2510
  let { pathname } = new URL(
2511
2511
  (_a = configApi.getOptionalString("app.baseUrl")) != null ? _a : "/",
2512
- "http://dummy.dev"
2512
+ "http://sample.dev"
2513
2513
  );
2514
2514
  pathname = pathname.replace(/\/*$/, "");
2515
2515
  return pathname;
@@ -2532,7 +2532,44 @@ function useConfigLoader(configLoader, components, appThemeApi) {
2532
2532
  node: /* @__PURE__ */ React.createElement(ApiProvider, { apis: ApiRegistry.with(appThemeApiRef, appThemeApi) }, /* @__PURE__ */ React.createElement(ThemeProvider, null, noConfigNode))
2533
2533
  };
2534
2534
  }
2535
- const configReader = ConfigReader.fromConfigs((_a = config.value) != null ? _a : []);
2535
+ let configReader;
2536
+ if ((_a = config.value) == null ? void 0 : _a.length) {
2537
+ const urlConfigReader = ConfigReader.fromConfigs(config.value);
2538
+ const getOrigin = (url) => new URL(url).origin;
2539
+ const overrideOrigin = (fullUrl) => {
2540
+ return new URL(
2541
+ fullUrl.replace(getOrigin(fullUrl), ""),
2542
+ document.location.origin
2543
+ ).href;
2544
+ };
2545
+ const appBaseUrl = urlConfigReader.getOptionalString("app.baseUrl");
2546
+ const backendBaseUrl = urlConfigReader.getOptionalString("backend.baseUrl");
2547
+ let configs = config.value;
2548
+ const relativeResolverConfig = {
2549
+ data: {},
2550
+ context: "relative-resolver"
2551
+ };
2552
+ if (appBaseUrl && backendBaseUrl) {
2553
+ const appOrigin = getOrigin(appBaseUrl);
2554
+ const backendOrigin = getOrigin(backendBaseUrl);
2555
+ if (appOrigin === backendOrigin) {
2556
+ relativeResolverConfig.data.backend = {
2557
+ baseUrl: overrideOrigin(backendBaseUrl)
2558
+ };
2559
+ }
2560
+ }
2561
+ if (appBaseUrl) {
2562
+ relativeResolverConfig.data.app = {
2563
+ baseUrl: overrideOrigin(appBaseUrl)
2564
+ };
2565
+ }
2566
+ if (Object.keys(relativeResolverConfig.data).length) {
2567
+ configs = configs.concat([relativeResolverConfig]);
2568
+ }
2569
+ configReader = ConfigReader.fromConfigs(configs);
2570
+ } else {
2571
+ configReader = ConfigReader.fromConfigs([]);
2572
+ }
2536
2573
  return { api: configReader };
2537
2574
  }
2538
2575
  class AppContextImpl {
@@ -2582,6 +2619,7 @@ class AppManager {
2582
2619
  const appContext = new AppContextImpl(this);
2583
2620
  let routesHaveBeenValidated = false;
2584
2621
  const Provider = ({ children }) => {
2622
+ const needsFeatureFlagRegistrationRef = useRef(true);
2585
2623
  const appThemeApi = useMemo(
2586
2624
  () => AppThemeSelector.createWithStorage(this.themes),
2587
2625
  []
@@ -2622,9 +2660,13 @@ class AppManager {
2622
2660
  const { api } = loadedConfig;
2623
2661
  this.configApi = api;
2624
2662
  }
2625
- useEffect(() => {
2626
- if (hasConfigApi) {
2627
- const featureFlagsApi = this.getApiHolder().get(featureFlagsApiRef);
2663
+ if ("node" in loadedConfig) {
2664
+ return loadedConfig.node;
2665
+ }
2666
+ if (hasConfigApi && needsFeatureFlagRegistrationRef.current) {
2667
+ needsFeatureFlagRegistrationRef.current = false;
2668
+ const featureFlagsApi = this.getApiHolder().get(featureFlagsApiRef);
2669
+ if (featureFlagsApi) {
2628
2670
  for (const plugin of this.plugins.values()) {
2629
2671
  if ("getFeatureFlags" in plugin) {
2630
2672
  for (const flag of plugin.getFeatureFlags()) {
@@ -2644,13 +2686,14 @@ class AppManager {
2644
2686
  }
2645
2687
  }
2646
2688
  }
2689
+ const registeredFlags = featureFlagsApi.getRegisteredFlags();
2690
+ const flagNames = new Set(registeredFlags.map((f) => f.name));
2647
2691
  for (const name of featureFlags) {
2648
- featureFlagsApi.registerFlag({ name, pluginId: "" });
2692
+ if (!flagNames.has(name)) {
2693
+ featureFlagsApi.registerFlag({ name, pluginId: "" });
2694
+ }
2649
2695
  }
2650
2696
  }
2651
- }, [hasConfigApi, loadedConfig, featureFlags]);
2652
- if ("node" in loadedConfig) {
2653
- return loadedConfig.node;
2654
2697
  }
2655
2698
  const { ThemeProvider = AppThemeProvider } = this.components;
2656
2699
  return /* @__PURE__ */ React.createElement(ApiProvider, { apis: this.getApiHolder() }, /* @__PURE__ */ React.createElement(AppContextProvider, { appContext }, /* @__PURE__ */ React.createElement(ThemeProvider, null, /* @__PURE__ */ React.createElement(