diff --git a/dashboard/tailwind.config.js b/dashboard/tailwind.config.js index c37aa573..c7cd96db 100644 --- a/dashboard/tailwind.config.js +++ b/dashboard/tailwind.config.js @@ -16,7 +16,7 @@ export default { ...frappeUIContent, './index.html', './src/**/*.{vue,js,ts,jsx,tsx}', - ...readPluginApps().map((app) => `${sourceDirOf(app)}/**/*.vue`), + ...readPluginApps().map((app) => `${sourceDirOf(app)}/**/*.{vue,js,ts}`), ], safelist: pluginIcons.map((name) => `lucide-${name}`), } diff --git a/docs/implementation/media/plugin-js-classes-after.png b/docs/implementation/media/plugin-js-classes-after.png new file mode 100644 index 00000000..65fcd686 Binary files /dev/null and b/docs/implementation/media/plugin-js-classes-after.png differ diff --git a/docs/implementation/media/plugin-js-classes-before.png b/docs/implementation/media/plugin-js-classes-before.png new file mode 100644 index 00000000..d32c87bf Binary files /dev/null and b/docs/implementation/media/plugin-js-classes-before.png differ diff --git a/docs/implementation/media/plugin-page-dialog.png b/docs/implementation/media/plugin-page-dialog.png new file mode 100644 index 00000000..025e82ba Binary files /dev/null and b/docs/implementation/media/plugin-page-dialog.png differ diff --git a/packages/plugin-kit/README.md b/packages/plugin-kit/README.md index 0275f103..0e253393 100644 --- a/packages/plugin-kit/README.md +++ b/packages/plugin-kit/README.md @@ -182,7 +182,7 @@ Folder and `plugin` problems are collected and reported together. | A command with a template or `\n`, - }, - new RegExp( - `do not import ${name} from '${specifier}'[\\s\\S]*${hint.source}`, - ), - ); + test('a page and an action may each open their own Dialog', async () => { + await buildApp({ + 'pages/jobs/index.vue': `${page}\n`, + 'order/actions/resend/index.vue': vue( + `{ label: 'Resend' }`, + `\n`, + ), }); - } + }); for (const name of ['createResource', 'useCall', 'useList', 'call']) { test(`importing ${name} from frappe-ui fails and points at useMethodRead`, async () => { @@ -446,19 +441,6 @@ describe('guards', () => { ); }); } - - test('a Dialog in shared code fails too', async () => { - await buildFails( - { - 'order/actions/resend/index.vue': vue( - `{ label: 'Resend' }`, - `\n`, - ), - 'shared/open.js': `import { Dialog } from 'frappe-ui'\nexport const open = () => console.log(Dialog)\n`, - }, - /do not import Dialog from 'frappe-ui'/, - ); - }); }); describe('detail pages', () => { diff --git a/packages/plugin-kit/vite.js b/packages/plugin-kit/vite.js index eb3317f0..889fcd12 100644 --- a/packages/plugin-kit/vite.js +++ b/packages/plugin-kit/vite.js @@ -33,14 +33,6 @@ const SKIPPED_DIRS = new Set(['node_modules', 'dist']); const ICON_FILE = 'plugin-icon.svg'; const ICON_LIMIT = 20 * 1024; -// The host draws these frames itself, so an app that draws its own gets two headers or a dialog on a dialog. -const HOST_FRAMES = { - 'frappe-ui': { - Dialog: - 'Commera draws action dialogs; put the form in an action and drive its button with useAction()', - }, -}; - const FRAPPE_V1 = new Set([ 'createResource', 'createListResource', @@ -378,7 +370,7 @@ export function discoverPlugins( isIndex ? `${display} declares a plugin block but ${placeOf( folder, - )} isn't a Commera placement; valid places:\n${placementTable()}` + )} isn't a Commera placement; valid places:\n${placementTable()}` : `${display} declares a plugin block, but only a placement's index.vue may; valid places:\n${placementTable()}`, ); continue; @@ -556,12 +548,6 @@ function guard({ hostDir, compiler, pluginFiles, pageEntries }) { for (const [specifier, names] of Object.entries( chunk.importedBindings, )) { - const frames = HOST_FRAMES[specifier] ?? {}; - for (const name of names.filter((name) => frames[name])) { - problems.push( - `${chunk.fileName}: do not import ${name} from '${specifier}': ${frames[name]}`, - ); - } const callsV1 = (name) => specifier === 'frappe-ui' && FRAPPE_V1.has(name); for (const name of names.filter(callsV1)) { @@ -573,10 +559,7 @@ function guard({ hostDir, compiler, pluginFiles, pageEntries }) { const available = sharedExports[specifier] ?? []; const missing = names.filter( (name) => - name !== '*' && - !frames[name] && - !callsV1(name) && - !available.includes(name), + name !== '*' && !callsV1(name) && !available.includes(name), ); if (missing.length) { problems.push(