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(