@aiot-nexus/plugin-sdk 2.0.2 → 2.1.0

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.
Files changed (31) hide show
  1. package/README.md +18 -8
  2. package/dev-host/main.js +134 -7
  3. package/dev-host/plugin-host.js +1 -427
  4. package/dist/.generated/plugin-framework-version.d.ts +1 -1
  5. package/dist/.generated/plugin-framework-version.js +1 -1
  6. package/dist/.generated/plugin-manifest.schema.json +1 -1
  7. package/dist/internal/src-electron/main/core/runtime-result.js +42 -0
  8. package/dist/internal/src-electron/main/plugins/plugin-electron-facade-broker.js +890 -0
  9. package/dist/internal/src-electron/plugin-host-bootstrap.js +417 -0
  10. package/dist/internal/src-electron/shared/contracts.js +2 -0
  11. package/dist/internal/src-electron/shared/plugin-electron-facade-client.js +181 -0
  12. package/dist/internal/src-electron/shared/plugin-electron-facade-descriptors.js +70 -0
  13. package/dist/internal/src-electron/shared/plugin-electron-facade.js +243 -0
  14. package/dist/internal/src-electron/shared/plugin-rpc.js +245 -0
  15. package/dist/src/electron-facade.d.ts +4 -0
  16. package/dist/src/electron-facade.js +56 -0
  17. package/dist/src/index.d.ts +2 -1
  18. package/dist/src/index.js +2 -1
  19. package/dist/src/nexus-dev.js +5 -4
  20. package/dist/src/scaffold.js +2 -2
  21. package/dist/src/types.d.ts +86 -2
  22. package/dist/src/web-dev.js +2 -2
  23. package/package.json +7 -2
  24. package/templates/minimal/README.md.tmpl +35 -2
  25. package/templates/minimal/src/main.ts.tmpl +2 -1
  26. package/templates/sqlite/README.md.tmpl +30 -2
  27. package/templates/sqlite/src/better-sqlite3.d.ts +12 -1
  28. package/templates/sqlite/src/main.ts.tmpl +939 -124
  29. package/templates/sqlite/src/renderer/app.ts.tmpl +688 -181
  30. package/templates/sqlite/src/renderer/index.html +40 -22
  31. package/templates/sqlite/src/renderer/plugin.css +302 -90
@@ -3,53 +3,71 @@
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title data-i18n="document.title">Plugin SQLite</title>
6
+ <title data-i18n="document.title">SQLite Browser</title>
7
7
  <link rel="stylesheet" href="assets/plugin.css">
8
8
  </head>
9
9
  <body hidden>
10
10
  <main class="plugin-shell">
11
11
  <header class="plugin-header">
12
- <div>
13
- <h1 data-i18n="heading.records">SQLite Records</h1>
12
+ <div class="database-heading">
13
+ <h1 data-i18n="heading.browser">SQLite Browser</h1>
14
14
  <p id="databasePath" data-i18n="status.connecting">Connecting</p>
15
15
  </div>
16
- <button id="refreshButton" class="button-secondary" type="button" data-i18n="action.refresh">Refresh</button>
16
+ <div class="toolbar" aria-label="Database actions" data-i18n-aria-label="toolbar.databaseActions">
17
+ <button id="openDatabaseButton" type="button" data-i18n="action.openDatabase">Open Database</button>
18
+ <button id="useDefaultDatabaseButton" class="button-secondary" type="button" data-i18n="action.useDefault">Use Sample</button>
19
+ <button id="refreshButton" class="button-secondary" type="button" data-i18n="action.refresh">Refresh</button>
20
+ </div>
17
21
  </header>
18
22
 
19
23
  <section class="summary" aria-label="Database summary" data-i18n-aria-label="summary.aria">
20
24
  <div><span data-i18n="summary.database">Database</span><strong id="databaseName">plugin.db</strong></div>
21
- <div><span data-i18n="summary.table">Table</span><strong id="tableName">plugin_records</strong></div>
25
+ <div><span data-i18n="summary.source">Source</span><strong id="databaseSource">Sample</strong></div>
26
+ <label class="table-selector"><span data-i18n="summary.table">Table</span><select id="tableSelect" aria-label="Table" data-i18n-aria-label="summary.table"></select></label>
27
+ <div><span data-i18n="summary.columns">Columns</span><strong id="columnCount">0</strong></div>
22
28
  <div><span data-i18n="summary.rows">Rows</span><strong id="recordCount">0</strong></div>
23
29
  <div><span data-i18n="summary.status">Status</span><strong id="loadingState" data-i18n="status.waiting">Waiting</strong></div>
24
30
  </section>
25
31
 
26
- <section class="panel">
27
- <h2 id="entryFormTitle" data-i18n="form.insertRow">Insert Row</h2>
28
- <div class="entry-form">
29
- <label><span data-i18n="field.title">Title</span><input id="titleInput" type="text" maxlength="80" autocomplete="off"></label>
30
- <label><span data-i18n="field.note">Note</span><textarea id="noteInput" maxlength="500" rows="2"></textarea></label>
31
- <div class="entry-actions">
32
- <button id="insertButton" type="button" data-i18n="action.insert">Insert</button>
33
- <button id="cancelEditButton" class="button-secondary" type="button" data-i18n="action.cancel" hidden>Cancel</button>
32
+ <section id="editorPanel" class="editor-panel" hidden>
33
+ <div class="panel-heading">
34
+ <div>
35
+ <h2 id="editorTitle" data-i18n="editor.insert">Insert Row</h2>
36
+ <p data-i18n="editor.help">Choose how each SQLite column should be written.</p>
34
37
  </div>
38
+ <button id="closeEditorButton" class="button-secondary compact-button" type="button" data-i18n="action.close">Close</button>
35
39
  </div>
40
+ <div id="editorFields" class="editor-fields"></div>
36
41
  <p id="formError" class="error" hidden></p>
42
+ <div class="editor-actions">
43
+ <button id="saveRowButton" type="button" data-i18n="action.insert">Insert</button>
44
+ <button id="cancelEditorButton" class="button-secondary" type="button" data-i18n="action.cancel">Cancel</button>
45
+ </div>
37
46
  </section>
38
47
 
39
- <section class="panel recent-rows-panel">
40
- <div class="panel-heading">
41
- <h2 data-i18n="section.recentRows">Recent Rows</h2>
42
- <span id="statusLog" data-i18n="status.idle">Idle</span>
48
+ <section class="data-panel">
49
+ <div class="panel-heading data-heading">
50
+ <div>
51
+ <h2 data-i18n="section.rows">Table Rows</h2>
52
+ <span id="statusLog" data-i18n="status.idle">Idle</span>
53
+ </div>
54
+ <button id="addRowButton" type="button" data-i18n="action.addRow">Add Row</button>
43
55
  </div>
44
- <div id="emptyState" class="empty-state" data-i18n="empty.noRows" hidden>No rows yet.</div>
56
+ <div id="emptyState" class="empty-state" data-i18n="empty.noRows" hidden>No rows in this table.</div>
45
57
  <div class="table-wrap">
46
- <table>
47
- <thead>
48
- <tr><th data-i18n="table.id">ID</th><th data-i18n="table.title">Title</th><th data-i18n="table.note">Note</th><th data-i18n="table.created">Created</th><th class="actions-column" data-i18n="table.actions">Actions</th></tr>
49
- </thead>
58
+ <table id="recordsTable">
59
+ <thead><tr id="recordsHead"></tr></thead>
50
60
  <tbody id="recordsBody"></tbody>
51
61
  </table>
52
62
  </div>
63
+ <footer class="pager" aria-label="Pagination" data-i18n-aria-label="pager.aria">
64
+ <label><span data-i18n="pager.pageSize">Rows per page</span><select id="pageSizeSelect"><option value="25">25</option><option value="50" selected>50</option><option value="100">100</option></select></label>
65
+ <span id="pageLabel">0-0 / 0</span>
66
+ <div>
67
+ <button id="previousPageButton" class="button-secondary compact-button" type="button" data-i18n="action.previous">Previous</button>
68
+ <button id="nextPageButton" class="button-secondary compact-button" type="button" data-i18n="action.next">Next</button>
69
+ </div>
70
+ </footer>
53
71
  </section>
54
72
  </main>
55
73
  <script type="module" src="assets/app.js"></script>
@@ -7,6 +7,7 @@
7
7
 
8
8
  * {
9
9
  box-sizing: border-box;
10
+ letter-spacing: 0;
10
11
  }
11
12
 
12
13
  :root:not([data-context-ready="true"]) .plugin-shell {
@@ -15,36 +16,66 @@
15
16
 
16
17
  body {
17
18
  margin: 0;
19
+ height: 100vh;
18
20
  min-height: 100vh;
21
+ overflow: hidden;
19
22
  background: #f3f5f7;
20
23
  }
21
24
 
25
+ button,
26
+ input,
27
+ select,
28
+ textarea {
29
+ font: inherit;
30
+ }
31
+
22
32
  .plugin-shell {
23
33
  display: grid;
24
- grid-template-rows: auto auto auto minmax(0, 1fr);
25
- gap: 12px;
26
- min-height: 100vh;
27
- padding: 16px;
34
+ grid-template-rows: auto auto minmax(0, auto) minmax(0, 1fr);
35
+ gap: 10px;
36
+ width: 100%;
37
+ min-width: 0;
38
+ height: 100vh;
39
+ min-height: 0;
40
+ overflow: hidden;
41
+ padding: 12px;
28
42
  }
29
43
 
30
44
  .plugin-header,
31
45
  .summary,
32
- .panel {
46
+ .editor-panel,
47
+ .data-panel {
33
48
  min-width: 0;
34
49
  border: 1px solid #d4d9df;
35
50
  border-radius: 8px;
36
51
  background: #ffffff;
37
52
  }
38
53
 
54
+ .plugin-header {
55
+ grid-row: 1;
56
+ }
57
+
58
+ .summary {
59
+ grid-row: 2;
60
+ }
61
+
62
+ .editor-panel {
63
+ grid-row: 3;
64
+ }
65
+
66
+ .data-panel {
67
+ grid-row: 4;
68
+ }
69
+
39
70
  .plugin-header {
40
71
  display: flex;
41
- align-items: flex-start;
72
+ align-items: center;
42
73
  justify-content: space-between;
43
- gap: 16px;
44
- padding: 14px 16px;
74
+ gap: 12px;
75
+ padding: 12px 14px;
45
76
  }
46
77
 
47
- .plugin-header > div {
78
+ .database-heading {
48
79
  min-width: 0;
49
80
  }
50
81
 
@@ -55,38 +86,88 @@ p {
55
86
  }
56
87
 
57
88
  h1 {
58
- font-size: 22px;
89
+ font-size: 20px;
59
90
  }
60
91
 
61
92
  h2 {
62
93
  font-size: 15px;
63
94
  }
64
95
 
65
- .plugin-header p {
66
- max-width: 760px;
96
+ .database-heading p {
67
97
  overflow: hidden;
68
- margin-top: 4px;
98
+ max-width: min(62vw, 760px);
99
+ margin-top: 3px;
69
100
  color: #65717e;
70
101
  font-size: 12px;
71
102
  text-overflow: ellipsis;
72
103
  white-space: nowrap;
73
104
  }
74
105
 
106
+ .toolbar,
107
+ .editor-actions,
108
+ .row-actions,
109
+ .pager > div {
110
+ display: flex;
111
+ flex-wrap: wrap;
112
+ gap: 6px;
113
+ align-items: center;
114
+ }
115
+
116
+ button {
117
+ min-height: 32px;
118
+ border: 1px solid #1768a6;
119
+ border-radius: 6px;
120
+ padding: 0 11px;
121
+ background: #1768a6;
122
+ color: #ffffff;
123
+ font-weight: 600;
124
+ cursor: pointer;
125
+ }
126
+
127
+ button:disabled,
128
+ select:disabled,
129
+ input:disabled,
130
+ textarea:disabled {
131
+ cursor: default;
132
+ opacity: 0.55;
133
+ }
134
+
135
+ button.button-secondary {
136
+ border-color: #aeb7c2;
137
+ background: #ffffff;
138
+ color: #20252b;
139
+ }
140
+
141
+ button.button-danger {
142
+ border-color: #b42318;
143
+ background: #b42318;
144
+ }
145
+
146
+ .compact-button {
147
+ min-height: 28px;
148
+ padding: 0 9px;
149
+ font-size: 12px;
150
+ }
151
+
75
152
  .summary {
76
153
  display: grid;
77
- grid-template-columns: repeat(4, minmax(100px, 1fr));
78
- gap: 12px;
79
- padding: 12px 16px;
154
+ grid-template-columns: repeat(6, minmax(105px, 1fr));
155
+ gap: 10px;
156
+ padding: 10px 14px;
80
157
  }
81
158
 
82
- .summary div {
159
+ .summary > div,
160
+ .table-selector {
83
161
  display: grid;
84
162
  gap: 3px;
85
163
  min-width: 0;
86
164
  }
87
165
 
88
166
  .summary span,
89
- #statusLog {
167
+ .table-selector > span,
168
+ #statusLog,
169
+ .editor-panel .panel-heading p,
170
+ .field-current {
90
171
  color: #65717e;
91
172
  font-size: 12px;
92
173
  }
@@ -98,99 +179,129 @@ h2 {
98
179
  white-space: nowrap;
99
180
  }
100
181
 
101
- .panel {
102
- padding: 14px 16px;
182
+ input,
183
+ select,
184
+ textarea {
185
+ width: 100%;
186
+ min-width: 0;
187
+ border: 1px solid #aeb7c2;
188
+ border-radius: 6px;
189
+ padding: 7px 9px;
190
+ background: #ffffff;
191
+ color: #20252b;
103
192
  }
104
193
 
105
- .recent-rows-panel {
106
- display: flex;
107
- flex-direction: column;
108
- min-height: 0;
194
+ textarea {
195
+ min-height: 58px;
196
+ resize: vertical;
109
197
  }
110
198
 
111
- .recent-rows-panel .table-wrap {
112
- flex: 1 1 auto;
113
- min-height: 0;
199
+ .table-selector select {
200
+ height: 31px;
201
+ padding-top: 4px;
202
+ padding-bottom: 4px;
114
203
  }
115
204
 
116
- .entry-form {
117
- display: grid;
118
- grid-template-columns: minmax(150px, 1fr) minmax(220px, 2fr) auto;
205
+ .editor-panel {
206
+ max-height: min(38vh, 360px);
207
+ overflow: auto;
208
+ padding: 12px 14px;
209
+ }
210
+
211
+ .panel-heading {
212
+ display: flex;
213
+ align-items: flex-start;
214
+ justify-content: space-between;
119
215
  gap: 12px;
120
- align-items: end;
121
- margin-top: 12px;
216
+ margin-bottom: 9px;
122
217
  }
123
218
 
124
- label {
125
- display: grid;
126
- gap: 5px;
127
- font-size: 12px;
128
- font-weight: 600;
219
+ .panel-heading > div {
220
+ min-width: 0;
129
221
  }
130
222
 
131
- input,
132
- textarea {
133
- width: 100%;
134
- border: 1px solid #aeb7c2;
135
- border-radius: 6px;
136
- padding: 8px 10px;
137
- background: #ffffff;
138
- color: #20252b;
139
- font: inherit;
223
+ .panel-heading p {
224
+ margin-top: 3px;
140
225
  }
141
226
 
142
- textarea {
143
- min-height: 36px;
144
- resize: vertical;
227
+ .editor-fields {
228
+ display: grid;
229
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
230
+ gap: 9px;
231
+ }
232
+
233
+ .editor-field {
234
+ display: grid;
235
+ grid-template-columns: minmax(0, 1fr) 112px;
236
+ gap: 6px 8px;
237
+ align-items: end;
238
+ min-width: 0;
239
+ border-top: 1px solid #e7eaee;
240
+ padding-top: 8px;
145
241
  }
146
242
 
147
- .entry-actions,
148
- .record-actions {
243
+ .field-heading {
149
244
  display: flex;
150
- gap: 8px;
151
- justify-content: flex-end;
245
+ flex-wrap: wrap;
246
+ gap: 5px;
247
+ align-items: center;
248
+ min-width: 0;
249
+ font-size: 12px;
250
+ font-weight: 600;
152
251
  }
153
252
 
154
- button {
155
- min-height: 34px;
156
- border: 1px solid #1768a6;
157
- border-radius: 6px;
158
- padding: 0 12px;
159
- background: #1768a6;
160
- color: #ffffff;
161
- font: inherit;
253
+ .field-heading strong {
254
+ overflow-wrap: anywhere;
255
+ }
256
+
257
+ .column-badge {
258
+ border: 1px solid #ccd3da;
259
+ border-radius: 4px;
260
+ padding: 1px 4px;
261
+ background: #f7f8fa;
262
+ color: #56616d;
263
+ font-size: 10px;
162
264
  font-weight: 600;
163
- cursor: pointer;
164
265
  }
165
266
 
166
- button:disabled {
167
- cursor: default;
168
- opacity: 0.55;
267
+ .field-input,
268
+ .field-current {
269
+ grid-column: 1 / -1;
169
270
  }
170
271
 
171
- button.button-secondary {
172
- border-color: #aeb7c2;
173
- background: #ffffff;
174
- color: #20252b;
272
+ .field-current {
273
+ overflow: hidden;
274
+ text-overflow: ellipsis;
275
+ white-space: nowrap;
175
276
  }
176
277
 
177
- button.button-danger {
178
- border-color: #b42318;
179
- background: #b42318;
278
+ .editor-actions {
279
+ justify-content: flex-end;
280
+ margin-top: 10px;
180
281
  }
181
282
 
182
283
  .error {
183
- margin-top: 10px;
284
+ margin-top: 8px;
184
285
  color: #b42318;
185
286
  font-size: 12px;
186
287
  }
187
288
 
188
- .panel-heading {
289
+ .data-panel {
189
290
  display: flex;
291
+ flex-direction: column;
292
+ min-height: 0;
293
+ overflow: hidden;
294
+ padding: 12px 14px;
295
+ }
296
+
297
+ .data-heading {
190
298
  align-items: center;
191
- justify-content: space-between;
192
- gap: 12px;
193
- margin-bottom: 10px;
299
+ }
300
+
301
+ .data-heading > div {
302
+ display: flex;
303
+ gap: 10px;
304
+ align-items: baseline;
194
305
  }
195
306
 
196
307
  .empty-state {
@@ -202,7 +313,9 @@ button.button-danger {
202
313
  }
203
314
 
204
315
  .table-wrap {
316
+ flex: 1 1 auto;
205
317
  min-width: 0;
318
+ min-height: 80px;
206
319
  max-width: 100%;
207
320
  overflow: auto;
208
321
  border: 1px solid #d4d9df;
@@ -210,45 +323,127 @@ button.button-danger {
210
323
  }
211
324
 
212
325
  table {
213
- width: 100%;
214
- min-width: 720px;
326
+ width: max-content;
327
+ min-width: 100%;
215
328
  border-collapse: collapse;
216
329
  }
217
330
 
218
331
  th,
219
332
  td {
333
+ max-width: 360px;
220
334
  border-bottom: 1px solid #e7eaee;
221
- padding: 8px 10px;
335
+ padding: 7px 9px;
222
336
  text-align: left;
223
337
  vertical-align: top;
224
338
  }
225
339
 
226
340
  th {
341
+ position: sticky;
342
+ z-index: 1;
343
+ top: 0;
344
+ min-width: 120px;
227
345
  background: #f7f8fa;
228
346
  color: #56616d;
229
347
  font-size: 12px;
230
348
  }
231
349
 
350
+ .column-title {
351
+ display: flex;
352
+ flex-wrap: wrap;
353
+ gap: 4px;
354
+ align-items: center;
355
+ }
356
+
232
357
  td {
358
+ overflow: hidden;
233
359
  font-size: 13px;
360
+ text-overflow: ellipsis;
361
+ white-space: pre-wrap;
362
+ overflow-wrap: anywhere;
363
+ }
364
+
365
+ .cell-null,
366
+ .cell-blob,
367
+ .cell-truncated {
368
+ color: #65717e;
369
+ font-family: Consolas, monospace;
370
+ font-size: 12px;
234
371
  }
235
372
 
236
373
  .actions-column {
374
+ right: 0;
237
375
  width: 150px;
376
+ min-width: 150px;
238
377
  }
239
378
 
240
- .record-actions button {
241
- min-height: 28px;
379
+ td.row-actions-cell {
380
+ position: sticky;
381
+ right: 0;
382
+ background: #ffffff;
383
+ }
384
+
385
+ .pager {
386
+ display: flex;
387
+ align-items: center;
388
+ justify-content: flex-end;
389
+ gap: 12px;
390
+ padding-top: 9px;
391
+ color: #65717e;
242
392
  font-size: 12px;
243
393
  }
244
394
 
245
- @media (max-width: 720px) {
246
- .summary,
247
- .entry-form {
395
+ .pager label {
396
+ display: flex;
397
+ gap: 6px;
398
+ align-items: center;
399
+ }
400
+
401
+ .pager select {
402
+ width: 68px;
403
+ padding: 4px 6px;
404
+ }
405
+
406
+ @media (max-width: 900px) {
407
+ .summary {
408
+ grid-template-columns: repeat(3, minmax(100px, 1fr));
409
+ }
410
+ }
411
+
412
+ @media (max-width: 620px) {
413
+ .plugin-shell {
414
+ grid-template-rows: auto auto minmax(0, auto) minmax(220px, 1fr);
415
+ overflow-y: auto;
416
+ padding: 8px;
417
+ }
418
+
419
+ .plugin-header {
420
+ align-items: stretch;
421
+ flex-direction: column;
422
+ }
423
+
424
+ .pager {
425
+ flex-wrap: wrap;
426
+ justify-content: space-between;
427
+ }
428
+
429
+ .database-heading p {
430
+ max-width: 100%;
431
+ }
432
+
433
+ .toolbar button {
434
+ flex: 1 1 auto;
435
+ }
436
+
437
+ .summary {
438
+ grid-template-columns: repeat(2, minmax(100px, 1fr));
439
+ }
440
+
441
+ .editor-fields {
248
442
  grid-template-columns: 1fr;
249
443
  }
250
444
 
251
- .entry-actions {
445
+ .pager > div,
446
+ .editor-actions {
252
447
  justify-content: flex-start;
253
448
  }
254
449
  }
@@ -266,19 +461,29 @@ td {
266
461
 
267
462
  :root[data-theme="dark"] .plugin-header,
268
463
  :root[data-theme="dark"] .summary,
269
- :root[data-theme="dark"] .panel {
464
+ :root[data-theme="dark"] .editor-panel,
465
+ :root[data-theme="dark"] .data-panel,
466
+ :root[data-theme="dark"] td.row-actions-cell {
270
467
  border-color: #454b52;
271
468
  background: #24282d;
272
469
  }
273
470
 
274
- :root[data-theme="dark"] .plugin-header p,
471
+ :root[data-theme="dark"] .database-heading p,
275
472
  :root[data-theme="dark"] .summary span,
473
+ :root[data-theme="dark"] .table-selector > span,
276
474
  :root[data-theme="dark"] #statusLog,
277
- :root[data-theme="dark"] .empty-state {
475
+ :root[data-theme="dark"] .editor-panel .panel-heading p,
476
+ :root[data-theme="dark"] .field-current,
477
+ :root[data-theme="dark"] .empty-state,
478
+ :root[data-theme="dark"] .pager,
479
+ :root[data-theme="dark"] .cell-null,
480
+ :root[data-theme="dark"] .cell-blob,
481
+ :root[data-theme="dark"] .cell-truncated {
278
482
  color: #aeb7c2;
279
483
  }
280
484
 
281
485
  :root[data-theme="dark"] input,
486
+ :root[data-theme="dark"] select,
282
487
  :root[data-theme="dark"] textarea,
283
488
  :root[data-theme="dark"] button.button-secondary {
284
489
  border-color: #59616a;
@@ -286,8 +491,15 @@ td {
286
491
  color: #edf0f2;
287
492
  }
288
493
 
494
+ :root[data-theme="dark"] .column-badge {
495
+ border-color: #59616a;
496
+ background: #30353b;
497
+ color: #d2d8de;
498
+ }
499
+
289
500
  :root[data-theme="dark"] .table-wrap,
290
- :root[data-theme="dark"] .empty-state {
501
+ :root[data-theme="dark"] .empty-state,
502
+ :root[data-theme="dark"] .editor-field {
291
503
  border-color: #454b52;
292
504
  }
293
505