frontend-plugin-api: add new internal option for extension inputs

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2026-01-22 14:22:56 +01:00
parent 24eb7d7933
commit 7edb810248
27 changed files with 315 additions and 149 deletions
+1 -8
View File
@@ -90,18 +90,11 @@ export const AppNav = createExtension({
content: createExtensionInput([NavContentBlueprint.dataRefs.component], {
singleton: true,
optional: true,
internal: true,
}),
},
output: [coreExtensionData.reactElement],
*factory({ inputs }) {
if (inputs.content && inputs.content.node.spec.plugin?.id !== 'app') {
// eslint-disable-next-line no-console
console.warn(
`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}`,
);
}
const Content =
inputs.content?.get(NavContentBlueprint.dataRefs.component) ??
DefaultNavContent;
+8 -27
View File
@@ -59,37 +59,26 @@ export const AppRoot = createExtension({
router: createExtensionInput([RouterBlueprint.dataRefs.component], {
singleton: true,
optional: true,
internal: true,
}),
signInPage: createExtensionInput([SignInPageBlueprint.dataRefs.component], {
singleton: true,
optional: true,
internal: true,
}),
children: createExtensionInput([coreExtensionData.reactElement], {
singleton: true,
}),
elements: createExtensionInput([coreExtensionData.reactElement]),
wrappers: createExtensionInput([
AppRootWrapperBlueprint.dataRefs.component,
]),
wrappers: createExtensionInput(
[AppRootWrapperBlueprint.dataRefs.component],
{
internal: true,
},
),
},
output: [coreExtensionData.reactElement],
factory({ inputs, apis }) {
if (inputs.router && inputs.router.node.spec.plugin?.id !== 'app') {
// eslint-disable-next-line no-console
console.warn(
`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}`,
);
}
if (inputs.signInPage && inputs.signInPage.node.spec.plugin?.id !== 'app') {
// eslint-disable-next-line no-console
console.warn(
`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}`,
);
}
if (isProtectedApp()) {
const identityApi = apis.get(identityApiRef);
if (!identityApi) {
@@ -117,16 +106,8 @@ export const AppRoot = createExtension({
for (const wrapper of inputs.wrappers) {
const Component = wrapper.get(AppRootWrapperBlueprint.dataRefs.component);
const pluginId = wrapper.node.spec.plugin.id;
if (Component) {
content = <Component>{content}</Component>;
if (pluginId !== 'app') {
// eslint-disable-next-line no-console
console.warn(
`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}`,
);
}
}
}
+1 -13
View File
@@ -37,6 +37,7 @@ export const AppThemeApi = ApiBlueprint.makeWithOverrides({
inputs: {
themes: createExtensionInput([ThemeBlueprint.dataRefs.theme], {
replaces: [{ id: 'app', input: 'themes' }],
internal: true,
}),
},
factory: (originalFactory, { inputs }) => {
@@ -45,19 +46,6 @@ export const AppThemeApi = ApiBlueprint.makeWithOverrides({
api: appThemeApiRef,
deps: {},
factory: () => {
const nonAppExtensions = inputs.themes.filter(
i => i.node.spec.plugin?.id !== 'app',
);
if (nonAppExtensions.length > 0) {
const list = nonAppExtensions.map(i => i.node.spec.id).join(', ');
// eslint-disable-next-line no-console
console.warn(
`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}`,
);
}
return AppThemeSelector.createWithStorage(
inputs.themes.map(i => i.get(ThemeBlueprint.dataRefs.theme)),
);
+1 -13
View File
@@ -33,6 +33,7 @@ export const IconsApi = ApiBlueprint.makeWithOverrides({
inputs: {
icons: createExtensionInput([IconBundleBlueprint.dataRefs.icons], {
replaces: [{ id: 'app', input: 'icons' }],
internal: true,
}),
},
factory: (originalFactory, { inputs }) => {
@@ -41,19 +42,6 @@ export const IconsApi = ApiBlueprint.makeWithOverrides({
api: iconsApiRef,
deps: {},
factory: () => {
const nonAppExtensions = inputs.icons.filter(
i => i.node.spec.plugin?.id !== 'app',
);
if (nonAppExtensions.length > 0) {
const list = nonAppExtensions.map(i => i.node.spec.id).join(', ');
// eslint-disable-next-line no-console
console.warn(
`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}`,
);
}
return new DefaultIconsApi(
inputs.icons
.map(i => i.get(IconBundleBlueprint.dataRefs.icons))
@@ -28,9 +28,12 @@ import { DefaultSwappableComponentsApi } from '../apis/SwappableComponentsApi';
export const SwappableComponentsApi = ApiBlueprint.makeWithOverrides({
name: 'swappable-components',
inputs: {
components: createExtensionInput([
SwappableComponentBlueprint.dataRefs.component,
]),
components: createExtensionInput(
[SwappableComponentBlueprint.dataRefs.component],
{
internal: true,
},
),
},
factory: (originalFactory, { inputs }) => {
return originalFactory(defineParams =>
@@ -38,25 +41,8 @@ export const SwappableComponentsApi = ApiBlueprint.makeWithOverrides({
api: swappableComponentsApiRef,
deps: {},
factory: () => {
const nonAppExtensions = inputs.components.filter(
i => i.node.spec.plugin?.id !== 'app',
);
if (nonAppExtensions.length > 0) {
// eslint-disable-next-line no-console
console.warn(
`SwappableComponents should only be installed as an extension in the app plugin. You can either use appPlugin.override(), or provide a module for the app-plugin with the extension there instead. Invalid extensions: ${nonAppExtensions
.map(i => i.node.spec.id)
.join(', ')}`,
);
}
const appExtensions = inputs.components.filter(
i => i.node.spec.plugin?.id === 'app',
);
return DefaultSwappableComponentsApi.fromComponents(
appExtensions.map(i =>
inputs.components.map(i =>
i.get(SwappableComponentBlueprint.dataRefs.component),
),
);
+1 -14
View File
@@ -34,7 +34,7 @@ export const TranslationsApi = ApiBlueprint.makeWithOverrides({
inputs: {
translations: createExtensionInput(
[TranslationBlueprint.dataRefs.translation],
{ replaces: [{ id: 'app', input: 'translations' }] },
{ replaces: [{ id: 'app', input: 'translations' }], internal: true },
),
},
factory: (originalFactory, { inputs }) => {
@@ -43,19 +43,6 @@ export const TranslationsApi = ApiBlueprint.makeWithOverrides({
api: translationApiRef,
deps: { languageApi: appLanguageApiRef },
factory: ({ languageApi }) => {
const nonAppExtensions = inputs.translations.filter(
i => i.node.spec.plugin?.id !== 'app',
);
if (nonAppExtensions.length > 0) {
const list = nonAppExtensions.map(i => i.node.spec.id).join(', ');
// eslint-disable-next-line no-console
console.warn(
`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}`,
);
}
return I18nextTranslationApi.create({
languageApi,
resources: inputs.translations.map(i =>