@backstage/plugin-app 0.3.4-next.0 → 0.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.
- package/CHANGELOG.md +30 -0
- package/dist/apis/PluginWrapperApi/DefaultPluginWrapperApi.esm.js +55 -0
- package/dist/apis/PluginWrapperApi/DefaultPluginWrapperApi.esm.js.map +1 -0
- package/dist/extensions/AppNav.esm.js +5 -0
- package/dist/extensions/AppNav.esm.js.map +1 -1
- package/dist/extensions/AppRoot.esm.js +19 -1
- package/dist/extensions/AppRoot.esm.js.map +1 -1
- package/dist/extensions/AppThemeApi.esm.js +14 -3
- package/dist/extensions/AppThemeApi.esm.js.map +1 -1
- package/dist/extensions/IconsApi.esm.js +14 -3
- package/dist/extensions/IconsApi.esm.js.map +1 -1
- package/dist/extensions/PluginWrapperApi.esm.js +29 -0
- package/dist/extensions/PluginWrapperApi.esm.js.map +1 -0
- package/dist/extensions/TranslationsApi.esm.js +17 -6
- package/dist/extensions/TranslationsApi.esm.js.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/plugin.esm.js +2 -0
- package/dist/plugin.esm.js.map +1 -1
- package/dist/plugins/app/package.json.esm.js +4 -2
- package/dist/plugins/app/package.json.esm.js.map +1 -1
- package/package.json +17 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @backstage/plugin-app
|
|
2
2
|
|
|
3
|
+
## 0.3.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4554a4e: Implemented support for the new `PluginWrapperBlueprint` from `@backstage/frontend-plugin-api/alpha`.
|
|
8
|
+
- 9ccf84e: The following blueprints are being restricted to only be used in app plugin overrides and modules. They will now produce a deprecation warning when used outside of the app plugin:
|
|
9
|
+
|
|
10
|
+
- `AppRootWrapperBlueprint`
|
|
11
|
+
- `IconBundleBlueprint`
|
|
12
|
+
- `NavContentBlueprint`
|
|
13
|
+
- `RouterBlueprint`
|
|
14
|
+
- `SignInPageBlueprint`
|
|
15
|
+
- `SwappableComponentBlueprint`
|
|
16
|
+
- `ThemeBlueprint`
|
|
17
|
+
- `TranslationBlueprint`
|
|
18
|
+
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
- @backstage/frontend-plugin-api@0.13.3
|
|
21
|
+
- @backstage/plugin-app-react@0.1.0
|
|
22
|
+
- @backstage/core-components@0.18.5
|
|
23
|
+
- @backstage/integration-react@1.2.14
|
|
24
|
+
|
|
25
|
+
## 0.3.4-next.1
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Updated dependencies
|
|
30
|
+
- @backstage/core-components@0.18.5-next.0
|
|
31
|
+
- @backstage/integration-react@1.2.14-next.0
|
|
32
|
+
|
|
3
33
|
## 0.3.4-next.0
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
3
|
+
|
|
4
|
+
class DefaultPluginWrapperApi {
|
|
5
|
+
constructor(pluginWrappers) {
|
|
6
|
+
this.pluginWrappers = pluginWrappers;
|
|
7
|
+
}
|
|
8
|
+
getPluginWrapper(pluginId) {
|
|
9
|
+
return this.pluginWrappers.get(pluginId);
|
|
10
|
+
}
|
|
11
|
+
static fromWrappers(wrappers) {
|
|
12
|
+
const loadersByPlugin = /* @__PURE__ */ new Map();
|
|
13
|
+
for (const wrapper of wrappers) {
|
|
14
|
+
let loaders = loadersByPlugin.get(wrapper.pluginId);
|
|
15
|
+
if (!loaders) {
|
|
16
|
+
loaders = [];
|
|
17
|
+
loadersByPlugin.set(wrapper.pluginId, loaders);
|
|
18
|
+
}
|
|
19
|
+
loaders.push(wrapper.loader);
|
|
20
|
+
}
|
|
21
|
+
const composedWrappers = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const [pluginId, loaders] of loadersByPlugin) {
|
|
23
|
+
if (loaders.length === 0) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const ComposedWrapper = (props) => {
|
|
27
|
+
const [loadedWrappers, setLoadedWrappers] = useState(void 0);
|
|
28
|
+
const [error, setError] = useState(void 0);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
Promise.all(loaders.map((loader) => loader())).then((results) => {
|
|
31
|
+
setLoadedWrappers(results.map((r) => r.component));
|
|
32
|
+
}).catch(setError);
|
|
33
|
+
}, []);
|
|
34
|
+
if (error) {
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
return useMemo(() => {
|
|
38
|
+
if (!loadedWrappers) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
let current = props.children;
|
|
42
|
+
for (const Wrapper of loadedWrappers) {
|
|
43
|
+
current = /* @__PURE__ */ jsx(Wrapper, { children: current });
|
|
44
|
+
}
|
|
45
|
+
return current;
|
|
46
|
+
}, [loadedWrappers, props.children]);
|
|
47
|
+
};
|
|
48
|
+
composedWrappers.set(pluginId, ComposedWrapper);
|
|
49
|
+
}
|
|
50
|
+
return new DefaultPluginWrapperApi(composedWrappers);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { DefaultPluginWrapperApi };
|
|
55
|
+
//# sourceMappingURL=DefaultPluginWrapperApi.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultPluginWrapperApi.esm.js","sources":["../../../src/apis/PluginWrapperApi/DefaultPluginWrapperApi.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PluginWrapperApi } from '@backstage/frontend-plugin-api/alpha';\nimport { ComponentType, ReactNode, useEffect, useMemo, useState } from 'react';\n\ntype WrapperInput = {\n loader: () => Promise<{ component: ComponentType<{ children: ReactNode }> }>;\n pluginId: string;\n};\n\n/**\n * Default implementation of PluginWrapperApi.\n *\n * @internal\n */\nexport class DefaultPluginWrapperApi implements PluginWrapperApi {\n constructor(\n private readonly pluginWrappers: Map<\n string,\n ComponentType<{ children: ReactNode }>\n >,\n ) {}\n\n getPluginWrapper(\n pluginId: string,\n ): ComponentType<{ children: ReactNode }> | undefined {\n return this.pluginWrappers.get(pluginId);\n }\n\n static fromWrappers(wrappers: Array<WrapperInput>): DefaultPluginWrapperApi {\n const loadersByPlugin = new Map<\n string,\n Array<\n () => Promise<{ component: ComponentType<{ children: ReactNode }> }>\n >\n >();\n\n for (const wrapper of wrappers) {\n let loaders = loadersByPlugin.get(wrapper.pluginId);\n if (!loaders) {\n loaders = [];\n loadersByPlugin.set(wrapper.pluginId, loaders);\n }\n loaders.push(wrapper.loader);\n }\n\n const composedWrappers = new Map<\n string,\n ComponentType<{ children: ReactNode }>\n >();\n\n for (const [pluginId, loaders] of loadersByPlugin) {\n if (loaders.length === 0) {\n continue;\n }\n\n const ComposedWrapper = (props: { children: ReactNode }) => {\n const [loadedWrappers, setLoadedWrappers] = useState<\n Array<ComponentType<{ children: ReactNode }>> | undefined\n >(undefined);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n useEffect(() => {\n Promise.all(loaders.map(loader => loader()))\n .then(results => {\n setLoadedWrappers(results.map(r => r.component));\n })\n .catch(setError);\n }, []);\n\n if (error) {\n throw error;\n }\n\n return useMemo(() => {\n if (!loadedWrappers) {\n return null;\n }\n\n let current = props.children;\n\n for (const Wrapper of loadedWrappers) {\n current = <Wrapper>{current}</Wrapper>;\n }\n\n return current;\n }, [loadedWrappers, props.children]);\n };\n\n composedWrappers.set(pluginId, ComposedWrapper);\n }\n\n return new DefaultPluginWrapperApi(composedWrappers);\n }\n}\n"],"names":[],"mappings":";;;AA6BO,MAAM,uBAAA,CAAoD;AAAA,EAC/D,YACmB,cAAA,EAIjB;AAJiB,IAAA,IAAA,CAAA,cAAA,GAAA,cAAA;AAAA,EAIhB;AAAA,EAEH,iBACE,QAAA,EACoD;AACpD,IAAA,OAAO,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,QAAQ,CAAA;AAAA,EACzC;AAAA,EAEA,OAAO,aAAa,QAAA,EAAwD;AAC1E,IAAA,MAAM,eAAA,uBAAsB,GAAA,EAK1B;AAEF,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,IAAI,OAAA,GAAU,eAAA,CAAgB,GAAA,CAAI,OAAA,CAAQ,QAAQ,CAAA;AAClD,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,OAAA,GAAU,EAAC;AACX,QAAA,eAAA,CAAgB,GAAA,CAAI,OAAA,CAAQ,QAAA,EAAU,OAAO,CAAA;AAAA,MAC/C;AACA,MAAA,OAAA,CAAQ,IAAA,CAAK,QAAQ,MAAM,CAAA;AAAA,IAC7B;AAEA,IAAA,MAAM,gBAAA,uBAAuB,GAAA,EAG3B;AAEF,IAAA,KAAA,MAAW,CAAC,QAAA,EAAU,OAAO,CAAA,IAAK,eAAA,EAAiB;AACjD,MAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,eAAA,GAAkB,CAAC,KAAA,KAAmC;AAC1D,QAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAE1C,MAAS,CAAA;AACX,QAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAA4B,MAAS,CAAA;AAE/D,QAAA,SAAA,CAAU,MAAM;AACd,UAAA,OAAA,CAAQ,GAAA,CAAI,QAAQ,GAAA,CAAI,CAAA,MAAA,KAAU,QAAQ,CAAC,CAAA,CACxC,IAAA,CAAK,CAAA,OAAA,KAAW;AACf,YAAA,iBAAA,CAAkB,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,SAAS,CAAC,CAAA;AAAA,UACjD,CAAC,CAAA,CACA,KAAA,CAAM,QAAQ,CAAA;AAAA,QACnB,CAAA,EAAG,EAAE,CAAA;AAEL,QAAA,IAAI,KAAA,EAAO;AACT,UAAA,MAAM,KAAA;AAAA,QACR;AAEA,QAAA,OAAO,QAAQ,MAAM;AACnB,UAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,YAAA,OAAO,IAAA;AAAA,UACT;AAEA,UAAA,IAAI,UAAU,KAAA,CAAM,QAAA;AAEpB,UAAA,KAAA,MAAW,WAAW,cAAA,EAAgB;AACpC,YAAA,OAAA,mBAAU,GAAA,CAAC,WAAS,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,UAC9B;AAEA,UAAA,OAAO,OAAA;AAAA,QACT,CAAA,EAAG,CAAC,cAAA,EAAgB,KAAA,CAAM,QAAQ,CAAC,CAAA;AAAA,MACrC,CAAA;AAEA,MAAA,gBAAA,CAAiB,GAAA,CAAI,UAAU,eAAe,CAAA;AAAA,IAChD;AAEA,IAAA,OAAO,IAAI,wBAAwB,gBAAgB,CAAA;AAAA,EACrD;AACF;;;;"}
|
|
@@ -50,6 +50,11 @@ const AppNav = createExtension({
|
|
|
50
50
|
},
|
|
51
51
|
output: [coreExtensionData.reactElement],
|
|
52
52
|
*factory({ inputs }) {
|
|
53
|
+
if (inputs.content && inputs.content.node.spec.plugin?.id !== "app") {
|
|
54
|
+
console.warn(
|
|
55
|
+
`DEPRECATION WARNING: NavContent should only be installed as an extension in the app plugin. You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${inputs.content.node.spec.id}`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
53
58
|
const Content = inputs.content?.get(NavContentBlueprint.dataRefs.component) ?? DefaultNavContent;
|
|
54
59
|
yield coreExtensionData.reactElement(
|
|
55
60
|
/* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppNav.esm.js","sources":["../../src/extensions/AppNav.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createExtension,\n coreExtensionData,\n createExtensionInput,\n NavItemBlueprint,\n NavContentBlueprint,\n NavContentComponentProps,\n routeResolutionApiRef,\n IconComponent,\n RouteRef,\n useApi,\n NavContentComponent,\n} from '@backstage/frontend-plugin-api';\nimport { Sidebar, SidebarItem } from '@backstage/core-components';\nimport { useMemo } from 'react';\n\nfunction DefaultNavContent(props: NavContentComponentProps) {\n return (\n <Sidebar>\n {props.items.map((item, index) => (\n <SidebarItem\n to={item.to}\n icon={item.icon}\n text={item.text}\n key={index}\n />\n ))}\n </Sidebar>\n );\n}\n\n// This helps defer rendering until the app is being rendered, which is needed\n// because the RouteResolutionApi can't be called until the app has been fully initialized.\nfunction NavContentRenderer(props: {\n Content: NavContentComponent;\n items: Array<{\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n }>;\n}) {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const items = useMemo(() => {\n return props.items.flatMap(item => {\n const link = routeResolutionApi.resolve(item.routeRef);\n if (!link) {\n // eslint-disable-next-line no-console\n console.warn(\n `NavItemBlueprint: unable to resolve route ref ${item.routeRef}`,\n );\n return [];\n }\n return [\n {\n to: link(),\n text: item.title,\n icon: item.icon,\n title: item.title,\n routeRef: item.routeRef,\n },\n ];\n });\n }, [props.items, routeResolutionApi]);\n\n return <props.Content items={items} />;\n}\n\nexport const AppNav = createExtension({\n name: 'nav',\n attachTo: { id: 'app/layout', input: 'nav' },\n inputs: {\n items: createExtensionInput([NavItemBlueprint.dataRefs.target]),\n content: createExtensionInput([NavContentBlueprint.dataRefs.component], {\n singleton: true,\n optional: true,\n }),\n },\n output: [coreExtensionData.reactElement],\n *factory({ inputs }) {\n const Content =\n inputs.content?.get(NavContentBlueprint.dataRefs.component) ??\n DefaultNavContent;\n\n yield coreExtensionData.reactElement(\n <NavContentRenderer\n items={inputs.items.map(item =>\n item.get(NavItemBlueprint.dataRefs.target),\n )}\n Content={Content}\n />,\n );\n },\n});\n"],"names":[],"mappings":";;;;;AAgCA,SAAS,kBAAkB,KAAA,EAAiC;AAC1D,EAAA,2BACG,OAAA,EAAA,EACE,QAAA,EAAA,KAAA,CAAM,MAAM,GAAA,CAAI,CAAC,MAAM,KAAA,qBACtB,GAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,MAAM,IAAA,CAAK;AAAA,KAAA;AAAA,IACN;AAAA,GAER,CAAA,EACH,CAAA;AAEJ;AAIA,SAAS,mBAAmB,KAAA,EAOzB;AACD,EAAA,MAAM,kBAAA,GAAqB,OAAO,qBAAqB,CAAA;AAEvD,EAAA,MAAM,KAAA,GAAQ,QAAQ,MAAM;AAC1B,IAAA,OAAO,KAAA,CAAM,KAAA,CAAM,OAAA,CAAQ,CAAA,IAAA,KAAQ;AACjC,MAAA,MAAM,IAAA,GAAO,kBAAA,CAAmB,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA;AACrD,MAAA,IAAI,CAAC,IAAA,EAAM;AAET,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,CAAA,8CAAA,EAAiD,KAAK,QAAQ,CAAA;AAAA,SAChE;AACA,QAAA,OAAO,EAAC;AAAA,MACV;AACA,MAAA,OAAO;AAAA,QACL;AAAA,UACE,IAAI,IAAA,EAAK;AAAA,UACT,MAAM,IAAA,CAAK,KAAA;AAAA,UACX,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,UAAU,IAAA,CAAK;AAAA;AACjB,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAA,CAAM,KAAA,EAAO,kBAAkB,CAAC,CAAA;AAEpC,EAAA,uBAAO,GAAA,CAAC,KAAA,CAAM,OAAA,EAAN,EAAc,KAAA,EAAc,CAAA;AACtC;AAEO,MAAM,SAAS,eAAA,CAAgB;AAAA,EACpC,IAAA,EAAM,KAAA;AAAA,EACN,QAAA,EAAU,EAAE,EAAA,EAAI,YAAA,EAAc,OAAO,KAAA,EAAM;AAAA,EAC3C,MAAA,EAAQ;AAAA,IACN,OAAO,oBAAA,CAAqB,CAAC,gBAAA,CAAiB,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,IAC9D,SAAS,oBAAA,CAAqB,CAAC,mBAAA,CAAoB,QAAA,CAAS,SAAS,CAAA,EAAG;AAAA,MACtE,SAAA,EAAW,IAAA;AAAA,MACX,QAAA,EAAU;AAAA,KACX;AAAA,GACH;AAAA,EACA,MAAA,EAAQ,CAAC,iBAAA,CAAkB,YAAY,CAAA;AAAA,EACvC,CAAC,OAAA,CAAQ,EAAE,MAAA,EAAO,EAAG;AACnB,IAAA,MAAM,UACJ,MAAA,CAAO,OAAA,EAAS,IAAI,mBAAA,CAAoB,QAAA,CAAS,SAAS,CAAA,IAC1D,iBAAA;AAEF,IAAA,MAAM,iBAAA,CAAkB,YAAA;AAAA,sBACtB,GAAA;AAAA,QAAC,kBAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,OAAO,KAAA,CAAM,GAAA;AAAA,YAAI,CAAA,IAAA,KACtB,IAAA,CAAK,GAAA,CAAI,gBAAA,CAAiB,SAAS,MAAM;AAAA,WAC3C;AAAA,UACA;AAAA;AAAA;AACF,KACF;AAAA,EACF;AACF,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"AppNav.esm.js","sources":["../../src/extensions/AppNav.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createExtension,\n coreExtensionData,\n createExtensionInput,\n NavItemBlueprint,\n NavContentBlueprint,\n NavContentComponentProps,\n routeResolutionApiRef,\n IconComponent,\n RouteRef,\n useApi,\n NavContentComponent,\n} from '@backstage/frontend-plugin-api';\nimport { Sidebar, SidebarItem } from '@backstage/core-components';\nimport { useMemo } from 'react';\n\nfunction DefaultNavContent(props: NavContentComponentProps) {\n return (\n <Sidebar>\n {props.items.map((item, index) => (\n <SidebarItem\n to={item.to}\n icon={item.icon}\n text={item.text}\n key={index}\n />\n ))}\n </Sidebar>\n );\n}\n\n// This helps defer rendering until the app is being rendered, which is needed\n// because the RouteResolutionApi can't be called until the app has been fully initialized.\nfunction NavContentRenderer(props: {\n Content: NavContentComponent;\n items: Array<{\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n }>;\n}) {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const items = useMemo(() => {\n return props.items.flatMap(item => {\n const link = routeResolutionApi.resolve(item.routeRef);\n if (!link) {\n // eslint-disable-next-line no-console\n console.warn(\n `NavItemBlueprint: unable to resolve route ref ${item.routeRef}`,\n );\n return [];\n }\n return [\n {\n to: link(),\n text: item.title,\n icon: item.icon,\n title: item.title,\n routeRef: item.routeRef,\n },\n ];\n });\n }, [props.items, routeResolutionApi]);\n\n return <props.Content items={items} />;\n}\n\nexport const AppNav = createExtension({\n name: 'nav',\n attachTo: { id: 'app/layout', input: 'nav' },\n inputs: {\n items: createExtensionInput([NavItemBlueprint.dataRefs.target]),\n content: createExtensionInput([NavContentBlueprint.dataRefs.component], {\n singleton: true,\n optional: true,\n }),\n },\n output: [coreExtensionData.reactElement],\n *factory({ inputs }) {\n if (inputs.content && inputs.content.node.spec.plugin?.id !== 'app') {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: NavContent should only be installed as an extension in the app plugin. ` +\n `You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${inputs.content.node.spec.id}`,\n );\n }\n\n const Content =\n inputs.content?.get(NavContentBlueprint.dataRefs.component) ??\n DefaultNavContent;\n\n yield coreExtensionData.reactElement(\n <NavContentRenderer\n items={inputs.items.map(item =>\n item.get(NavItemBlueprint.dataRefs.target),\n )}\n Content={Content}\n />,\n );\n },\n});\n"],"names":[],"mappings":";;;;;AAgCA,SAAS,kBAAkB,KAAA,EAAiC;AAC1D,EAAA,2BACG,OAAA,EAAA,EACE,QAAA,EAAA,KAAA,CAAM,MAAM,GAAA,CAAI,CAAC,MAAM,KAAA,qBACtB,GAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,MAAM,IAAA,CAAK;AAAA,KAAA;AAAA,IACN;AAAA,GAER,CAAA,EACH,CAAA;AAEJ;AAIA,SAAS,mBAAmB,KAAA,EAOzB;AACD,EAAA,MAAM,kBAAA,GAAqB,OAAO,qBAAqB,CAAA;AAEvD,EAAA,MAAM,KAAA,GAAQ,QAAQ,MAAM;AAC1B,IAAA,OAAO,KAAA,CAAM,KAAA,CAAM,OAAA,CAAQ,CAAA,IAAA,KAAQ;AACjC,MAAA,MAAM,IAAA,GAAO,kBAAA,CAAmB,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA;AACrD,MAAA,IAAI,CAAC,IAAA,EAAM;AAET,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,CAAA,8CAAA,EAAiD,KAAK,QAAQ,CAAA;AAAA,SAChE;AACA,QAAA,OAAO,EAAC;AAAA,MACV;AACA,MAAA,OAAO;AAAA,QACL;AAAA,UACE,IAAI,IAAA,EAAK;AAAA,UACT,MAAM,IAAA,CAAK,KAAA;AAAA,UACX,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,UAAU,IAAA,CAAK;AAAA;AACjB,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAA,CAAM,KAAA,EAAO,kBAAkB,CAAC,CAAA;AAEpC,EAAA,uBAAO,GAAA,CAAC,KAAA,CAAM,OAAA,EAAN,EAAc,KAAA,EAAc,CAAA;AACtC;AAEO,MAAM,SAAS,eAAA,CAAgB;AAAA,EACpC,IAAA,EAAM,KAAA;AAAA,EACN,QAAA,EAAU,EAAE,EAAA,EAAI,YAAA,EAAc,OAAO,KAAA,EAAM;AAAA,EAC3C,MAAA,EAAQ;AAAA,IACN,OAAO,oBAAA,CAAqB,CAAC,gBAAA,CAAiB,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,IAC9D,SAAS,oBAAA,CAAqB,CAAC,mBAAA,CAAoB,QAAA,CAAS,SAAS,CAAA,EAAG;AAAA,MACtE,SAAA,EAAW,IAAA;AAAA,MACX,QAAA,EAAU;AAAA,KACX;AAAA,GACH;AAAA,EACA,MAAA,EAAQ,CAAC,iBAAA,CAAkB,YAAY,CAAA;AAAA,EACvC,CAAC,OAAA,CAAQ,EAAE,MAAA,EAAO,EAAG;AACnB,IAAA,IAAI,MAAA,CAAO,WAAW,MAAA,CAAO,OAAA,CAAQ,KAAK,IAAA,CAAK,MAAA,EAAQ,OAAO,KAAA,EAAO;AAEnE,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,4NAAA,EACqI,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,EAAE,CAAA;AAAA,OAClK;AAAA,IACF;AAEA,IAAA,MAAM,UACJ,MAAA,CAAO,OAAA,EAAS,IAAI,mBAAA,CAAoB,QAAA,CAAS,SAAS,CAAA,IAC1D,iBAAA;AAEF,IAAA,MAAM,iBAAA,CAAkB,YAAA;AAAA,sBACtB,GAAA;AAAA,QAAC,kBAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,OAAO,KAAA,CAAM,GAAA;AAAA,YAAI,CAAA,IAAA,KACtB,IAAA,CAAK,GAAA,CAAI,gBAAA,CAAiB,SAAS,MAAM;AAAA,WAC3C;AAAA,UACA;AAAA;AAAA;AACF,KACF;AAAA,EACF;AACF,CAAC;;;;"}
|
|
@@ -29,6 +29,16 @@ const AppRoot = createExtension({
|
|
|
29
29
|
},
|
|
30
30
|
output: [coreExtensionData.reactElement],
|
|
31
31
|
factory({ inputs, apis }) {
|
|
32
|
+
if (inputs.router && inputs.router.node.spec.plugin?.id !== "app") {
|
|
33
|
+
console.warn(
|
|
34
|
+
`DEPRECATION WARNING: Router should only be installed as an extension in the app plugin. You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${inputs.router.node.spec.id}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
if (inputs.signInPage && inputs.signInPage.node.spec.plugin?.id !== "app") {
|
|
38
|
+
console.warn(
|
|
39
|
+
`DEPRECATION WARNING: SignInPage should only be installed as an extension in the app plugin. You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${inputs.signInPage.node.spec.id}`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
32
42
|
if (isProtectedApp()) {
|
|
33
43
|
const identityApi = apis.get(identityApiRef);
|
|
34
44
|
if (!identityApi) {
|
|
@@ -54,7 +64,15 @@ const AppRoot = createExtension({
|
|
|
54
64
|
);
|
|
55
65
|
for (const wrapper of inputs.wrappers) {
|
|
56
66
|
const Component = wrapper.get(AppRootWrapperBlueprint.dataRefs.component);
|
|
57
|
-
|
|
67
|
+
const pluginId = wrapper.node.spec.plugin.id;
|
|
68
|
+
if (Component) {
|
|
69
|
+
content = /* @__PURE__ */ jsx(Component, { children: content });
|
|
70
|
+
if (pluginId !== "app") {
|
|
71
|
+
console.warn(
|
|
72
|
+
`DEPRECATION WARNING: AppRootWrappers should only be installed as an extension in the app plugin. You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${wrapper.node.spec.id}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
58
76
|
}
|
|
59
77
|
return [
|
|
60
78
|
coreExtensionData.reactElement(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppRoot.esm.js","sources":["../../src/extensions/AppRoot.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ComponentType,\n PropsWithChildren,\n ReactNode,\n useState,\n JSX,\n} from 'react';\nimport {\n AppRootWrapperBlueprint,\n RouterBlueprint,\n SignInPageBlueprint,\n coreExtensionData,\n discoveryApiRef,\n fetchApiRef,\n errorApiRef,\n createExtension,\n createExtensionInput,\n routeResolutionApiRef,\n} from '@backstage/frontend-plugin-api';\nimport {\n DiscoveryApi,\n ErrorApi,\n FetchApi,\n IdentityApi,\n ProfileInfo,\n SignInPageProps,\n configApiRef,\n identityApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { isProtectedApp } from '../../../../packages/core-app-api/src/app/isProtectedApp';\nimport { BrowserRouter } from 'react-router-dom';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { RouteTracker } from '../../../../packages/frontend-app-api/src/routing/RouteTracker';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { getBasePath } from '../../../../packages/frontend-app-api/src/routing/getBasePath';\n\nexport const AppRoot = createExtension({\n name: 'root',\n attachTo: { id: 'app', input: 'root' },\n inputs: {\n router: createExtensionInput([RouterBlueprint.dataRefs.component], {\n singleton: true,\n optional: true,\n }),\n signInPage: createExtensionInput([SignInPageBlueprint.dataRefs.component], {\n singleton: true,\n optional: true,\n }),\n children: createExtensionInput([coreExtensionData.reactElement], {\n singleton: true,\n }),\n elements: createExtensionInput([coreExtensionData.reactElement]),\n wrappers: createExtensionInput([\n AppRootWrapperBlueprint.dataRefs.component,\n ]),\n },\n output: [coreExtensionData.reactElement],\n factory({ inputs, apis }) {\n if (isProtectedApp()) {\n const identityApi = apis.get(identityApiRef);\n if (!identityApi) {\n throw new Error('App requires an Identity API implementation');\n }\n const appIdentityProxy = toAppIdentityProxy(identityApi);\n const discoveryApi = apis.get(discoveryApiRef);\n const errorApi = apis.get(errorApiRef);\n const fetchApi = apis.get(fetchApiRef);\n if (!discoveryApi || !errorApi || !fetchApi) {\n throw new Error(\n 'App is running in protected mode but missing required APIs',\n );\n }\n appIdentityProxy.enableCookieAuth({\n discoveryApi,\n errorApi,\n fetchApi,\n });\n }\n\n let content: ReactNode = inputs.children.get(\n coreExtensionData.reactElement,\n );\n\n for (const wrapper of inputs.wrappers) {\n const Component = wrapper.get(AppRootWrapperBlueprint.dataRefs.component);\n content = <Component>{content}</Component>;\n }\n\n return [\n coreExtensionData.reactElement(\n <AppRouter\n SignInPageComponent={inputs.signInPage?.get(\n SignInPageBlueprint.dataRefs.component,\n )}\n RouterComponent={inputs.router?.get(\n RouterBlueprint.dataRefs.component,\n )}\n extraElements={inputs.elements?.map(el =>\n el.get(coreExtensionData.reactElement),\n )}\n >\n {content}\n </AppRouter>,\n ),\n ];\n },\n});\n\n// This wraps the sign-in page and waits for sign-in to be completed before rendering the app\nfunction SignInPageWrapper({\n component: Component,\n appIdentityProxy,\n children,\n}: {\n component: ComponentType<SignInPageProps>;\n appIdentityProxy: AppIdentityProxy;\n children: ReactNode;\n}) {\n const [identityApi, setIdentityApi] = useState<IdentityApi>();\n const configApi = useApi(configApiRef);\n const basePath = getBasePath(configApi);\n\n if (!identityApi) {\n return <Component onSignInSuccess={setIdentityApi} />;\n }\n\n appIdentityProxy.setTarget(identityApi, {\n signOutTargetUrl: basePath || '/',\n });\n return <>{children}</>;\n}\n\ntype AppIdentityProxy = IdentityApi & {\n enableCookieAuth(ctx: {\n errorApi: ErrorApi;\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n }): void;\n setTarget(\n impl: IdentityApi & /* backwards compat stuff */ {\n getUserId?(): string;\n getIdToken?(): Promise<string | undefined>;\n getProfile?(): ProfileInfo;\n },\n options: { signOutTargetUrl: string },\n ): void;\n};\n\nfunction toAppIdentityProxy(identityApi: IdentityApi): AppIdentityProxy {\n if (!('enableCookieAuth' in identityApi)) {\n throw new Error('Unexpected Identity API implementation');\n }\n return identityApi as AppIdentityProxy;\n}\n\ntype RouteResolverProxy = {\n getRouteObjects(): any[];\n};\n\n/**\n * Props for the {@link AppRouter} component.\n * @public\n */\nexport interface AppRouterProps {\n children?: ReactNode;\n SignInPageComponent?: ComponentType<SignInPageProps>;\n RouterComponent?: (props: { children: ReactNode }) => JSX.Element | null;\n extraElements?: Array<JSX.Element>;\n}\n\nfunction DefaultRouter(props: PropsWithChildren<{}>) {\n const configApi = useApi(configApiRef);\n const basePath = getBasePath(configApi);\n return <BrowserRouter basename={basePath}>{props.children}</BrowserRouter>;\n}\n\n/**\n * App router and sign-in page wrapper.\n *\n * @remarks\n *\n * The AppRouter provides the routing context and renders the sign-in page.\n * Until the user has successfully signed in, this component will render\n * the sign-in page. Once the user has signed-in, it will instead render\n * the app, while providing routing and route tracking for the app.\n */\nexport function AppRouter(props: AppRouterProps) {\n const {\n children,\n SignInPageComponent,\n RouterComponent = DefaultRouter,\n extraElements = [],\n } = props;\n\n const configApi = useApi(configApiRef);\n const appIdentityProxy = toAppIdentityProxy(useApi(identityApiRef));\n const routeResolutionsApi = useApi(routeResolutionApiRef);\n const basePath = getBasePath(configApi);\n\n // TODO: Private access for now, probably replace with path -> node lookup method on the API\n if (!('getRouteObjects' in routeResolutionsApi)) {\n throw new Error('Unexpected route resolution API implementation');\n }\n const routeObjects = (\n routeResolutionsApi as RouteResolverProxy\n ).getRouteObjects();\n\n // If the app hasn't configured a sign-in page, we just continue as guest.\n if (!SignInPageComponent) {\n appIdentityProxy.setTarget(\n {\n getUserId: () => 'guest',\n getIdToken: async () => undefined,\n getProfile: () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getProfileInfo: async () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getBackstageIdentity: async () => ({\n type: 'user',\n userEntityRef: 'user:default/guest',\n ownershipEntityRefs: ['user:default/guest'],\n }),\n getCredentials: async () => ({}),\n signOut: async () => {},\n },\n { signOutTargetUrl: basePath || '/' },\n );\n\n return (\n <RouterComponent>\n {...extraElements}\n <RouteTracker routeObjects={routeObjects} />\n {children}\n </RouterComponent>\n );\n }\n\n return (\n <RouterComponent>\n {...extraElements}\n <RouteTracker routeObjects={routeObjects} />\n <SignInPageWrapper\n component={SignInPageComponent}\n appIdentityProxy={appIdentityProxy}\n >\n {children}\n </SignInPageWrapper>\n </RouterComponent>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AppRoot.esm.js","sources":["../../src/extensions/AppRoot.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ComponentType,\n PropsWithChildren,\n ReactNode,\n useState,\n JSX,\n} from 'react';\nimport {\n AppRootWrapperBlueprint,\n RouterBlueprint,\n SignInPageBlueprint,\n coreExtensionData,\n discoveryApiRef,\n fetchApiRef,\n errorApiRef,\n createExtension,\n createExtensionInput,\n routeResolutionApiRef,\n} from '@backstage/frontend-plugin-api';\nimport {\n DiscoveryApi,\n ErrorApi,\n FetchApi,\n IdentityApi,\n ProfileInfo,\n SignInPageProps,\n configApiRef,\n identityApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { isProtectedApp } from '../../../../packages/core-app-api/src/app/isProtectedApp';\nimport { BrowserRouter } from 'react-router-dom';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { RouteTracker } from '../../../../packages/frontend-app-api/src/routing/RouteTracker';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { getBasePath } from '../../../../packages/frontend-app-api/src/routing/getBasePath';\n\nexport const AppRoot = createExtension({\n name: 'root',\n attachTo: { id: 'app', input: 'root' },\n inputs: {\n router: createExtensionInput([RouterBlueprint.dataRefs.component], {\n singleton: true,\n optional: true,\n }),\n signInPage: createExtensionInput([SignInPageBlueprint.dataRefs.component], {\n singleton: true,\n optional: true,\n }),\n children: createExtensionInput([coreExtensionData.reactElement], {\n singleton: true,\n }),\n elements: createExtensionInput([coreExtensionData.reactElement]),\n wrappers: createExtensionInput([\n AppRootWrapperBlueprint.dataRefs.component,\n ]),\n },\n output: [coreExtensionData.reactElement],\n factory({ inputs, apis }) {\n if (inputs.router && inputs.router.node.spec.plugin?.id !== 'app') {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: Router should only be installed as an extension in the app plugin. ` +\n `You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${inputs.router.node.spec.id}`,\n );\n }\n\n if (inputs.signInPage && inputs.signInPage.node.spec.plugin?.id !== 'app') {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: SignInPage should only be installed as an extension in the app plugin. ` +\n `You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${inputs.signInPage.node.spec.id}`,\n );\n }\n\n if (isProtectedApp()) {\n const identityApi = apis.get(identityApiRef);\n if (!identityApi) {\n throw new Error('App requires an Identity API implementation');\n }\n const appIdentityProxy = toAppIdentityProxy(identityApi);\n const discoveryApi = apis.get(discoveryApiRef);\n const errorApi = apis.get(errorApiRef);\n const fetchApi = apis.get(fetchApiRef);\n if (!discoveryApi || !errorApi || !fetchApi) {\n throw new Error(\n 'App is running in protected mode but missing required APIs',\n );\n }\n appIdentityProxy.enableCookieAuth({\n discoveryApi,\n errorApi,\n fetchApi,\n });\n }\n\n let content: ReactNode = inputs.children.get(\n coreExtensionData.reactElement,\n );\n\n for (const wrapper of inputs.wrappers) {\n const Component = wrapper.get(AppRootWrapperBlueprint.dataRefs.component);\n const pluginId = wrapper.node.spec.plugin.id;\n if (Component) {\n content = <Component>{content}</Component>;\n if (pluginId !== 'app') {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: AppRootWrappers should only be installed as an extension in the app plugin. ` +\n `You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${wrapper.node.spec.id}`,\n );\n }\n }\n }\n\n return [\n coreExtensionData.reactElement(\n <AppRouter\n SignInPageComponent={inputs.signInPage?.get(\n SignInPageBlueprint.dataRefs.component,\n )}\n RouterComponent={inputs.router?.get(\n RouterBlueprint.dataRefs.component,\n )}\n extraElements={inputs.elements?.map(el =>\n el.get(coreExtensionData.reactElement),\n )}\n >\n {content}\n </AppRouter>,\n ),\n ];\n },\n});\n\n// This wraps the sign-in page and waits for sign-in to be completed before rendering the app\nfunction SignInPageWrapper({\n component: Component,\n appIdentityProxy,\n children,\n}: {\n component: ComponentType<SignInPageProps>;\n appIdentityProxy: AppIdentityProxy;\n children: ReactNode;\n}) {\n const [identityApi, setIdentityApi] = useState<IdentityApi>();\n const configApi = useApi(configApiRef);\n const basePath = getBasePath(configApi);\n\n if (!identityApi) {\n return <Component onSignInSuccess={setIdentityApi} />;\n }\n\n appIdentityProxy.setTarget(identityApi, {\n signOutTargetUrl: basePath || '/',\n });\n return <>{children}</>;\n}\n\ntype AppIdentityProxy = IdentityApi & {\n enableCookieAuth(ctx: {\n errorApi: ErrorApi;\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n }): void;\n setTarget(\n impl: IdentityApi & /* backwards compat stuff */ {\n getUserId?(): string;\n getIdToken?(): Promise<string | undefined>;\n getProfile?(): ProfileInfo;\n },\n options: { signOutTargetUrl: string },\n ): void;\n};\n\nfunction toAppIdentityProxy(identityApi: IdentityApi): AppIdentityProxy {\n if (!('enableCookieAuth' in identityApi)) {\n throw new Error('Unexpected Identity API implementation');\n }\n return identityApi as AppIdentityProxy;\n}\n\ntype RouteResolverProxy = {\n getRouteObjects(): any[];\n};\n\n/**\n * Props for the {@link AppRouter} component.\n * @public\n */\nexport interface AppRouterProps {\n children?: ReactNode;\n SignInPageComponent?: ComponentType<SignInPageProps>;\n RouterComponent?: (props: { children: ReactNode }) => JSX.Element | null;\n extraElements?: Array<JSX.Element>;\n}\n\nfunction DefaultRouter(props: PropsWithChildren<{}>) {\n const configApi = useApi(configApiRef);\n const basePath = getBasePath(configApi);\n return <BrowserRouter basename={basePath}>{props.children}</BrowserRouter>;\n}\n\n/**\n * App router and sign-in page wrapper.\n *\n * @remarks\n *\n * The AppRouter provides the routing context and renders the sign-in page.\n * Until the user has successfully signed in, this component will render\n * the sign-in page. Once the user has signed-in, it will instead render\n * the app, while providing routing and route tracking for the app.\n */\nexport function AppRouter(props: AppRouterProps) {\n const {\n children,\n SignInPageComponent,\n RouterComponent = DefaultRouter,\n extraElements = [],\n } = props;\n\n const configApi = useApi(configApiRef);\n const appIdentityProxy = toAppIdentityProxy(useApi(identityApiRef));\n const routeResolutionsApi = useApi(routeResolutionApiRef);\n const basePath = getBasePath(configApi);\n\n // TODO: Private access for now, probably replace with path -> node lookup method on the API\n if (!('getRouteObjects' in routeResolutionsApi)) {\n throw new Error('Unexpected route resolution API implementation');\n }\n const routeObjects = (\n routeResolutionsApi as RouteResolverProxy\n ).getRouteObjects();\n\n // If the app hasn't configured a sign-in page, we just continue as guest.\n if (!SignInPageComponent) {\n appIdentityProxy.setTarget(\n {\n getUserId: () => 'guest',\n getIdToken: async () => undefined,\n getProfile: () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getProfileInfo: async () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getBackstageIdentity: async () => ({\n type: 'user',\n userEntityRef: 'user:default/guest',\n ownershipEntityRefs: ['user:default/guest'],\n }),\n getCredentials: async () => ({}),\n signOut: async () => {},\n },\n { signOutTargetUrl: basePath || '/' },\n );\n\n return (\n <RouterComponent>\n {...extraElements}\n <RouteTracker routeObjects={routeObjects} />\n {children}\n </RouterComponent>\n );\n }\n\n return (\n <RouterComponent>\n {...extraElements}\n <RouteTracker routeObjects={routeObjects} />\n <SignInPageWrapper\n component={SignInPageComponent}\n appIdentityProxy={appIdentityProxy}\n >\n {children}\n </SignInPageWrapper>\n </RouterComponent>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -21,9 +21,20 @@ const AppThemeApi = ApiBlueprint.makeWithOverrides({
|
|
|
21
21
|
(defineParams) => defineParams({
|
|
22
22
|
api: appThemeApiRef,
|
|
23
23
|
deps: {},
|
|
24
|
-
factory: () =>
|
|
25
|
-
inputs.themes.
|
|
26
|
-
|
|
24
|
+
factory: () => {
|
|
25
|
+
const nonAppExtensions = inputs.themes.filter(
|
|
26
|
+
(i) => i.node.spec.plugin?.id !== "app"
|
|
27
|
+
);
|
|
28
|
+
if (nonAppExtensions.length > 0) {
|
|
29
|
+
const list = nonAppExtensions.map((i) => i.node.spec.id).join(", ");
|
|
30
|
+
console.warn(
|
|
31
|
+
`DEPRECATION WARNING: Theme should only be installed as an extension in the app plugin. You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${list}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return AppThemeSelector.createWithStorage(
|
|
35
|
+
inputs.themes.map((i) => i.get(ThemeBlueprint.dataRefs.theme))
|
|
36
|
+
);
|
|
37
|
+
}
|
|
27
38
|
})
|
|
28
39
|
);
|
|
29
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppThemeApi.esm.js","sources":["../../src/extensions/AppThemeApi.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UnifiedThemeProvider,\n themes as builtinThemes,\n} from '@backstage/theme';\nimport DarkIcon from '@material-ui/icons/Brightness2';\nimport LightIcon from '@material-ui/icons/WbSunny';\nimport {\n createExtensionInput,\n ThemeBlueprint,\n ApiBlueprint,\n appThemeApiRef,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppThemeSelector } from '../../../../packages/core-app-api/src/apis/implementations';\n\n/**\n * Contains the themes installed into the app.\n */\nexport const AppThemeApi = ApiBlueprint.makeWithOverrides({\n name: 'app-theme',\n inputs: {\n themes: createExtensionInput([ThemeBlueprint.dataRefs.theme], {\n replaces: [{ id: 'app', input: 'themes' }],\n }),\n },\n factory: (originalFactory, { inputs }) => {\n return originalFactory(defineParams =>\n defineParams({\n api: appThemeApiRef,\n deps: {},\n factory: ()
|
|
1
|
+
{"version":3,"file":"AppThemeApi.esm.js","sources":["../../src/extensions/AppThemeApi.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UnifiedThemeProvider,\n themes as builtinThemes,\n} from '@backstage/theme';\nimport DarkIcon from '@material-ui/icons/Brightness2';\nimport LightIcon from '@material-ui/icons/WbSunny';\nimport {\n createExtensionInput,\n ThemeBlueprint,\n ApiBlueprint,\n appThemeApiRef,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppThemeSelector } from '../../../../packages/core-app-api/src/apis/implementations';\n\n/**\n * Contains the themes installed into the app.\n */\nexport const AppThemeApi = ApiBlueprint.makeWithOverrides({\n name: 'app-theme',\n inputs: {\n themes: createExtensionInput([ThemeBlueprint.dataRefs.theme], {\n replaces: [{ id: 'app', input: 'themes' }],\n }),\n },\n factory: (originalFactory, { inputs }) => {\n return originalFactory(defineParams =>\n defineParams({\n api: appThemeApiRef,\n deps: {},\n factory: () => {\n const nonAppExtensions = inputs.themes.filter(\n i => i.node.spec.plugin?.id !== 'app',\n );\n\n if (nonAppExtensions.length > 0) {\n const list = nonAppExtensions.map(i => i.node.spec.id).join(', ');\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: Theme should only be installed as an extension in the app plugin. ` +\n `You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${list}`,\n );\n }\n\n return AppThemeSelector.createWithStorage(\n inputs.themes.map(i => i.get(ThemeBlueprint.dataRefs.theme)),\n );\n },\n }),\n );\n },\n});\n\nexport const LightTheme = ThemeBlueprint.make({\n name: 'light',\n params: {\n theme: {\n id: 'light',\n title: 'Light Theme',\n variant: 'light',\n icon: <LightIcon />,\n Provider: ({ children }) => (\n <UnifiedThemeProvider theme={builtinThemes.light} children={children} />\n ),\n },\n },\n});\n\nexport const DarkTheme = ThemeBlueprint.make({\n name: 'dark',\n params: {\n theme: {\n id: 'dark',\n title: 'Dark Theme',\n variant: 'dark',\n icon: <DarkIcon />,\n Provider: ({ children }) => (\n <UnifiedThemeProvider theme={builtinThemes.dark} children={children} />\n ),\n },\n },\n});\n"],"names":["builtinThemes"],"mappings":";;;;;;;;;;;AAkCO,MAAM,WAAA,GAAc,aAAa,iBAAA,CAAkB;AAAA,EACxD,IAAA,EAAM,WAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,QAAQ,oBAAA,CAAqB,CAAC,cAAA,CAAe,QAAA,CAAS,KAAK,CAAA,EAAG;AAAA,MAC5D,UAAU,CAAC,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,UAAU;AAAA,KAC1C;AAAA,GACH;AAAA,EACA,OAAA,EAAS,CAAC,eAAA,EAAiB,EAAE,QAAO,KAAM;AACxC,IAAA,OAAO,eAAA;AAAA,MAAgB,kBACrB,YAAA,CAAa;AAAA,QACX,GAAA,EAAK,cAAA;AAAA,QACL,MAAM,EAAC;AAAA,QACP,SAAS,MAAM;AACb,UAAA,MAAM,gBAAA,GAAmB,OAAO,MAAA,CAAO,MAAA;AAAA,YACrC,CAAA,CAAA,KAAK,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,QAAQ,EAAA,KAAO;AAAA,WAClC;AAEA,UAAA,IAAI,gBAAA,CAAiB,SAAS,CAAA,EAAG;AAC/B,YAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,KAAK,IAAA,CAAK,EAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAEhE,YAAA,OAAA,CAAQ,IAAA;AAAA,cACN,0NACqI,IAAI,CAAA;AAAA,aAC3I;AAAA,UACF;AAEA,UAAA,OAAO,gBAAA,CAAiB,iBAAA;AAAA,YACtB,MAAA,CAAO,OAAO,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,GAAA,CAAI,cAAA,CAAe,QAAA,CAAS,KAAK,CAAC;AAAA,WAC7D;AAAA,QACF;AAAA,OACD;AAAA,KACH;AAAA,EACF;AACF,CAAC;AAEM,MAAM,UAAA,GAAa,eAAe,IAAA,CAAK;AAAA,EAC5C,IAAA,EAAM,OAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO;AAAA,MACL,EAAA,EAAI,OAAA;AAAA,MACJ,KAAA,EAAO,aAAA;AAAA,MACP,OAAA,EAAS,OAAA;AAAA,MACT,IAAA,sBAAO,SAAA,EAAA,EAAU,CAAA;AAAA,MACjB,QAAA,EAAU,CAAC,EAAE,QAAA,EAAS,yBACnB,oBAAA,EAAA,EAAqB,KAAA,EAAOA,MAAA,CAAc,KAAA,EAAO,QAAA,EAAoB;AAAA;AAE1E;AAEJ,CAAC;AAEM,MAAM,SAAA,GAAY,eAAe,IAAA,CAAK;AAAA,EAC3C,IAAA,EAAM,MAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO;AAAA,MACL,EAAA,EAAI,MAAA;AAAA,MACJ,KAAA,EAAO,YAAA;AAAA,MACP,OAAA,EAAS,MAAA;AAAA,MACT,IAAA,sBAAO,QAAA,EAAA,EAAS,CAAA;AAAA,MAChB,QAAA,EAAU,CAAC,EAAE,QAAA,EAAS,yBACnB,oBAAA,EAAA,EAAqB,KAAA,EAAOA,MAAA,CAAc,IAAA,EAAM,QAAA,EAAoB;AAAA;AAEzE;AAEJ,CAAC;;;;"}
|
|
@@ -22,9 +22,20 @@ const IconsApi = ApiBlueprint.makeWithOverrides({
|
|
|
22
22
|
(defineParams) => defineParams({
|
|
23
23
|
api: iconsApiRef,
|
|
24
24
|
deps: {},
|
|
25
|
-
factory: () =>
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
factory: () => {
|
|
26
|
+
const nonAppExtensions = inputs.icons.filter(
|
|
27
|
+
(i) => i.node.spec.plugin?.id !== "app"
|
|
28
|
+
);
|
|
29
|
+
if (nonAppExtensions.length > 0) {
|
|
30
|
+
const list = nonAppExtensions.map((i) => i.node.spec.id).join(", ");
|
|
31
|
+
console.warn(
|
|
32
|
+
`DEPRECATION WARNING: IconBundle should only be installed as an extension in the app plugin. You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${list}`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return new DefaultIconsApi(
|
|
36
|
+
inputs.icons.map((i) => i.get(IconBundleBlueprint.dataRefs.icons)).reduce((acc, bundle) => ({ ...acc, ...bundle }), icons)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
28
39
|
})
|
|
29
40
|
);
|
|
30
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconsApi.esm.js","sources":["../../src/extensions/IconsApi.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createExtensionInput,\n IconBundleBlueprint,\n ApiBlueprint,\n iconsApiRef,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { DefaultIconsApi } from '../../../../packages/frontend-app-api/src/apis/implementations/IconsApi';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { icons as defaultIcons } from '../../../../packages/app-defaults/src/defaults';\n\n/**\n * Contains the shareable icons installed into the app.\n */\nexport const IconsApi = ApiBlueprint.makeWithOverrides({\n name: 'icons',\n inputs: {\n icons: createExtensionInput([IconBundleBlueprint.dataRefs.icons], {\n replaces: [{ id: 'app', input: 'icons' }],\n }),\n },\n factory: (originalFactory, { inputs }) => {\n return originalFactory(defineParams =>\n defineParams({\n api: iconsApiRef,\n deps: {},\n factory: ()
|
|
1
|
+
{"version":3,"file":"IconsApi.esm.js","sources":["../../src/extensions/IconsApi.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createExtensionInput,\n IconBundleBlueprint,\n ApiBlueprint,\n iconsApiRef,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { DefaultIconsApi } from '../../../../packages/frontend-app-api/src/apis/implementations/IconsApi';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { icons as defaultIcons } from '../../../../packages/app-defaults/src/defaults';\n\n/**\n * Contains the shareable icons installed into the app.\n */\nexport const IconsApi = ApiBlueprint.makeWithOverrides({\n name: 'icons',\n inputs: {\n icons: createExtensionInput([IconBundleBlueprint.dataRefs.icons], {\n replaces: [{ id: 'app', input: 'icons' }],\n }),\n },\n factory: (originalFactory, { inputs }) => {\n return originalFactory(defineParams =>\n defineParams({\n api: iconsApiRef,\n deps: {},\n factory: () => {\n const nonAppExtensions = inputs.icons.filter(\n i => i.node.spec.plugin?.id !== 'app',\n );\n\n if (nonAppExtensions.length > 0) {\n const list = nonAppExtensions.map(i => i.node.spec.id).join(', ');\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: IconBundle should only be installed as an extension in the app plugin. ` +\n `You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${list}`,\n );\n }\n\n return new DefaultIconsApi(\n inputs.icons\n .map(i => i.get(IconBundleBlueprint.dataRefs.icons))\n .reduce((acc, bundle) => ({ ...acc, ...bundle }), defaultIcons),\n );\n },\n }),\n );\n },\n});\n"],"names":["defaultIcons"],"mappings":";;;;;;;;;;;;AA8BO,MAAM,QAAA,GAAW,aAAa,iBAAA,CAAkB;AAAA,EACrD,IAAA,EAAM,OAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,OAAO,oBAAA,CAAqB,CAAC,mBAAA,CAAoB,QAAA,CAAS,KAAK,CAAA,EAAG;AAAA,MAChE,UAAU,CAAC,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,SAAS;AAAA,KACzC;AAAA,GACH;AAAA,EACA,OAAA,EAAS,CAAC,eAAA,EAAiB,EAAE,QAAO,KAAM;AACxC,IAAA,OAAO,eAAA;AAAA,MAAgB,kBACrB,YAAA,CAAa;AAAA,QACX,GAAA,EAAK,WAAA;AAAA,QACL,MAAM,EAAC;AAAA,QACP,SAAS,MAAM;AACb,UAAA,MAAM,gBAAA,GAAmB,OAAO,KAAA,CAAM,MAAA;AAAA,YACpC,CAAA,CAAA,KAAK,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,QAAQ,EAAA,KAAO;AAAA,WAClC;AAEA,UAAA,IAAI,gBAAA,CAAiB,SAAS,CAAA,EAAG;AAC/B,YAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,KAAK,IAAA,CAAK,EAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAEhE,YAAA,OAAA,CAAQ,IAAA;AAAA,cACN,+NACqI,IAAI,CAAA;AAAA,aAC3I;AAAA,UACF;AAEA,UAAA,OAAO,IAAI,eAAA;AAAA,YACT,MAAA,CAAO,MACJ,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,GAAA,CAAI,mBAAA,CAAoB,SAAS,KAAK,CAAC,EAClD,MAAA,CAAO,CAAC,KAAK,MAAA,MAAY,EAAE,GAAG,GAAA,EAAK,GAAG,MAAA,EAAO,CAAA,EAAIA,KAAY;AAAA,WAClE;AAAA,QACF;AAAA,OACD;AAAA,KACH;AAAA,EACF;AACF,CAAC;;;;"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { pluginWrapperApiRef, PluginWrapperBlueprint } from '@backstage/frontend-plugin-api/alpha';
|
|
2
|
+
import { ApiBlueprint, createExtensionInput } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { DefaultPluginWrapperApi } from '../apis/PluginWrapperApi/DefaultPluginWrapperApi.esm.js';
|
|
4
|
+
|
|
5
|
+
const PluginWrapperApi = ApiBlueprint.makeWithOverrides({
|
|
6
|
+
name: "plugin-wrapper",
|
|
7
|
+
inputs: {
|
|
8
|
+
wrappers: createExtensionInput([PluginWrapperBlueprint.dataRefs.wrapper])
|
|
9
|
+
},
|
|
10
|
+
factory: (originalFactory, { inputs }) => {
|
|
11
|
+
return originalFactory(
|
|
12
|
+
(defineParams) => defineParams({
|
|
13
|
+
api: pluginWrapperApiRef,
|
|
14
|
+
deps: {},
|
|
15
|
+
factory: () => {
|
|
16
|
+
return DefaultPluginWrapperApi.fromWrappers(
|
|
17
|
+
inputs.wrappers.map((wrapperInput) => ({
|
|
18
|
+
loader: wrapperInput.get(PluginWrapperBlueprint.dataRefs.wrapper),
|
|
19
|
+
pluginId: wrapperInput.node.spec.plugin.id ?? "app"
|
|
20
|
+
}))
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export { PluginWrapperApi };
|
|
29
|
+
//# sourceMappingURL=PluginWrapperApi.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PluginWrapperApi.esm.js","sources":["../../src/extensions/PluginWrapperApi.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PluginWrapperBlueprint,\n pluginWrapperApiRef,\n} from '@backstage/frontend-plugin-api/alpha';\nimport {\n createExtensionInput,\n ApiBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport { DefaultPluginWrapperApi } from '../apis/PluginWrapperApi';\n\n/**\n * Contains the plugin wrappers installed into the app.\n */\nexport const PluginWrapperApi = ApiBlueprint.makeWithOverrides({\n name: 'plugin-wrapper',\n inputs: {\n wrappers: createExtensionInput([PluginWrapperBlueprint.dataRefs.wrapper]),\n },\n factory: (originalFactory, { inputs }) => {\n return originalFactory(defineParams =>\n defineParams({\n api: pluginWrapperApiRef,\n deps: {},\n factory: () => {\n return DefaultPluginWrapperApi.fromWrappers(\n inputs.wrappers.map(wrapperInput => ({\n loader: wrapperInput.get(PluginWrapperBlueprint.dataRefs.wrapper),\n pluginId: wrapperInput.node.spec.plugin.id ?? 'app',\n })),\n );\n },\n }),\n );\n },\n});\n"],"names":[],"mappings":";;;;AA6BO,MAAM,gBAAA,GAAmB,aAAa,iBAAA,CAAkB;AAAA,EAC7D,IAAA,EAAM,gBAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,UAAU,oBAAA,CAAqB,CAAC,sBAAA,CAAuB,QAAA,CAAS,OAAO,CAAC;AAAA,GAC1E;AAAA,EACA,OAAA,EAAS,CAAC,eAAA,EAAiB,EAAE,QAAO,KAAM;AACxC,IAAA,OAAO,eAAA;AAAA,MAAgB,kBACrB,YAAA,CAAa;AAAA,QACX,GAAA,EAAK,mBAAA;AAAA,QACL,MAAM,EAAC;AAAA,QACP,SAAS,MAAM;AACb,UAAA,OAAO,uBAAA,CAAwB,YAAA;AAAA,YAC7B,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,CAAA,YAAA,MAAiB;AAAA,cACnC,MAAA,EAAQ,YAAA,CAAa,GAAA,CAAI,sBAAA,CAAuB,SAAS,OAAO,CAAA;AAAA,cAChE,QAAA,EAAU,YAAA,CAAa,IAAA,CAAK,IAAA,CAAK,OAAO,EAAA,IAAM;AAAA,aAChD,CAAE;AAAA,WACJ;AAAA,QACF;AAAA,OACD;AAAA,KACH;AAAA,EACF;AACF,CAAC;;;;"}
|
|
@@ -15,12 +15,23 @@ const TranslationsApi = ApiBlueprint.makeWithOverrides({
|
|
|
15
15
|
(defineParams) => defineParams({
|
|
16
16
|
api: translationApiRef,
|
|
17
17
|
deps: { languageApi: appLanguageApiRef },
|
|
18
|
-
factory: ({ languageApi }) =>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
)
|
|
23
|
-
|
|
18
|
+
factory: ({ languageApi }) => {
|
|
19
|
+
const nonAppExtensions = inputs.translations.filter(
|
|
20
|
+
(i) => i.node.spec.plugin?.id !== "app"
|
|
21
|
+
);
|
|
22
|
+
if (nonAppExtensions.length > 0) {
|
|
23
|
+
const list = nonAppExtensions.map((i) => i.node.spec.id).join(", ");
|
|
24
|
+
console.warn(
|
|
25
|
+
`DEPRECATION WARNING: Translations should only be installed as an extension in the app plugin. You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${list}`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return I18nextTranslationApi.create({
|
|
29
|
+
languageApi,
|
|
30
|
+
resources: inputs.translations.map(
|
|
31
|
+
(i) => i.get(TranslationBlueprint.dataRefs.translation)
|
|
32
|
+
)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
24
35
|
})
|
|
25
36
|
);
|
|
26
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranslationsApi.esm.js","sources":["../../src/extensions/TranslationsApi.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n ApiBlueprint,\n TranslationBlueprint,\n createExtensionInput,\n} from '@backstage/frontend-plugin-api';\nimport {\n appLanguageApiRef,\n translationApiRef,\n} from '@backstage/core-plugin-api/alpha';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { I18nextTranslationApi } from '../../../../packages/core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi';\n\n/**\n * Contains translations that are installed in the app.\n */\nexport const TranslationsApi = ApiBlueprint.makeWithOverrides({\n name: 'translations',\n inputs: {\n translations: createExtensionInput(\n [TranslationBlueprint.dataRefs.translation],\n { replaces: [{ id: 'app', input: 'translations' }] },\n ),\n },\n factory: (originalFactory, { inputs }) => {\n return originalFactory(defineParams =>\n defineParams({\n api: translationApiRef,\n deps: { languageApi: appLanguageApiRef },\n factory: ({ languageApi })
|
|
1
|
+
{"version":3,"file":"TranslationsApi.esm.js","sources":["../../src/extensions/TranslationsApi.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n ApiBlueprint,\n TranslationBlueprint,\n createExtensionInput,\n} from '@backstage/frontend-plugin-api';\nimport {\n appLanguageApiRef,\n translationApiRef,\n} from '@backstage/core-plugin-api/alpha';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { I18nextTranslationApi } from '../../../../packages/core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi';\n\n/**\n * Contains translations that are installed in the app.\n */\nexport const TranslationsApi = ApiBlueprint.makeWithOverrides({\n name: 'translations',\n inputs: {\n translations: createExtensionInput(\n [TranslationBlueprint.dataRefs.translation],\n { replaces: [{ id: 'app', input: 'translations' }] },\n ),\n },\n factory: (originalFactory, { inputs }) => {\n return originalFactory(defineParams =>\n defineParams({\n api: translationApiRef,\n deps: { languageApi: appLanguageApiRef },\n factory: ({ languageApi }) => {\n const nonAppExtensions = inputs.translations.filter(\n i => i.node.spec.plugin?.id !== 'app',\n );\n\n if (nonAppExtensions.length > 0) {\n const list = nonAppExtensions.map(i => i.node.spec.id).join(', ');\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: Translations should only be installed as an extension in the app plugin. ` +\n `You can either use appPlugin.override(), or a module for the app plugin. The following extension will be ignored in the future: ${list}`,\n );\n }\n\n return I18nextTranslationApi.create({\n languageApi,\n resources: inputs.translations.map(i =>\n i.get(TranslationBlueprint.dataRefs.translation),\n ),\n });\n },\n }),\n );\n },\n});\n"],"names":[],"mappings":";;;;AA+BO,MAAM,eAAA,GAAkB,aAAa,iBAAA,CAAkB;AAAA,EAC5D,IAAA,EAAM,cAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,YAAA,EAAc,oBAAA;AAAA,MACZ,CAAC,oBAAA,CAAqB,QAAA,CAAS,WAAW,CAAA;AAAA,MAC1C,EAAE,UAAU,CAAC,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,cAAA,EAAgB,CAAA;AAAE;AACrD,GACF;AAAA,EACA,OAAA,EAAS,CAAC,eAAA,EAAiB,EAAE,QAAO,KAAM;AACxC,IAAA,OAAO,eAAA;AAAA,MAAgB,kBACrB,YAAA,CAAa;AAAA,QACX,GAAA,EAAK,iBAAA;AAAA,QACL,IAAA,EAAM,EAAE,WAAA,EAAa,iBAAA,EAAkB;AAAA,QACvC,OAAA,EAAS,CAAC,EAAE,WAAA,EAAY,KAAM;AAC5B,UAAA,MAAM,gBAAA,GAAmB,OAAO,YAAA,CAAa,MAAA;AAAA,YAC3C,CAAA,CAAA,KAAK,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,QAAQ,EAAA,KAAO;AAAA,WAClC;AAEA,UAAA,IAAI,gBAAA,CAAiB,SAAS,CAAA,EAAG;AAC/B,YAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,KAAK,IAAA,CAAK,EAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAEhE,YAAA,OAAA,CAAQ,IAAA;AAAA,cACN,iOACqI,IAAI,CAAA;AAAA,aAC3I;AAAA,UACF;AAEA,UAAA,OAAO,sBAAsB,MAAA,CAAO;AAAA,YAClC,WAAA;AAAA,YACA,SAAA,EAAW,OAAO,YAAA,CAAa,GAAA;AAAA,cAAI,CAAA,CAAA,KACjC,CAAA,CAAE,GAAA,CAAI,oBAAA,CAAqB,SAAS,WAAW;AAAA;AACjD,WACD,CAAA;AAAA,QACH;AAAA,OACD;AAAA,KACH;AAAA,EACF;AACF,CAAC;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -337,6 +337,24 @@ declare const appPlugin: _backstage_frontend_plugin_api.OverridableFrontendPlugi
|
|
|
337
337
|
inputs: {};
|
|
338
338
|
params: <TApi, TImpl extends TApi, TDeps extends { [name in string]: unknown; }>(params: _backstage_frontend_plugin_api.ApiFactory<TApi, TImpl, TDeps>) => _backstage_frontend_plugin_api.ExtensionBlueprintParams<_backstage_frontend_plugin_api.AnyApiFactory>;
|
|
339
339
|
}>;
|
|
340
|
+
"api:app/plugin-wrapper": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
341
|
+
config: {};
|
|
342
|
+
configInput: {};
|
|
343
|
+
output: _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.AnyApiFactory, "core.api.factory", {}>;
|
|
344
|
+
inputs: {
|
|
345
|
+
wrappers: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<() => Promise<{
|
|
346
|
+
component: react.ComponentType<{
|
|
347
|
+
children: react.ReactNode;
|
|
348
|
+
}>;
|
|
349
|
+
}>, "core.plugin-wrapper.loader", {}>, {
|
|
350
|
+
singleton: false;
|
|
351
|
+
optional: false;
|
|
352
|
+
}>;
|
|
353
|
+
};
|
|
354
|
+
kind: "api";
|
|
355
|
+
name: "plugin-wrapper";
|
|
356
|
+
params: <TApi, TImpl extends TApi, TDeps extends { [name in string]: unknown; }>(params: _backstage_frontend_plugin_api.ApiFactory<TApi, TImpl, TDeps>) => _backstage_frontend_plugin_api.ExtensionBlueprintParams<_backstage_frontend_plugin_api.AnyApiFactory>;
|
|
357
|
+
}>;
|
|
340
358
|
"api:app/scm-auth": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
341
359
|
kind: "api";
|
|
342
360
|
name: "scm-auth";
|
package/dist/plugin.esm.js
CHANGED
|
@@ -15,6 +15,7 @@ import { DefaultSignInPage } from './extensions/DefaultSignInPage.esm.js';
|
|
|
15
15
|
import { dialogDisplayAppRootElement } from './extensions/DialogDisplay.esm.js';
|
|
16
16
|
import { oauthRequestDialogAppRootElement, alertDisplayAppRootElement } from './extensions/elements.esm.js';
|
|
17
17
|
import { Progress, NotFoundErrorPage, ErrorDisplay } from './extensions/components.esm.js';
|
|
18
|
+
import { PluginWrapperApi } from './extensions/PluginWrapperApi.esm.js';
|
|
18
19
|
import { apis } from './defaultApis.esm.js';
|
|
19
20
|
|
|
20
21
|
const appPlugin = createFrontendPlugin({
|
|
@@ -34,6 +35,7 @@ const appPlugin = createFrontendPlugin({
|
|
|
34
35
|
SwappableComponentsApi,
|
|
35
36
|
IconsApi,
|
|
36
37
|
FeatureFlagsApi,
|
|
38
|
+
PluginWrapperApi,
|
|
37
39
|
TranslationsApi,
|
|
38
40
|
DefaultSignInPage,
|
|
39
41
|
oauthRequestDialogAppRootElement,
|
package/dist/plugin.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createFrontendPlugin } from '@backstage/frontend-plugin-api';\nimport {\n App,\n AppLanguageApi,\n AppLayout,\n AppNav,\n AppRoot,\n AppRoutes,\n AppThemeApi,\n DarkTheme,\n LightTheme,\n SwappableComponentsApi,\n IconsApi,\n FeatureFlagsApi,\n TranslationsApi,\n oauthRequestDialogAppRootElement,\n alertDisplayAppRootElement,\n DefaultSignInPage,\n dialogDisplayAppRootElement,\n Progress,\n NotFoundErrorPage,\n ErrorDisplay,\n LegacyComponentsApi,\n} from './extensions';\nimport { apis } from './defaultApis';\n\n/** @public */\nexport const appPlugin = createFrontendPlugin({\n pluginId: 'app',\n info: { packageJson: () => import('../package.json') },\n extensions: [\n ...apis,\n App,\n AppLanguageApi,\n AppLayout,\n AppNav,\n AppRoot,\n AppRoutes,\n AppThemeApi,\n DarkTheme,\n LightTheme,\n SwappableComponentsApi,\n IconsApi,\n FeatureFlagsApi,\n TranslationsApi,\n DefaultSignInPage,\n oauthRequestDialogAppRootElement,\n alertDisplayAppRootElement,\n dialogDisplayAppRootElement,\n Progress,\n NotFoundErrorPage,\n ErrorDisplay,\n LegacyComponentsApi,\n ],\n});\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createFrontendPlugin } from '@backstage/frontend-plugin-api';\nimport {\n App,\n AppLanguageApi,\n AppLayout,\n AppNav,\n AppRoot,\n AppRoutes,\n AppThemeApi,\n DarkTheme,\n LightTheme,\n SwappableComponentsApi,\n IconsApi,\n FeatureFlagsApi,\n PluginWrapperApi,\n TranslationsApi,\n oauthRequestDialogAppRootElement,\n alertDisplayAppRootElement,\n DefaultSignInPage,\n dialogDisplayAppRootElement,\n Progress,\n NotFoundErrorPage,\n ErrorDisplay,\n LegacyComponentsApi,\n} from './extensions';\nimport { apis } from './defaultApis';\n\n/** @public */\nexport const appPlugin = createFrontendPlugin({\n pluginId: 'app',\n info: { packageJson: () => import('../package.json') },\n extensions: [\n ...apis,\n App,\n AppLanguageApi,\n AppLayout,\n AppNav,\n AppRoot,\n AppRoutes,\n AppThemeApi,\n DarkTheme,\n LightTheme,\n SwappableComponentsApi,\n IconsApi,\n FeatureFlagsApi,\n PluginWrapperApi,\n TranslationsApi,\n DefaultSignInPage,\n oauthRequestDialogAppRootElement,\n alertDisplayAppRootElement,\n dialogDisplayAppRootElement,\n Progress,\n NotFoundErrorPage,\n ErrorDisplay,\n LegacyComponentsApi,\n ],\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA4CO,MAAM,YAAY,oBAAA,CAAqB;AAAA,EAC5C,QAAA,EAAU,KAAA;AAAA,EACV,MAAM,EAAE,WAAA,EAAa,MAAM,OAAO,mCAAiB,CAAA,EAAE;AAAA,EACrD,UAAA,EAAY;AAAA,IACV,GAAG,IAAA;AAAA,IACH,GAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA;AAAA,IACA,MAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,IACA,sBAAA;AAAA,IACA,QAAA;AAAA,IACA,eAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,iBAAA;AAAA,IACA,gCAAA;AAAA,IACA,0BAAA;AAAA,IACA,2BAAA;AAAA,IACA,QAAA;AAAA,IACA,iBAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA;AAEJ,CAAC;;;;"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
var name = "@backstage/plugin-app";
|
|
2
|
-
var version = "0.3.4
|
|
2
|
+
var version = "0.3.4";
|
|
3
3
|
var backstage = {
|
|
4
4
|
role: "frontend-plugin",
|
|
5
5
|
pluginId: "app",
|
|
6
6
|
pluginPackages: [
|
|
7
7
|
"@backstage/plugin-app",
|
|
8
8
|
"@backstage/plugin-app-backend",
|
|
9
|
-
"@backstage/plugin-app-node"
|
|
9
|
+
"@backstage/plugin-app-node",
|
|
10
|
+
"@backstage/plugin-app-react"
|
|
10
11
|
]
|
|
11
12
|
};
|
|
12
13
|
var publishConfig = {
|
|
@@ -53,6 +54,7 @@ var dependencies = {
|
|
|
53
54
|
"@backstage/core-plugin-api": "workspace:^",
|
|
54
55
|
"@backstage/frontend-plugin-api": "workspace:^",
|
|
55
56
|
"@backstage/integration-react": "workspace:^",
|
|
57
|
+
"@backstage/plugin-app-react": "workspace:^",
|
|
56
58
|
"@backstage/plugin-permission-react": "workspace:^",
|
|
57
59
|
"@backstage/theme": "workspace:^",
|
|
58
60
|
"@backstage/types": "workspace:^",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.json.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"package.json.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-app",
|
|
3
|
-
"version": "0.3.4
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "frontend-plugin",
|
|
6
6
|
"pluginId": "app",
|
|
7
7
|
"pluginPackages": [
|
|
8
8
|
"@backstage/plugin-app",
|
|
9
9
|
"@backstage/plugin-app-backend",
|
|
10
|
-
"@backstage/plugin-app-node"
|
|
10
|
+
"@backstage/plugin-app-node",
|
|
11
|
+
"@backstage/plugin-app-react"
|
|
11
12
|
],
|
|
12
13
|
"features": {
|
|
13
14
|
".": "@backstage/FrontendPlugin"
|
|
@@ -62,14 +63,15 @@
|
|
|
62
63
|
"test": "backstage-cli package test"
|
|
63
64
|
},
|
|
64
65
|
"dependencies": {
|
|
65
|
-
"@backstage/core-components": "0.18.
|
|
66
|
-
"@backstage/core-plugin-api": "1.12.1",
|
|
67
|
-
"@backstage/frontend-plugin-api": "0.13.
|
|
68
|
-
"@backstage/integration-react": "1.2.14
|
|
69
|
-
"@backstage/plugin-
|
|
70
|
-
"@backstage/
|
|
71
|
-
"@backstage/
|
|
72
|
-
"@backstage/
|
|
66
|
+
"@backstage/core-components": "^0.18.5",
|
|
67
|
+
"@backstage/core-plugin-api": "^1.12.1",
|
|
68
|
+
"@backstage/frontend-plugin-api": "^0.13.3",
|
|
69
|
+
"@backstage/integration-react": "^1.2.14",
|
|
70
|
+
"@backstage/plugin-app-react": "^0.1.0",
|
|
71
|
+
"@backstage/plugin-permission-react": "^0.4.39",
|
|
72
|
+
"@backstage/theme": "^0.7.1",
|
|
73
|
+
"@backstage/types": "^1.2.2",
|
|
74
|
+
"@backstage/version-bridge": "^1.0.11",
|
|
73
75
|
"@material-ui/core": "^4.9.13",
|
|
74
76
|
"@material-ui/icons": "^4.9.1",
|
|
75
77
|
"@material-ui/lab": "^4.0.0-alpha.61",
|
|
@@ -78,11 +80,11 @@
|
|
|
78
80
|
"zod": "^3.22.4"
|
|
79
81
|
},
|
|
80
82
|
"devDependencies": {
|
|
81
|
-
"@backstage/cli": "0.35.2
|
|
82
|
-
"@backstage/dev-utils": "1.1.19
|
|
83
|
-
"@backstage/frontend-defaults": "0.3.5
|
|
84
|
-
"@backstage/frontend-test-utils": "0.4.3
|
|
85
|
-
"@backstage/test-utils": "1.7.14",
|
|
83
|
+
"@backstage/cli": "^0.35.2",
|
|
84
|
+
"@backstage/dev-utils": "^1.1.19",
|
|
85
|
+
"@backstage/frontend-defaults": "^0.3.5",
|
|
86
|
+
"@backstage/frontend-test-utils": "^0.4.3",
|
|
87
|
+
"@backstage/test-utils": "^1.7.14",
|
|
86
88
|
"@testing-library/jest-dom": "^6.0.0",
|
|
87
89
|
"@testing-library/react": "^16.0.0",
|
|
88
90
|
"@testing-library/user-event": "^14.0.0",
|