@aiot-nexus/plugin-sdk 1.0.1 → 1.0.2
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/README.md +14 -5
- package/dev-host/host.html +82 -15
- package/dev-host/main.js +98 -8
- package/dist/dev-host-metadata.json +3 -0
- package/dist/src/cli/run.js +103 -3
- package/dist/src/dev.d.ts +21 -9
- package/dist/src/dev.js +100 -19
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/scaffold.js +2 -0
- package/dist/src/validation.d.ts +4 -1
- package/dist/src/validation.js +8 -6
- package/dist/src/web-dev.d.ts +11 -0
- package/dist/src/web-dev.js +379 -0
- package/package.json +6 -3
- package/templates/minimal/README.md.tmpl +5 -2
- package/templates/minimal/scripts/build.js.tmpl +21 -4
- package/templates/minimal/src/renderer/app.ts.tmpl +37 -4
- package/templates/minimal/src/renderer/index.html +2 -2
- package/templates/minimal/src/renderer/plugin.css +34 -27
- package/templates/sqlite/README.md.tmpl +5 -2
- package/templates/sqlite/scripts/build.js.tmpl +28 -7
- package/templates/sqlite/src/renderer/app.ts.tmpl +37 -4
- package/templates/sqlite/src/renderer/index.html +2 -2
- package/templates/sqlite/src/renderer/plugin.css +52 -38
|
@@ -6,6 +6,7 @@ AIoT Nexus independent PluginFrame plugin generated from the `sqlite` template.
|
|
|
6
6
|
npm install
|
|
7
7
|
npm run typecheck
|
|
8
8
|
npm run build
|
|
9
|
+
npm run dev:web
|
|
9
10
|
npm run dev
|
|
10
11
|
```
|
|
11
12
|
|
|
@@ -13,10 +14,12 @@ Every `npm run build` rebuilds `better-sqlite3@8.7.0` for Electron 22.3.27 with
|
|
|
13
14
|
|
|
14
15
|
The deployable plugin package is `dist/__PLUGIN_ID__/`. Copy that directory to the Nexus executable's `Plugins/__PLUGIN_ID__/` directory, then restart Nexus. Runtime data is stored in the host-provided plugin data directory and is not written into the plugin package.
|
|
15
16
|
|
|
16
|
-
The renderer follows `context.language` from Nexus, subscribes to in-place context updates without reloading the iframe, and includes `en-US` and `zh-CN` message catalogs. Static labels, CRUD status messages, action buttons, validation text, and date formatting switch together. Edit renderer messages in `src/renderer/app.ts`; edit host-shell titles and descriptions in `src/manifest.json` resources.
|
|
17
|
+
The renderer follows `context.language` and `context.themeMode` from Nexus, subscribes to in-place context updates without reloading the iframe, and includes `en-US` and `zh-CN` message catalogs. The plugin page has no language or theme selector; the controls shown by `npm run dev` belong to the debug host and simulate Nexus context changes. Static labels, CRUD status messages, action buttons, validation text, and date formatting switch together. Edit renderer messages in `src/renderer/app.ts`; edit host-shell titles and descriptions in `src/manifest.json` resources.
|
|
18
|
+
|
|
19
|
+
Use `npm run dev:web` for renderer-only layout, styling, localization, and responsive checks in the system browser. It runs `build:web`, writes an isolated package under `.nexus-plugin-dev/web-package/`, and does not rebuild or load `better-sqlite3`, execute `mainEntry`, copy native runtime files, or overwrite the deployable `dist` package. It builds with source maps, serves only on `127.0.0.1:4173`, and opens the browser automatically. Database operations report unsupported; use `npm run dev` for SQLite and Host API integration. Pass `-- --no-open` or `-- --port <port>` when needed.
|
|
17
20
|
|
|
18
21
|
When this project was created from a local SDK archive, `vendor/aiot-nexus-plugin-sdk.tgz` is part of the source project and must be kept when the project is moved or committed.
|
|
19
22
|
|
|
20
23
|
For main-process breakpoints, open this plugin directory in VS Code, set breakpoints in `src/main.ts`, and run `Debug Nexus plugin`. If child-process auto attach is disabled, start `npm run dev:debug` and select `Attach Nexus plugin main (9229)`. Renderer DevTools opens automatically, with `src/renderer/app.ts` available through the development source map. The default debug build also runs the Electron 22.3.27 native rebuild before launch. Use `npm run dev -- --no-build` only when intentionally reusing a compatible current `dist` output.
|
|
21
24
|
|
|
22
|
-
The independent host stores the SQLite database and settings under `.nexus-plugin-dev/data/` and mirrors the PluginFrame protocol and current Host API surface. Run the deployable `dist/__PLUGIN_ID__/` in Nexus before delivery because the standalone host does not reproduce the full application shell or routing state.
|
|
25
|
+
The independent host stores the SQLite database and settings under `.nexus-plugin-dev/data/` and mirrors the PluginFrame protocol and current Host API surface. Its simulated Nexus application version defaults to the version recorded by the SDK build; pass `npm run dev -- --host-version <X.Y.Z>` to exercise another compatibility branch. Run the deployable `dist/__PLUGIN_ID__/` in Nexus before delivery because the standalone host does not reproduce the full application shell or routing state.
|
|
@@ -9,7 +9,10 @@ const ts = require("typescript");
|
|
|
9
9
|
const pluginId = "__PLUGIN_ID__";
|
|
10
10
|
const pluginRoot = path.resolve(__dirname, "..");
|
|
11
11
|
const buildDirectory = path.join(pluginRoot, ".build");
|
|
12
|
-
const
|
|
12
|
+
const rendererOnly = readRendererOnlyOption(process.argv.slice(2));
|
|
13
|
+
const outputDirectory = rendererOnly
|
|
14
|
+
? path.join(pluginRoot, ".nexus-plugin-dev", "web-package", pluginId)
|
|
15
|
+
: path.join(pluginRoot, "dist", pluginId);
|
|
13
16
|
const nodeModulesDirectory = path.join(pluginRoot, "node_modules");
|
|
14
17
|
const sdkModuleSpecifier = "@aiot-nexus/plugin-sdk/browser";
|
|
15
18
|
const runtimePackages = ["better-sqlite3", "bindings", "file-uri-to-path"];
|
|
@@ -17,15 +20,21 @@ const runtimePackages = ["better-sqlite3", "bindings", "file-uri-to-path"];
|
|
|
17
20
|
run();
|
|
18
21
|
|
|
19
22
|
function run() {
|
|
20
|
-
|
|
23
|
+
if (!rendererOnly) {
|
|
24
|
+
verifyNativeDependency();
|
|
25
|
+
}
|
|
21
26
|
fs.rmSync(buildDirectory, { recursive: true, force: true });
|
|
22
27
|
fs.rmSync(outputDirectory, { recursive: true, force: true });
|
|
23
|
-
|
|
28
|
+
if (!rendererOnly) {
|
|
29
|
+
runTypeScript("tsconfig.main.json");
|
|
30
|
+
}
|
|
24
31
|
runTypeScript("tsconfig.renderer.json");
|
|
25
32
|
|
|
26
33
|
fs.mkdirSync(path.join(outputDirectory, "renderer", "assets"), { recursive: true });
|
|
27
34
|
fs.copyFileSync(path.join(pluginRoot, "src", "manifest.json"), path.join(outputDirectory, "manifest.json"));
|
|
28
|
-
|
|
35
|
+
if (!rendererOnly) {
|
|
36
|
+
fs.copyFileSync(path.join(buildDirectory, "main", "main.js"), path.join(outputDirectory, "main.cjs"));
|
|
37
|
+
}
|
|
29
38
|
fs.copyFileSync(path.join(pluginRoot, "src", "renderer", "index.html"), path.join(outputDirectory, "renderer", "index.html"));
|
|
30
39
|
fs.copyFileSync(path.join(pluginRoot, "src", "renderer", "plugin.css"), path.join(outputDirectory, "renderer", "assets", "plugin.css"));
|
|
31
40
|
rewriteRendererSdkImport(
|
|
@@ -33,11 +42,23 @@ function run() {
|
|
|
33
42
|
path.join(outputDirectory, "renderer", "assets", "app.js")
|
|
34
43
|
);
|
|
35
44
|
copyBrowserSdk();
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
if (!rendererOnly) {
|
|
46
|
+
for (const packageName of runtimePackages) {
|
|
47
|
+
copyRuntimePackage(packageName);
|
|
48
|
+
}
|
|
38
49
|
}
|
|
39
50
|
fs.rmSync(buildDirectory, { recursive: true, force: true });
|
|
40
|
-
console.log("[" + pluginId + "] built " + outputDirectory);
|
|
51
|
+
console.log("[" + pluginId + "] built " + (rendererOnly ? "browser UI package " : "") + outputDirectory);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function readRendererOnlyOption(args) {
|
|
55
|
+
if (args.length === 0) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
if (args.length === 1 && args[0] === "--renderer-only") {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
throw new Error("Unknown build option: " + args.join(" "));
|
|
41
62
|
}
|
|
42
63
|
|
|
43
64
|
function verifyNativeDependency() {
|
|
@@ -16,6 +16,7 @@ interface SqliteRecord {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
type SupportedLanguage = "en-US" | "zh-CN";
|
|
19
|
+
type ThemeMode = "light" | "dark" | "system";
|
|
19
20
|
type MessageParams = Record<string, string | number>;
|
|
20
21
|
|
|
21
22
|
const englishMessages = {
|
|
@@ -133,8 +134,10 @@ const elements = {
|
|
|
133
134
|
recordsBody: requireElement<HTMLTableSectionElement>("recordsBody"),
|
|
134
135
|
statusLog: requireElement<HTMLElement>("statusLog")
|
|
135
136
|
};
|
|
137
|
+
const systemDarkMode = window.matchMedia("(prefers-color-scheme: dark)");
|
|
136
138
|
|
|
137
139
|
let language: SupportedLanguage = "en-US";
|
|
140
|
+
let themeMode: ThemeMode = "system";
|
|
138
141
|
let records: SqliteRecord[] = [];
|
|
139
142
|
let editingRecord: SqliteRecord | undefined;
|
|
140
143
|
let pendingDeleteId: number | undefined;
|
|
@@ -154,19 +157,22 @@ elements.titleInput.addEventListener("keydown", (event) => {
|
|
|
154
157
|
}
|
|
155
158
|
});
|
|
156
159
|
const stopContextUpdates = client.onContextChanged((context) => {
|
|
157
|
-
|
|
160
|
+
applyContext(context);
|
|
158
161
|
});
|
|
162
|
+
systemDarkMode.addEventListener("change", handleSystemThemeChange);
|
|
159
163
|
window.addEventListener("beforeunload", () => {
|
|
160
164
|
stopContextUpdates();
|
|
165
|
+
systemDarkMode.removeEventListener("change", handleSystemThemeChange);
|
|
161
166
|
client.dispose();
|
|
162
167
|
});
|
|
163
168
|
|
|
164
|
-
applyLanguage(language);
|
|
165
|
-
|
|
166
169
|
void client.waitForContext().then((context) => {
|
|
167
|
-
|
|
170
|
+
applyContext(context);
|
|
168
171
|
return refreshAll();
|
|
169
172
|
}).catch((error: unknown) => {
|
|
173
|
+
applyLanguage(language);
|
|
174
|
+
applyTheme(themeMode);
|
|
175
|
+
revealPluginContent();
|
|
170
176
|
writeStatusMessage("error.initializationFailed", { message: errorMessage(error) });
|
|
171
177
|
});
|
|
172
178
|
|
|
@@ -389,6 +395,33 @@ function applyLanguage(nextLanguage: SupportedLanguage): void {
|
|
|
389
395
|
client.notifyResize();
|
|
390
396
|
}
|
|
391
397
|
|
|
398
|
+
function applyContext(context: { language: string; themeMode: ThemeMode }): void {
|
|
399
|
+
applyLanguage(resolveLanguage(context.language));
|
|
400
|
+
applyTheme(context.themeMode);
|
|
401
|
+
revealPluginContent();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function revealPluginContent(): void {
|
|
405
|
+
document.documentElement.dataset.contextReady = "true";
|
|
406
|
+
document.body.hidden = false;
|
|
407
|
+
client.notifyResize();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function applyTheme(nextThemeMode: ThemeMode): void {
|
|
411
|
+
themeMode = nextThemeMode;
|
|
412
|
+
const resolvedTheme = themeMode === "system"
|
|
413
|
+
? (systemDarkMode.matches ? "dark" : "light")
|
|
414
|
+
: themeMode;
|
|
415
|
+
document.documentElement.dataset.theme = resolvedTheme;
|
|
416
|
+
document.documentElement.style.colorScheme = resolvedTheme;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function handleSystemThemeChange(): void {
|
|
420
|
+
if (themeMode === "system") {
|
|
421
|
+
applyTheme(themeMode);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
392
425
|
function renderState(state: LocalizedState): string {
|
|
393
426
|
return state.kind === "message" ? text(state.key, state.params) : state.value;
|
|
394
427
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
|
-
<html lang="en-US">
|
|
2
|
+
<html lang="en-US" data-context-ready="false">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title data-i18n="document.title">Plugin SQLite</title>
|
|
7
7
|
<link rel="stylesheet" href="assets/plugin.css">
|
|
8
8
|
</head>
|
|
9
|
-
<body>
|
|
9
|
+
<body hidden>
|
|
10
10
|
<main class="plugin-shell">
|
|
11
11
|
<header class="plugin-header">
|
|
12
12
|
<div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
:root {
|
|
2
|
-
color-scheme: light
|
|
2
|
+
color-scheme: light;
|
|
3
3
|
font-family: "Segoe UI", Arial, sans-serif;
|
|
4
4
|
background: #f3f5f7;
|
|
5
5
|
color: #20252b;
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
box-sizing: border-box;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
:root:not([data-context-ready="true"]) .plugin-shell {
|
|
13
|
+
visibility: hidden;
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
body {
|
|
13
17
|
margin: 0;
|
|
14
18
|
min-height: 0;
|
|
@@ -24,6 +28,7 @@ body {
|
|
|
24
28
|
.plugin-header,
|
|
25
29
|
.summary,
|
|
26
30
|
.panel {
|
|
31
|
+
min-width: 0;
|
|
27
32
|
border: 1px solid #d4d9df;
|
|
28
33
|
border-radius: 8px;
|
|
29
34
|
background: #ffffff;
|
|
@@ -37,6 +42,10 @@ body {
|
|
|
37
42
|
padding: 14px 16px;
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
.plugin-header > div {
|
|
46
|
+
min-width: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
h1,
|
|
41
50
|
h2,
|
|
42
51
|
p {
|
|
@@ -180,6 +189,8 @@ button.button-danger {
|
|
|
180
189
|
}
|
|
181
190
|
|
|
182
191
|
.table-wrap {
|
|
192
|
+
min-width: 0;
|
|
193
|
+
max-width: 100%;
|
|
183
194
|
overflow: auto;
|
|
184
195
|
border: 1px solid #d4d9df;
|
|
185
196
|
border-radius: 6px;
|
|
@@ -229,47 +240,50 @@ td {
|
|
|
229
240
|
}
|
|
230
241
|
}
|
|
231
242
|
|
|
232
|
-
|
|
233
|
-
:
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
243
|
+
:root[data-theme="dark"] {
|
|
244
|
+
color-scheme: dark;
|
|
245
|
+
background: #16191d;
|
|
246
|
+
color: #edf0f2;
|
|
247
|
+
}
|
|
238
248
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
background: #24282d;
|
|
244
|
-
}
|
|
249
|
+
:root[data-theme="dark"] body {
|
|
250
|
+
background: #16191d;
|
|
251
|
+
color: #edf0f2;
|
|
252
|
+
}
|
|
245
253
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
254
|
+
:root[data-theme="dark"] .plugin-header,
|
|
255
|
+
:root[data-theme="dark"] .summary,
|
|
256
|
+
:root[data-theme="dark"] .panel {
|
|
257
|
+
border-color: #454b52;
|
|
258
|
+
background: #24282d;
|
|
259
|
+
}
|
|
252
260
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
261
|
+
:root[data-theme="dark"] .plugin-header p,
|
|
262
|
+
:root[data-theme="dark"] .summary span,
|
|
263
|
+
:root[data-theme="dark"] #statusLog,
|
|
264
|
+
:root[data-theme="dark"] .empty-state {
|
|
265
|
+
color: #aeb7c2;
|
|
266
|
+
}
|
|
260
267
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
268
|
+
:root[data-theme="dark"] input,
|
|
269
|
+
:root[data-theme="dark"] textarea,
|
|
270
|
+
:root[data-theme="dark"] button.button-secondary {
|
|
271
|
+
border-color: #59616a;
|
|
272
|
+
background: #191c20;
|
|
273
|
+
color: #edf0f2;
|
|
274
|
+
}
|
|
265
275
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
276
|
+
:root[data-theme="dark"] .table-wrap,
|
|
277
|
+
:root[data-theme="dark"] .empty-state {
|
|
278
|
+
border-color: #454b52;
|
|
279
|
+
}
|
|
270
280
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
281
|
+
:root[data-theme="dark"] th {
|
|
282
|
+
background: #2d3238;
|
|
283
|
+
color: #d2d8de;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
:root[data-theme="dark"] th,
|
|
287
|
+
:root[data-theme="dark"] td {
|
|
288
|
+
border-bottom-color: #454b52;
|
|
275
289
|
}
|