mirror of
https://github.com/strapi/strapi.git
synced 2026-05-03 16:22:30 +00:00
fix(admin): clean up lazy component registration warnings (#25015)
* fix(admin): don't warn when Component is missing in addMenuLink/addSettingsLink * fix: add some missing StrapiApp types * fix(admin): clean up lazy component registrations --------- Co-authored-by: Bassel Kanso <basselkanso82@gmail.com>
This commit is contained in:
@@ -157,15 +157,14 @@ class Router {
|
||||
);
|
||||
|
||||
if (
|
||||
!link.Component ||
|
||||
(link.Component &&
|
||||
typeof link.Component === 'function' &&
|
||||
// @ts-expect-error – shh
|
||||
link.Component[Symbol.toStringTag] === 'AsyncFunction')
|
||||
link.Component &&
|
||||
typeof link.Component === 'function' &&
|
||||
// @ts-expect-error – shh
|
||||
link.Component[Symbol.toStringTag] === 'AsyncFunction'
|
||||
) {
|
||||
console.warn(
|
||||
`
|
||||
[${link.intlLabel.defaultMessage}]: [deprecated] addMenuLink() was called with an async Component from the plugin "${link.intlLabel.defaultMessage}". This will be removed in the future. Please use: \`Component: () => import(path)\` ensuring you return a default export instead.
|
||||
[${link.intlLabel.defaultMessage}]: [deprecated] addMenuLink() was called with an async Component from the plugin "${link.intlLabel.defaultMessage}". Component loaders should return a dynamic import with a default export shape, e.g. \`Component: () => import(path).then((mod) => ({ default: mod.Component }))\`. Async wrapper functions will stop being supported in a future version.
|
||||
`.trim()
|
||||
);
|
||||
}
|
||||
@@ -280,15 +279,14 @@ class Router {
|
||||
);
|
||||
|
||||
if (
|
||||
!link.Component ||
|
||||
(link.Component &&
|
||||
typeof link.Component === 'function' &&
|
||||
// @ts-expect-error – shh
|
||||
link.Component[Symbol.toStringTag] === 'AsyncFunction')
|
||||
link.Component &&
|
||||
typeof link.Component === 'function' &&
|
||||
// @ts-expect-error – shh
|
||||
link.Component[Symbol.toStringTag] === 'AsyncFunction'
|
||||
) {
|
||||
console.warn(
|
||||
`
|
||||
[${link.intlLabel.defaultMessage}]: [deprecated] addSettingsLink() was called with an async Component from the plugin "${link.intlLabel.defaultMessage}". This will be removed in the future. Please use: \`Component: () => import(path)\` ensuring you return a default export instead.
|
||||
[${link.intlLabel.defaultMessage}]: [deprecated] addSettingsLink() was called with an async Component from the plugin "${link.intlLabel.defaultMessage}". Component loaders should return a dynamic import with a default export shape, e.g. \`Component: () => import(path).then((mod) => ({ default: mod.Component }))\`. Async wrapper functions will stop being supported in a future version.
|
||||
`.trim()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ describe('ADMIN | new StrapiApp', () => {
|
||||
|
||||
expect(consoleSpy.mock.calls).toHaveLength(1);
|
||||
expect(consoleSpy.mock.calls[0][0]).toBe(
|
||||
'[bar]: [deprecated] addSettingsLink() was called with an async Component from the plugin "bar". This will be removed in the future. Please use: `Component: () => import(path)` ensuring you return a default export instead.'
|
||||
'[bar]: [deprecated] addSettingsLink() was called with an async Component from the plugin "bar". Component loaders should return a dynamic import with a default export shape, e.g. `Component: () => import(path).then((mod) => ({ default: mod.Component }))`. Async wrapper functions will stop being supported in a future version.'
|
||||
);
|
||||
|
||||
console.warn = originalWarn;
|
||||
@@ -467,6 +467,28 @@ describe('ADMIN | new StrapiApp', () => {
|
||||
expect(typeof app.router.menu[0].icon).toBe('function');
|
||||
});
|
||||
|
||||
it('addMenuLink should allow a menu-only link', () => {
|
||||
const app = new StrapiApp();
|
||||
const link = {
|
||||
to: 'content-manager',
|
||||
intlLabel: { id: 'content-manager.plugin.name', defaultMessage: 'Content Manager' },
|
||||
permissions: [],
|
||||
icon: jest.fn(),
|
||||
};
|
||||
|
||||
app.addMenuLink(link as Parameters<typeof app.addMenuLink>[0]);
|
||||
|
||||
expect(app.router.menu[0]).toEqual({
|
||||
icon: expect.any(Function),
|
||||
intlLabel: {
|
||||
defaultMessage: 'Content Manager',
|
||||
id: 'content-manager.plugin.name',
|
||||
},
|
||||
permissions: [],
|
||||
to: 'content-manager',
|
||||
});
|
||||
});
|
||||
|
||||
it('should warn if a user supplies an absolute link', () => {
|
||||
const originalWarn = console.warn;
|
||||
const consoleSpy = jest.fn();
|
||||
@@ -513,7 +535,7 @@ describe('ADMIN | new StrapiApp', () => {
|
||||
|
||||
expect(consoleSpy.mock.calls).toHaveLength(1);
|
||||
expect(consoleSpy.mock.calls[0][0]).toBe(
|
||||
'[bar]: [deprecated] addMenuLink() was called with an async Component from the plugin "bar". This will be removed in the future. Please use: `Component: () => import(path)` ensuring you return a default export instead.'
|
||||
'[bar]: [deprecated] addMenuLink() was called with an async Component from the plugin "bar". Component loaders should return a dynamic import with a default export shape, e.g. `Component: () => import(path).then((mod) => ({ default: mod.Component }))`. Async wrapper functions will stop being supported in a future version.'
|
||||
);
|
||||
|
||||
console.warn = originalWarn;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { previewAdmin } from './preview';
|
||||
import { routes } from './router';
|
||||
import { prefixPluginTranslations } from './utils/translations';
|
||||
|
||||
import type { WidgetArgs } from '@strapi/admin/strapi-admin';
|
||||
import type { StrapiApp, WidgetArgs } from '@strapi/admin/strapi-admin';
|
||||
|
||||
// NOTE: we have to preload it to ensure chunks will have it available as global
|
||||
import 'prismjs';
|
||||
@@ -106,7 +106,7 @@ export default {
|
||||
return [lastEditedWidget, lastPublishedWidget, ...widgets, entriesWidget];
|
||||
});
|
||||
},
|
||||
bootstrap(app: any) {
|
||||
bootstrap(app: StrapiApp) {
|
||||
if (typeof historyAdmin.bootstrap === 'function') {
|
||||
historyAdmin.bootstrap(app);
|
||||
}
|
||||
|
||||
@@ -69,9 +69,10 @@ const admin: Plugin.Config.AdminInput = {
|
||||
},
|
||||
licenseOnly: true,
|
||||
permissions: [],
|
||||
async Component() {
|
||||
const { ProtectedReleasesSettingsPage } = await import('./pages/ReleasesSettingsPage');
|
||||
return { default: ProtectedReleasesSettingsPage };
|
||||
Component() {
|
||||
return import('./pages/ReleasesSettingsPage').then((mod) => ({
|
||||
default: mod.ProtectedReleasesSettingsPage,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -119,15 +120,16 @@ const admin: Plugin.Config.AdminInput = {
|
||||
) {
|
||||
app.addSettingsLink('global', {
|
||||
id: pluginId,
|
||||
to: '/plugins/purchase-content-releases',
|
||||
to: 'purchase-content-releases',
|
||||
intlLabel: {
|
||||
id: `${pluginId}.plugin.name`,
|
||||
defaultMessage: 'Releases',
|
||||
},
|
||||
permissions: [],
|
||||
async Component() {
|
||||
const { PurchaseContentReleases } = await import('./pages/PurchaseContentReleases');
|
||||
return { default: PurchaseContentReleases };
|
||||
Component() {
|
||||
return import('./pages/PurchaseContentReleases').then((mod) => ({
|
||||
default: mod.PurchaseContentReleases,
|
||||
}));
|
||||
},
|
||||
licenseOnly: true,
|
||||
});
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
import { PERMISSIONS } from './constants';
|
||||
import { prefixPluginTranslations } from './utils/prefixPluginTranslations';
|
||||
|
||||
import type { StrapiApp } from '@strapi/admin/strapi-admin';
|
||||
import type { Plugin } from '@strapi/types';
|
||||
|
||||
const admin: Plugin.Config.AdminInput = {
|
||||
// TODO typing app in strapi/types as every plugin needs it
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
register(app: any) {
|
||||
register(app: StrapiApp) {
|
||||
// Create the email settings section
|
||||
app.createSettingSection(
|
||||
app.addSettingsLink(
|
||||
{
|
||||
id: 'email',
|
||||
intlLabel: { id: 'email.SettingsNav.section-label', defaultMessage: 'Email Plugin' },
|
||||
},
|
||||
[
|
||||
{
|
||||
intlLabel: {
|
||||
id: 'email.Settings.email.plugin.title',
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
id: 'settings',
|
||||
to: 'email',
|
||||
Component: () =>
|
||||
import('./pages/Settings').then((mod) => ({
|
||||
default: mod.ProtectedSettingsPage,
|
||||
})),
|
||||
permissions: PERMISSIONS.settings,
|
||||
{
|
||||
intlLabel: {
|
||||
id: 'email.Settings.email.plugin.title',
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
]
|
||||
id: 'settings',
|
||||
to: 'email',
|
||||
Component: () =>
|
||||
import('./pages/Settings').then((mod) => ({
|
||||
default: mod.ProtectedSettingsPage,
|
||||
})),
|
||||
permissions: PERMISSIONS.settings,
|
||||
}
|
||||
);
|
||||
app.registerPlugin({
|
||||
id: 'email',
|
||||
|
||||
@@ -32,9 +32,10 @@ const admin: Plugin.Config.AdminInput = {
|
||||
},
|
||||
licenseOnly: true,
|
||||
permissions: [],
|
||||
async Component() {
|
||||
const { Router } = await import('./router');
|
||||
return { default: Router };
|
||||
Component() {
|
||||
return import('./router').then((mod) => ({
|
||||
default: mod.Router,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -66,9 +67,10 @@ const admin: Plugin.Config.AdminInput = {
|
||||
},
|
||||
licenseOnly: true,
|
||||
permissions: [],
|
||||
async Component() {
|
||||
const { PurchaseReviewWorkflows } = await import('./routes/purchase-review-workflows');
|
||||
return { default: PurchaseReviewWorkflows };
|
||||
Component() {
|
||||
return import('./routes/purchase-review-workflows').then((mod) => ({
|
||||
default: mod.PurchaseReviewWorkflows,
|
||||
}));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -67,9 +67,10 @@ const admin: Plugin.Config.AdminInput = {
|
||||
id: getTrad('plugin.name'),
|
||||
defaultMessage: 'Media Library',
|
||||
},
|
||||
async Component() {
|
||||
const { ProtectedSettingsPage } = await import('./pages/SettingsPage/SettingsPage');
|
||||
return { default: ProtectedSettingsPage };
|
||||
Component() {
|
||||
return import('./pages/SettingsPage/SettingsPage').then((mod) => ({
|
||||
default: mod.ProtectedSettingsPage,
|
||||
}));
|
||||
},
|
||||
permissions: PERMISSIONS.settings,
|
||||
});
|
||||
|
||||
@@ -6,11 +6,13 @@ import { Initializer } from './components/Initializer';
|
||||
import { pluginId } from './pluginId';
|
||||
import { prefixPluginTranslations } from './utils/prefixPluginTranslations';
|
||||
|
||||
import type { StrapiApp } from '@strapi/admin/strapi-admin';
|
||||
|
||||
const pluginName = 'Deploy';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default {
|
||||
register(app: any) {
|
||||
register(app: StrapiApp) {
|
||||
const { backendURL } = window.strapi;
|
||||
|
||||
// Only add the plugin menu link and registering it if the project is on development (localhost).
|
||||
@@ -22,11 +24,8 @@ export default {
|
||||
id: `${pluginId}.Plugin.name`,
|
||||
defaultMessage: pluginName,
|
||||
},
|
||||
Component: async () => {
|
||||
const { App } = await import('./pages/App');
|
||||
|
||||
return App;
|
||||
},
|
||||
Component: () => import('./pages/App').then((mod) => ({ default: mod.App })),
|
||||
permissions: [],
|
||||
});
|
||||
const plugin = {
|
||||
id: pluginId,
|
||||
|
||||
@@ -4,9 +4,11 @@ import { PERMISSIONS } from './constants';
|
||||
import { pluginId } from './pluginId';
|
||||
import { prefixPluginTranslations } from './utils/prefixPluginTranslations';
|
||||
|
||||
import type { StrapiApp } from '@strapi/admin/strapi-admin';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default {
|
||||
register(app: any) {
|
||||
register(app: StrapiApp) {
|
||||
app.addMenuLink({
|
||||
to: `plugins/${pluginId}`,
|
||||
icon: Information,
|
||||
@@ -15,10 +17,7 @@ export default {
|
||||
defaultMessage: 'Documentation',
|
||||
},
|
||||
permissions: PERMISSIONS.main,
|
||||
Component: async () => {
|
||||
const { App } = await import('./pages/App');
|
||||
return App;
|
||||
},
|
||||
Component: () => import('./pages/App').then((mod) => ({ default: mod.App })),
|
||||
position: 9,
|
||||
});
|
||||
|
||||
@@ -27,7 +26,7 @@ export default {
|
||||
name: pluginId,
|
||||
});
|
||||
},
|
||||
bootstrap(app: any) {
|
||||
bootstrap(app: StrapiApp) {
|
||||
app.addSettingsLink('global', {
|
||||
intlLabel: {
|
||||
id: `${pluginId}.plugin.name`,
|
||||
@@ -35,10 +34,7 @@ export default {
|
||||
},
|
||||
id: 'documentation',
|
||||
to: pluginId,
|
||||
Component: async () => {
|
||||
const { SettingsPage } = await import('./pages/Settings');
|
||||
return SettingsPage;
|
||||
},
|
||||
Component: () => import('./pages/Settings').then((mod) => ({ default: mod.SettingsPage })),
|
||||
permissions: PERMISSIONS.main,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -30,11 +30,37 @@ import { getTranslation } from './utils/getTranslation';
|
||||
import { prefixPluginTranslations } from './utils/prefixPluginTranslations';
|
||||
import { mutateCTBContentTypeSchema } from './utils/schemas';
|
||||
|
||||
import type { DocumentActionComponent } from '@strapi/content-manager/strapi-admin';
|
||||
import type { StrapiApp } from '@strapi/admin/strapi-admin';
|
||||
import type {
|
||||
ContentManagerPlugin,
|
||||
DocumentActionComponent,
|
||||
HeaderActionComponent,
|
||||
} from '@strapi/content-manager/strapi-admin';
|
||||
|
||||
type ContentTypeBuilderFormsAPI = {
|
||||
addContentTypeSchemaMutation: (mutation: typeof mutateCTBContentTypeSchema) => void;
|
||||
components: {
|
||||
add: (component: { id: string; component: typeof CheckboxConfirmation }) => void;
|
||||
};
|
||||
extendContentType: (extension: {
|
||||
validator: () => Record<string, unknown>;
|
||||
form: {
|
||||
advanced: () => Array<Record<string, unknown>>;
|
||||
};
|
||||
}) => void;
|
||||
extendFields: (
|
||||
fields: typeof LOCALIZED_FIELDS,
|
||||
extension: {
|
||||
form: {
|
||||
advanced: (args: any) => Array<Record<string, unknown>>;
|
||||
};
|
||||
}
|
||||
) => void;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default {
|
||||
register(app: any) {
|
||||
register(app: StrapiApp) {
|
||||
app.addMiddlewares([extendCTBAttributeInitialDataMiddleware, extendCTBInitialDataMiddleware]);
|
||||
app.addMiddlewares([() => i18nApi.middleware]);
|
||||
app.addReducers({
|
||||
@@ -46,7 +72,7 @@ export default {
|
||||
name: pluginId,
|
||||
});
|
||||
},
|
||||
bootstrap(app: any) {
|
||||
bootstrap(app: StrapiApp) {
|
||||
// // Hook that adds a column into the CM's LV table
|
||||
app.registerHook('Admin/CM/pages/ListView/inject-column-in-table', addColumnToTableHook);
|
||||
app.registerHook('Admin/CM/pages/EditView/mutate-edit-view-layout', mutateEditViewHook);
|
||||
@@ -70,19 +96,20 @@ export default {
|
||||
});
|
||||
|
||||
const contentManager = app.getPlugin('content-manager');
|
||||
const contentManagerApis = contentManager.apis as ContentManagerPlugin['config']['apis'];
|
||||
|
||||
contentManager.apis.addDocumentHeaderAction([
|
||||
contentManagerApis.addDocumentHeaderAction([
|
||||
AITranslationStatusAction,
|
||||
LocalePickerAction,
|
||||
FillFromAnotherLocaleAction,
|
||||
]);
|
||||
contentManager.apis.addDocumentAction((actions: DocumentActionComponent[]) => {
|
||||
] as HeaderActionComponent[]);
|
||||
contentManagerApis.addDocumentAction((actions: DocumentActionComponent[]) => {
|
||||
const indexOfDeleteAction = actions.findIndex((action) => action.type === 'delete');
|
||||
actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
|
||||
return actions;
|
||||
});
|
||||
|
||||
contentManager.apis.addDocumentAction((actions: DocumentActionComponent[]) => {
|
||||
contentManagerApis.addDocumentAction((actions: DocumentActionComponent[]) => {
|
||||
// When enabled the bulk locale publish action should be the first action
|
||||
// in 'More Document Actions' and therefore the third action in the array
|
||||
actions.splice(2, 0, BulkLocalePublishAction);
|
||||
@@ -113,7 +140,7 @@ export default {
|
||||
const ctbPlugin = app.getPlugin('content-type-builder');
|
||||
|
||||
if (ctbPlugin) {
|
||||
const ctbFormsAPI = ctbPlugin.apis.forms;
|
||||
const ctbFormsAPI = ctbPlugin.apis.forms as ContentTypeBuilderFormsAPI;
|
||||
ctbFormsAPI.addContentTypeSchemaMutation(mutateCTBContentTypeSchema);
|
||||
ctbFormsAPI.components.add({ id: 'checkboxConfirmation', component: CheckboxConfirmation });
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ import pluginPkg from '../../package.json';
|
||||
import { pluginId } from './pluginId';
|
||||
import { prefixPluginTranslations } from './utils/prefixPluginTranslations';
|
||||
|
||||
import type { StrapiApp } from '@strapi/admin/strapi-admin';
|
||||
|
||||
const name = pluginPkg.strapi.name;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default {
|
||||
register(app: any) {
|
||||
register(app: StrapiApp) {
|
||||
app.registerPlugin({
|
||||
id: pluginId,
|
||||
name,
|
||||
|
||||
Reference in New Issue
Block a user