@dxos/app-framework 0.7.5-main.9d2a38b → 0.7.5-main.ff8607b
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/dist/lib/browser/app-graph-builder-F7VZ6LRN.mjs +137 -0
- package/dist/lib/browser/app-graph-builder-F7VZ6LRN.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GNLU3GAU.mjs → chunk-ATRNTMSS.mjs} +623 -819
- package/dist/lib/browser/chunk-ATRNTMSS.mjs.map +7 -0
- package/dist/lib/browser/chunk-LDJ3T4V3.mjs +32 -0
- package/dist/lib/browser/chunk-LDJ3T4V3.mjs.map +7 -0
- package/dist/lib/browser/chunk-WS6SU6HI.mjs +285 -0
- package/dist/lib/browser/chunk-WS6SU6HI.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +57 -74
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/intent-dispatcher-E6J7E5Y5.mjs +11 -0
- package/dist/lib/browser/intent-dispatcher-E6J7E5Y5.mjs.map +7 -0
- package/dist/lib/browser/intent-resolver-XLE4L3LS.mjs +38 -0
- package/dist/lib/browser/intent-resolver-XLE4L3LS.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/store-QU2IKFAI.mjs +19 -0
- package/dist/lib/browser/store-QU2IKFAI.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +10 -3
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/worker.mjs +77 -0
- package/dist/lib/browser/worker.mjs.map +7 -0
- package/dist/lib/node/app-graph-builder-JGBADFF7.cjs +146 -0
- package/dist/lib/node/app-graph-builder-JGBADFF7.cjs.map +7 -0
- package/dist/lib/node/chunk-QLVQ6PND.cjs +58 -0
- package/dist/lib/node/chunk-QLVQ6PND.cjs.map +7 -0
- package/dist/lib/node/chunk-WKC6YMEQ.cjs +1433 -0
- package/dist/lib/node/chunk-WKC6YMEQ.cjs.map +7 -0
- package/dist/lib/node/chunk-WRWRZKZU.cjs +308 -0
- package/dist/lib/node/chunk-WRWRZKZU.cjs.map +7 -0
- package/dist/lib/node/index.cjs +106 -118
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/intent-dispatcher-CFBKDZQR.cjs +32 -0
- package/dist/lib/node/intent-dispatcher-CFBKDZQR.cjs.map +7 -0
- package/dist/lib/node/intent-resolver-3TKCXP4S.cjs +45 -0
- package/dist/lib/node/intent-resolver-3TKCXP4S.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/store-4QMUUU2A.cjs +34 -0
- package/dist/lib/node/store-4QMUUU2A.cjs.map +7 -0
- package/dist/lib/node/testing/index.cjs +15 -8
- package/dist/lib/node/testing/index.cjs.map +3 -3
- package/dist/lib/node/worker.cjs +99 -0
- package/dist/lib/node/worker.cjs.map +7 -0
- package/dist/lib/node-esm/app-graph-builder-2QEX57NX.mjs +138 -0
- package/dist/lib/node-esm/app-graph-builder-2QEX57NX.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-KPMTPXQI.mjs → chunk-44J2VZBB.mjs} +623 -819
- package/dist/lib/node-esm/chunk-44J2VZBB.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-CNJYZNSL.mjs +34 -0
- package/dist/lib/node-esm/chunk-CNJYZNSL.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HTLXL32I.mjs +286 -0
- package/dist/lib/node-esm/chunk-HTLXL32I.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +57 -74
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/intent-dispatcher-LDQGDZ62.mjs +12 -0
- package/dist/lib/node-esm/intent-dispatcher-LDQGDZ62.mjs.map +7 -0
- package/dist/lib/node-esm/intent-resolver-7VJWN67U.mjs +39 -0
- package/dist/lib/node-esm/intent-resolver-7VJWN67U.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/store-VWDAYUQY.mjs +20 -0
- package/dist/lib/node-esm/store-VWDAYUQY.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +10 -3
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/worker.mjs +78 -0
- package/dist/lib/node-esm/worker.mjs.map +7 -0
- package/dist/types/src/App.d.ts.map +1 -1
- package/dist/types/src/common/capabilities.d.ts +63 -110
- package/dist/types/src/common/capabilities.d.ts.map +1 -1
- package/dist/types/src/common/events.d.ts +8 -1
- package/dist/types/src/common/events.d.ts.map +1 -1
- package/dist/types/src/common/file.d.ts +1 -1
- package/dist/types/src/common/file.d.ts.map +1 -1
- package/dist/types/src/common/graph.d.ts +2 -2
- package/dist/types/src/common/graph.d.ts.map +1 -1
- package/dist/types/src/common/index.d.ts +0 -1
- package/dist/types/src/common/index.d.ts.map +1 -1
- package/dist/types/src/common/layout.d.ts +204 -121
- package/dist/types/src/common/layout.d.ts.map +1 -1
- package/dist/types/src/common/surface.d.ts +3 -3
- package/dist/types/src/common/surface.d.ts.map +1 -1
- package/dist/types/src/common/translations.d.ts +7 -7
- package/dist/types/src/common/translations.d.ts.map +1 -1
- package/dist/types/src/core/capabilities.d.ts +6 -2
- package/dist/types/src/core/capabilities.d.ts.map +1 -1
- package/dist/types/src/core/manager.d.ts +2 -9
- package/dist/types/src/core/manager.d.ts.map +1 -1
- package/dist/types/src/core/plugin.d.ts +5 -2
- package/dist/types/src/core/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -1
- package/dist/types/src/playground/generator/generator.d.ts +2 -0
- package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
- package/dist/types/src/playground/generator/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -1
- package/dist/types/src/playground/logger/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/logger/schema.d.ts +1 -1
- package/dist/types/src/playground/logger/schema.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/actions.d.ts +1 -1
- package/dist/types/src/plugin-intent/actions.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/index.d.ts +0 -1
- package/dist/types/src/plugin-intent/index.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +27 -20
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/intent.d.ts +3 -3
- package/dist/types/src/plugin-intent/intent.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/actions.d.ts +11 -1
- package/dist/types/src/plugin-settings/actions.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/app-graph-builder.d.ts +197 -0
- package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/intent-resolver.d.ts +4 -0
- package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/store.d.ts +5 -0
- package/dist/types/src/plugin-settings/store.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/translations.d.ts +11 -0
- package/dist/types/src/plugin-settings/translations.d.ts.map +1 -0
- package/dist/types/src/{plugin-intent → react}/IntentContext.d.ts +1 -1
- package/dist/types/src/react/IntentContext.d.ts.map +1 -0
- package/dist/types/src/react/Surface.d.ts.map +1 -1
- package/dist/types/src/react/Surface.stories.d.ts +16 -0
- package/dist/types/src/react/Surface.stories.d.ts.map +1 -0
- package/dist/types/src/react/common.d.ts +12 -0
- package/dist/types/src/react/common.d.ts.map +1 -0
- package/dist/types/src/react/index.d.ts +2 -0
- package/dist/types/src/react/index.d.ts.map +1 -1
- package/dist/types/src/react/useIntentResolver.d.ts +3 -0
- package/dist/types/src/react/useIntentResolver.d.ts.map +1 -0
- package/dist/types/src/testing/withPluginManager.d.ts +1 -1
- package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
- package/dist/types/src/worker.d.ts +4 -0
- package/dist/types/src/worker.d.ts.map +1 -0
- package/package.json +26 -20
- package/project.json +3 -3
- package/src/App.tsx +15 -14
- package/src/common/capabilities.ts +20 -11
- package/src/common/events.ts +10 -1
- package/src/common/file.ts +1 -1
- package/src/common/graph.ts +2 -2
- package/src/common/index.ts +0 -1
- package/src/common/layout.ts +194 -126
- package/src/common/surface.ts +2 -2
- package/src/common/translations.ts +7 -8
- package/src/core/capabilities.ts +16 -7
- package/src/core/manager.test.ts +22 -73
- package/src/core/manager.ts +105 -91
- package/src/core/plugin.ts +6 -3
- package/src/playground/debug/plugin.ts +1 -1
- package/src/playground/generator/Toolbar.tsx +11 -11
- package/src/playground/generator/generator.ts +25 -0
- package/src/playground/generator/plugin.ts +6 -1
- package/src/playground/layout/plugin.ts +1 -1
- package/src/playground/logger/Toolbar.tsx +2 -1
- package/src/playground/logger/plugin.ts +6 -3
- package/src/playground/logger/schema.ts +1 -1
- package/src/plugin-intent/IntentPlugin.tsx +3 -43
- package/src/plugin-intent/actions.ts +1 -1
- package/src/plugin-intent/index.ts +0 -1
- package/src/plugin-intent/intent-dispatcher.test.ts +48 -29
- package/src/plugin-intent/intent-dispatcher.ts +76 -41
- package/src/plugin-intent/intent.ts +5 -5
- package/src/plugin-settings/SettingsPlugin.ts +19 -13
- package/src/plugin-settings/actions.ts +11 -1
- package/src/plugin-settings/app-graph-builder.ts +122 -0
- package/src/plugin-settings/intent-resolver.ts +28 -0
- package/src/plugin-settings/store.ts +20 -0
- package/src/plugin-settings/translations.ts +17 -0
- package/src/{plugin-intent → react}/IntentContext.tsx +2 -2
- package/src/react/Surface.stories.tsx +96 -0
- package/src/react/Surface.tsx +11 -8
- package/src/react/common.ts +12 -0
- package/src/react/index.ts +2 -0
- package/src/react/useIntentResolver.ts +22 -0
- package/src/testing/withPluginManager.tsx +11 -3
- package/src/worker.ts +11 -0
- package/tsconfig.json +3 -3
- package/dist/lib/browser/chunk-GNLU3GAU.mjs.map +0 -7
- package/dist/lib/node/chunk-FBA4BB3J.cjs +0 -1639
- package/dist/lib/node/chunk-FBA4BB3J.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-KPMTPXQI.mjs.map +0 -7
- package/dist/types/src/common/navigation.d.ts +0 -241
- package/dist/types/src/common/navigation.d.ts.map +0 -1
- package/dist/types/src/plugin-intent/IntentContext.d.ts.map +0 -1
- package/src/common/navigation.ts +0 -199
package/src/core/capabilities.ts
CHANGED
|
@@ -79,17 +79,20 @@ export const contributes = <T>(
|
|
|
79
79
|
return { interface: interfaceDef, implementation, deactivate } satisfies Capability<T>;
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
type
|
|
82
|
+
type LoadCapability<T, U> = () => Promise<{ default: (props: T) => MaybePromise<Capability<U>> }>;
|
|
83
|
+
type LoadCapabilities<T> = () => Promise<{ default: (props: T) => MaybePromise<AnyCapability[]> }>;
|
|
84
|
+
// TODO(wittjosiah): Not having the array be `any` causes type errors when using the lazy capability.
|
|
85
|
+
type LazyCapability<T, U> = (props?: T) => Promise<() => Promise<Capability<U> | AnyCapability[]>>;
|
|
83
86
|
|
|
84
87
|
/**
|
|
85
88
|
* Helper to define a lazily loaded implementation of a capability.
|
|
86
89
|
*/
|
|
87
90
|
export const lazy =
|
|
88
|
-
<T, U>(c:
|
|
89
|
-
(props?: T)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
<T, U>(c: LoadCapability<T, U> | LoadCapabilities<T>): LazyCapability<T, U> =>
|
|
92
|
+
async (props?: T) => {
|
|
93
|
+
const { default: getCapability } = await c();
|
|
94
|
+
return async () => getCapability(props as T);
|
|
95
|
+
};
|
|
93
96
|
|
|
94
97
|
/**
|
|
95
98
|
* Context which is passed to plugins, allowing them to interact with each other.
|
|
@@ -136,7 +139,11 @@ export class PluginsContext {
|
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
current.push(new CapabilityImpl(moduleId, implementation));
|
|
139
|
-
log('capability contributed', {
|
|
142
|
+
log('capability contributed', {
|
|
143
|
+
id: interfaceDef.identifier,
|
|
144
|
+
moduleId,
|
|
145
|
+
count: untracked(() => current.length),
|
|
146
|
+
});
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
/**
|
|
@@ -152,6 +159,8 @@ export class PluginsContext {
|
|
|
152
159
|
if (index !== -1) {
|
|
153
160
|
current.splice(index, 1);
|
|
154
161
|
log('capability removed', { id: interfaceDef.identifier, count: untracked(() => current.length) });
|
|
162
|
+
} else {
|
|
163
|
+
log.warn('capability not removed', { id: interfaceDef.identifier });
|
|
155
164
|
}
|
|
156
165
|
}
|
|
157
166
|
|
package/src/core/manager.test.ts
CHANGED
|
@@ -62,10 +62,10 @@ describe('PluginManager', () => {
|
|
|
62
62
|
const Test = definePlugin(testMeta, [Hello]);
|
|
63
63
|
|
|
64
64
|
const manager = new PluginManager({ plugins: [Test], core: [], pluginLoader });
|
|
65
|
-
manager.enable(testMeta.id);
|
|
65
|
+
await manager.enable(testMeta.id);
|
|
66
66
|
expect(manager.enabled).toEqual([Test.meta.id]);
|
|
67
67
|
expect(manager.modules).toEqual([Hello]);
|
|
68
|
-
manager.disable(testMeta.id);
|
|
68
|
+
await manager.disable(testMeta.id);
|
|
69
69
|
expect(manager.enabled).toEqual([]);
|
|
70
70
|
expect(manager.modules).toEqual([]);
|
|
71
71
|
});
|
|
@@ -111,7 +111,8 @@ describe('PluginManager', () => {
|
|
|
111
111
|
const Fail = defineModule({
|
|
112
112
|
id: 'dxos.org/test/fail',
|
|
113
113
|
activatesOn: FailEvent,
|
|
114
|
-
|
|
114
|
+
// TODO(wittjosiah): Test and catch more failure modes.
|
|
115
|
+
activate: async () => async () => raise(new Error('test')),
|
|
115
116
|
});
|
|
116
117
|
plugins = [definePlugin(testMeta, [Hello, Fail])];
|
|
117
118
|
|
|
@@ -287,7 +288,7 @@ describe('PluginManager', () => {
|
|
|
287
288
|
id: 'dxos.org/test/count',
|
|
288
289
|
activatesOn: Events.Startup,
|
|
289
290
|
activatesBefore: [CountEvent],
|
|
290
|
-
activate: (context) => {
|
|
291
|
+
activate: async (context) => async () => {
|
|
291
292
|
computeTotal(context);
|
|
292
293
|
return contributes(Total, state);
|
|
293
294
|
},
|
|
@@ -328,57 +329,18 @@ describe('PluginManager', () => {
|
|
|
328
329
|
|
|
329
330
|
{
|
|
330
331
|
await manager.disable(Test.meta.id);
|
|
331
|
-
expect(manager.active).toEqual([...Test.modules.map((m) => m.id), Count.meta.id]);
|
|
332
|
-
expect(manager.pendingReset).toEqual([CountEvent.id, Events.Startup.id]);
|
|
333
|
-
|
|
334
|
-
const totals = manager.context.requestCapabilities(Total);
|
|
335
|
-
expect(totals).toHaveLength(1);
|
|
336
|
-
expect(totals[0].total).toEqual(6);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
{
|
|
340
|
-
await manager.reset(CountEvent);
|
|
341
|
-
expect(manager.active).toEqual([Count.meta.id]);
|
|
342
|
-
expect(manager.pendingReset).toEqual([Events.Startup.id]);
|
|
343
|
-
|
|
344
|
-
const totals = manager.context.requestCapabilities(Total);
|
|
345
|
-
expect(totals).toHaveLength(1);
|
|
346
|
-
expect(totals[0].total).toEqual(6);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
{
|
|
350
|
-
await manager.reset(Events.Startup);
|
|
351
332
|
expect(manager.active).toEqual([Count.meta.id]);
|
|
352
333
|
expect(manager.pendingReset).toEqual([]);
|
|
353
334
|
|
|
354
335
|
const totals = manager.context.requestCapabilities(Total);
|
|
355
336
|
expect(totals).toHaveLength(1);
|
|
356
|
-
|
|
337
|
+
// Total doesn't change because it is not reactive.
|
|
338
|
+
expect(totals[0].total).toEqual(6);
|
|
357
339
|
}
|
|
358
340
|
|
|
359
341
|
{
|
|
360
342
|
await manager.enable(Test.meta.id);
|
|
361
|
-
expect(manager.active).toEqual([Count.meta.id]);
|
|
362
|
-
expect(manager.pendingReset).toEqual([CountEvent.id, Events.Startup.id]);
|
|
363
|
-
|
|
364
|
-
const totals = manager.context.requestCapabilities(Total);
|
|
365
|
-
expect(totals).toHaveLength(1);
|
|
366
|
-
expect(totals[0].total).toEqual(0);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
{
|
|
370
|
-
await manager.reset(CountEvent);
|
|
371
343
|
expect(manager.active).toEqual([Count.meta.id, ...Test.modules.map((m) => m.id)]);
|
|
372
|
-
expect(manager.pendingReset).toEqual([Events.Startup.id]);
|
|
373
|
-
|
|
374
|
-
const totals = manager.context.requestCapabilities(Total);
|
|
375
|
-
expect(totals).toHaveLength(1);
|
|
376
|
-
expect(totals[0].total).toEqual(0);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
{
|
|
380
|
-
await manager.reset(Events.Startup);
|
|
381
|
-
expect(manager.active).toEqual([...Test.modules.map((m) => m.id), Count.meta.id]);
|
|
382
344
|
expect(manager.pendingReset).toEqual([]);
|
|
383
345
|
|
|
384
346
|
const totals = manager.context.requestCapabilities(Total);
|
|
@@ -464,9 +426,6 @@ describe('PluginManager', () => {
|
|
|
464
426
|
using activeUpdates = updateCounter(() => {
|
|
465
427
|
const _ = manager.active.length;
|
|
466
428
|
});
|
|
467
|
-
using pendingRemovalUpdates = updateCounter(() => {
|
|
468
|
-
const _ = manager.pendingRemoval.length;
|
|
469
|
-
});
|
|
470
429
|
using eventsFiredUpdates = updateCounter(() => {
|
|
471
430
|
const _ = manager.eventsFired.length;
|
|
472
431
|
});
|
|
@@ -477,7 +436,6 @@ describe('PluginManager', () => {
|
|
|
477
436
|
expect(enabledUpdates.count).toEqual(0);
|
|
478
437
|
expect(modulesUpdates.count).toEqual(0);
|
|
479
438
|
expect(activeUpdates.count).toEqual(0);
|
|
480
|
-
expect(pendingRemovalUpdates.count).toEqual(0);
|
|
481
439
|
expect(eventsFiredUpdates.count).toEqual(0);
|
|
482
440
|
expect(pendingResetUpdates.count).toEqual(0);
|
|
483
441
|
|
|
@@ -486,7 +444,6 @@ describe('PluginManager', () => {
|
|
|
486
444
|
expect(enabledUpdates.count).toEqual(1);
|
|
487
445
|
expect(modulesUpdates.count).toEqual(1);
|
|
488
446
|
expect(activeUpdates.count).toEqual(0);
|
|
489
|
-
expect(pendingRemovalUpdates.count).toEqual(0);
|
|
490
447
|
expect(eventsFiredUpdates.count).toEqual(0);
|
|
491
448
|
expect(pendingResetUpdates.count).toEqual(0);
|
|
492
449
|
|
|
@@ -495,7 +452,6 @@ describe('PluginManager', () => {
|
|
|
495
452
|
expect(enabledUpdates.count).toEqual(1);
|
|
496
453
|
expect(modulesUpdates.count).toEqual(1);
|
|
497
454
|
expect(activeUpdates.count).toEqual(1);
|
|
498
|
-
expect(pendingRemovalUpdates.count).toEqual(0);
|
|
499
455
|
expect(eventsFiredUpdates.count).toEqual(1);
|
|
500
456
|
expect(pendingResetUpdates.count).toEqual(0);
|
|
501
457
|
|
|
@@ -503,17 +459,15 @@ describe('PluginManager', () => {
|
|
|
503
459
|
expect(pluginUpdates.count).toEqual(2);
|
|
504
460
|
expect(enabledUpdates.count).toEqual(2);
|
|
505
461
|
expect(modulesUpdates.count).toEqual(2);
|
|
506
|
-
expect(activeUpdates.count).toEqual(
|
|
507
|
-
expect(pendingRemovalUpdates.count).toEqual(0);
|
|
462
|
+
expect(activeUpdates.count).toEqual(2);
|
|
508
463
|
expect(eventsFiredUpdates.count).toEqual(1);
|
|
509
|
-
expect(pendingResetUpdates.count).toEqual(
|
|
464
|
+
expect(pendingResetUpdates.count).toEqual(2);
|
|
510
465
|
|
|
511
466
|
await manager.activate(CountEvent);
|
|
512
467
|
expect(pluginUpdates.count).toEqual(2);
|
|
513
468
|
expect(enabledUpdates.count).toEqual(2);
|
|
514
469
|
expect(modulesUpdates.count).toEqual(2);
|
|
515
470
|
expect(activeUpdates.count).toEqual(2);
|
|
516
|
-
expect(pendingRemovalUpdates.count).toEqual(0);
|
|
517
471
|
expect(eventsFiredUpdates.count).toEqual(1);
|
|
518
472
|
expect(pendingResetUpdates.count).toEqual(2);
|
|
519
473
|
|
|
@@ -521,47 +475,42 @@ describe('PluginManager', () => {
|
|
|
521
475
|
expect(pluginUpdates.count).toEqual(3);
|
|
522
476
|
expect(enabledUpdates.count).toEqual(3);
|
|
523
477
|
expect(modulesUpdates.count).toEqual(3);
|
|
524
|
-
expect(activeUpdates.count).toEqual(
|
|
525
|
-
expect(pendingRemovalUpdates.count).toEqual(0);
|
|
478
|
+
expect(activeUpdates.count).toEqual(3);
|
|
526
479
|
expect(eventsFiredUpdates.count).toEqual(1);
|
|
527
|
-
expect(pendingResetUpdates.count).toEqual(
|
|
480
|
+
expect(pendingResetUpdates.count).toEqual(4);
|
|
528
481
|
|
|
529
482
|
await manager.reset(CountEvent);
|
|
530
483
|
expect(pluginUpdates.count).toEqual(3);
|
|
531
484
|
expect(enabledUpdates.count).toEqual(3);
|
|
532
485
|
expect(modulesUpdates.count).toEqual(3);
|
|
533
|
-
// Starts at
|
|
534
|
-
expect(activeUpdates.count).toEqual(
|
|
535
|
-
expect(pendingRemovalUpdates.count).toEqual(0);
|
|
486
|
+
// Starts at 3, plus deactivates 3, plus activates 3.
|
|
487
|
+
expect(activeUpdates.count).toEqual(9);
|
|
536
488
|
expect(eventsFiredUpdates.count).toEqual(1);
|
|
537
489
|
expect(pendingResetUpdates.count).toEqual(4);
|
|
538
490
|
|
|
539
491
|
await manager.disable(One.meta.id);
|
|
540
492
|
expect(pluginUpdates.count).toEqual(3);
|
|
541
493
|
expect(enabledUpdates.count).toEqual(4);
|
|
542
|
-
expect(modulesUpdates.count).toEqual(
|
|
543
|
-
expect(activeUpdates.count).toEqual(
|
|
544
|
-
expect(pendingRemovalUpdates.count).toEqual(1);
|
|
494
|
+
expect(modulesUpdates.count).toEqual(4);
|
|
495
|
+
expect(activeUpdates.count).toEqual(10);
|
|
545
496
|
expect(eventsFiredUpdates.count).toEqual(1);
|
|
546
|
-
expect(pendingResetUpdates.count).toEqual(
|
|
497
|
+
expect(pendingResetUpdates.count).toEqual(4);
|
|
547
498
|
|
|
548
499
|
await manager.remove(One.meta.id);
|
|
549
500
|
expect(pluginUpdates.count).toEqual(4);
|
|
550
501
|
expect(enabledUpdates.count).toEqual(4);
|
|
551
|
-
expect(modulesUpdates.count).toEqual(
|
|
552
|
-
expect(activeUpdates.count).toEqual(
|
|
553
|
-
expect(pendingRemovalUpdates.count).toEqual(1);
|
|
502
|
+
expect(modulesUpdates.count).toEqual(4);
|
|
503
|
+
expect(activeUpdates.count).toEqual(10);
|
|
554
504
|
expect(eventsFiredUpdates.count).toEqual(1);
|
|
555
|
-
expect(pendingResetUpdates.count).toEqual(
|
|
505
|
+
expect(pendingResetUpdates.count).toEqual(4);
|
|
556
506
|
|
|
557
507
|
await manager.reset(CountEvent);
|
|
558
508
|
expect(pluginUpdates.count).toEqual(4);
|
|
559
509
|
expect(enabledUpdates.count).toEqual(4);
|
|
560
510
|
expect(modulesUpdates.count).toEqual(4);
|
|
561
|
-
// Starts at
|
|
562
|
-
expect(activeUpdates.count).toEqual(
|
|
563
|
-
expect(pendingRemovalUpdates.count).toEqual(2);
|
|
511
|
+
// Starts at 10, plus deactivates 2, plus activates 2.
|
|
512
|
+
expect(activeUpdates.count).toEqual(14);
|
|
564
513
|
expect(eventsFiredUpdates.count).toEqual(1);
|
|
565
|
-
expect(pendingResetUpdates.count).toEqual(
|
|
514
|
+
expect(pendingResetUpdates.count).toEqual(4);
|
|
566
515
|
});
|
|
567
516
|
});
|
package/src/core/manager.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { untracked } from '@preact/signals-core';
|
|
6
|
-
import { Effect, Either, Match } from 'effect';
|
|
6
|
+
import { Array as A, Effect, Either, Match, pipe } from 'effect';
|
|
7
7
|
|
|
8
8
|
import { Event } from '@dxos/async';
|
|
9
9
|
import { create, type ReactiveObject } from '@dxos/live-object';
|
|
@@ -35,7 +35,6 @@ type PluginManagerState = {
|
|
|
35
35
|
// Modules
|
|
36
36
|
modules: PluginModule[];
|
|
37
37
|
active: string[];
|
|
38
|
-
pendingRemoval: string[];
|
|
39
38
|
|
|
40
39
|
// Events
|
|
41
40
|
eventsFired: string[];
|
|
@@ -67,7 +66,6 @@ export class PluginManager {
|
|
|
67
66
|
enabled,
|
|
68
67
|
modules: [],
|
|
69
68
|
active: [],
|
|
70
|
-
pendingRemoval: [],
|
|
71
69
|
pendingReset: [],
|
|
72
70
|
eventsFired: [],
|
|
73
71
|
});
|
|
@@ -121,15 +119,6 @@ export class PluginManager {
|
|
|
121
119
|
return this._state.active;
|
|
122
120
|
}
|
|
123
121
|
|
|
124
|
-
/**
|
|
125
|
-
* Ids of modules which are pending removal.
|
|
126
|
-
*
|
|
127
|
-
* @reactive
|
|
128
|
-
*/
|
|
129
|
-
get pendingRemoval(): ReactiveObject<readonly string[]> {
|
|
130
|
-
return this._state.pendingRemoval;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
122
|
/**
|
|
134
123
|
* Ids of events which have been fired.
|
|
135
124
|
*
|
|
@@ -165,8 +154,8 @@ export class PluginManager {
|
|
|
165
154
|
* Enables a plugin.
|
|
166
155
|
* @param id The id of the plugin.
|
|
167
156
|
*/
|
|
168
|
-
enable(id: string): boolean {
|
|
169
|
-
return untracked(() => {
|
|
157
|
+
enable(id: string): Promise<boolean> {
|
|
158
|
+
return untracked(async () => {
|
|
170
159
|
log('enable plugin', { id });
|
|
171
160
|
const plugin = this._getPlugin(id);
|
|
172
161
|
if (!plugin) {
|
|
@@ -181,6 +170,15 @@ export class PluginManager {
|
|
|
181
170
|
this._addModule(module);
|
|
182
171
|
this._setPendingResetByModule(module);
|
|
183
172
|
});
|
|
173
|
+
|
|
174
|
+
log('pending reset', { events: [...this.pendingReset] });
|
|
175
|
+
await Effect.runPromise(
|
|
176
|
+
Effect.all(
|
|
177
|
+
this.pendingReset.map((event) => this._activate(event)),
|
|
178
|
+
{ concurrency: 'unbounded' },
|
|
179
|
+
),
|
|
180
|
+
);
|
|
181
|
+
|
|
184
182
|
return true;
|
|
185
183
|
});
|
|
186
184
|
}
|
|
@@ -206,8 +204,8 @@ export class PluginManager {
|
|
|
206
204
|
* Disables a plugin.
|
|
207
205
|
* @param id The id of the plugin.
|
|
208
206
|
*/
|
|
209
|
-
disable(id: string): boolean {
|
|
210
|
-
return untracked(() => {
|
|
207
|
+
disable(id: string): Promise<boolean> {
|
|
208
|
+
return untracked(async () => {
|
|
211
209
|
log('disable plugin', { id });
|
|
212
210
|
if (this._state.core.includes(id)) {
|
|
213
211
|
return false;
|
|
@@ -221,16 +219,10 @@ export class PluginManager {
|
|
|
221
219
|
const enabledIndex = this._state.enabled.findIndex((enabled) => enabled === id);
|
|
222
220
|
if (enabledIndex !== -1) {
|
|
223
221
|
this._state.enabled.splice(enabledIndex, 1);
|
|
222
|
+
await Effect.runPromise(this._deactivate(id));
|
|
224
223
|
|
|
225
224
|
plugin.modules.forEach((module) => {
|
|
226
|
-
|
|
227
|
-
this._setPendingResetByModule(module);
|
|
228
|
-
if (!this._state.pendingRemoval.includes(module.id)) {
|
|
229
|
-
this._state.pendingRemoval.push(module.id);
|
|
230
|
-
}
|
|
231
|
-
} else {
|
|
232
|
-
this._removeModule(module.id);
|
|
233
|
-
}
|
|
225
|
+
this._removeModule(module.id);
|
|
234
226
|
});
|
|
235
227
|
}
|
|
236
228
|
|
|
@@ -328,14 +320,8 @@ export class PluginManager {
|
|
|
328
320
|
const activationEvents = getEvents(module.activatesOn)
|
|
329
321
|
.map(eventKey)
|
|
330
322
|
.filter((key) => this._state.eventsFired.includes(key));
|
|
331
|
-
const parentEvents = activationEvents.flatMap((event) => {
|
|
332
|
-
const modules = this._getActiveModules().filter((module) =>
|
|
333
|
-
module.activatesBefore?.map(eventKey).includes(event),
|
|
334
|
-
);
|
|
335
|
-
return modules.flatMap((module) => getEvents(module.activatesOn)).map(eventKey);
|
|
336
|
-
});
|
|
337
323
|
|
|
338
|
-
const pendingReset = Array.from(new Set(
|
|
324
|
+
const pendingReset = Array.from(new Set(activationEvents)).filter(
|
|
339
325
|
(event) => !this._state.pendingReset.includes(event),
|
|
340
326
|
);
|
|
341
327
|
if (pendingReset.length > 0) {
|
|
@@ -345,64 +331,91 @@ export class PluginManager {
|
|
|
345
331
|
});
|
|
346
332
|
}
|
|
347
333
|
|
|
334
|
+
/**
|
|
335
|
+
* @internal
|
|
336
|
+
*/
|
|
348
337
|
// TODO(wittjosiah): Improve error typing.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
return Effect.gen(function* () {
|
|
338
|
+
_activate(event: ActivationEvent | string): Effect.Effect<boolean, Error> {
|
|
339
|
+
return Effect.gen(this, function* () {
|
|
352
340
|
const key = typeof event === 'string' ? event : eventKey(event);
|
|
353
341
|
log('activating', { key });
|
|
354
|
-
const pendingIndex =
|
|
342
|
+
const pendingIndex = this._state.pendingReset.findIndex((event) => event === key);
|
|
355
343
|
if (pendingIndex !== -1) {
|
|
356
|
-
|
|
344
|
+
this._state.pendingReset.splice(pendingIndex, 1);
|
|
357
345
|
}
|
|
358
346
|
|
|
359
|
-
const modules =
|
|
347
|
+
const modules = this._getInactiveModulesByEvent(key).filter((module) => {
|
|
348
|
+
const allOf = isAllOf(module.activatesOn);
|
|
349
|
+
if (!allOf) {
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const events = module.activatesOn.events.filter((event) => eventKey(event) !== key);
|
|
354
|
+
return events.every((event) => this._state.eventsFired.includes(eventKey(event)));
|
|
355
|
+
});
|
|
360
356
|
if (modules.length === 0) {
|
|
361
357
|
log('no modules to activate', { key });
|
|
358
|
+
if (!this._state.eventsFired.includes(key)) {
|
|
359
|
+
this._state.eventsFired.push(key);
|
|
360
|
+
}
|
|
362
361
|
return false;
|
|
363
362
|
}
|
|
364
363
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
for (const module of modules) {
|
|
368
|
-
if (
|
|
369
|
-
isAllOf(module.activatesOn) &&
|
|
370
|
-
!module.activatesOn.events
|
|
371
|
-
.filter((event) => eventKey(event) !== key)
|
|
372
|
-
.every((event) => self._state.eventsFired.includes(eventKey(event)))
|
|
373
|
-
) {
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
364
|
+
log('activating modules', { key, modules: modules.map((module) => module.id) });
|
|
365
|
+
this.activation.emit({ event: key, state: 'activating' });
|
|
376
366
|
|
|
377
|
-
|
|
367
|
+
// Concurrently triggers loading of lazy capabilities.
|
|
368
|
+
const getCapabilities = yield* Effect.all(
|
|
369
|
+
modules.map(({ activate }) =>
|
|
370
|
+
Effect.tryPromise({
|
|
371
|
+
try: async () => activate(this.context),
|
|
372
|
+
catch: (error) => error as Error,
|
|
373
|
+
}),
|
|
374
|
+
),
|
|
375
|
+
{ concurrency: 'unbounded' },
|
|
376
|
+
);
|
|
378
377
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
378
|
+
const result = yield* pipe(
|
|
379
|
+
modules,
|
|
380
|
+
A.zip(getCapabilities),
|
|
381
|
+
A.map(([module, getCapabilities]) => this._activateModule(module, getCapabilities)),
|
|
382
|
+
// TODO(wittjosiah): This currently can't be run in parallel.
|
|
383
|
+
// Running this with concurrency causes races with `allOf` activation events.
|
|
384
|
+
Effect.all,
|
|
385
|
+
Effect.either,
|
|
386
|
+
);
|
|
384
387
|
|
|
385
|
-
|
|
388
|
+
if (Either.isLeft(result)) {
|
|
389
|
+
this.activation.emit({ event: key, state: 'error', error: result.left });
|
|
390
|
+
yield* Effect.fail(result.left);
|
|
386
391
|
}
|
|
387
392
|
|
|
388
|
-
if (!
|
|
389
|
-
|
|
393
|
+
if (!this._state.eventsFired.includes(key)) {
|
|
394
|
+
this._state.eventsFired.push(key);
|
|
390
395
|
}
|
|
391
396
|
|
|
392
|
-
|
|
397
|
+
this.activation.emit({ event: key, state: 'activated' });
|
|
393
398
|
log('activated', { key });
|
|
394
399
|
|
|
395
400
|
return true;
|
|
396
401
|
});
|
|
397
402
|
}
|
|
398
403
|
|
|
399
|
-
private _activateModule(
|
|
400
|
-
|
|
401
|
-
|
|
404
|
+
private _activateModule(
|
|
405
|
+
module: PluginModule,
|
|
406
|
+
getCapabilities: AnyCapability | AnyCapability[] | (() => Promise<AnyCapability | AnyCapability[]>),
|
|
407
|
+
): Effect.Effect<void, Error> {
|
|
408
|
+
return Effect.gen(this, function* () {
|
|
409
|
+
yield* Effect.all(module.activatesBefore?.map((event) => this._activate(event)) ?? [], {
|
|
410
|
+
concurrency: 'unbounded',
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
log('activating module...', { module: module.id });
|
|
402
414
|
// TODO(wittjosiah): This is not handling errors thrown if this is synchronous.
|
|
403
|
-
const
|
|
404
|
-
const
|
|
405
|
-
|
|
415
|
+
const maybeCapabilities = typeof getCapabilities === 'function' ? getCapabilities() : getCapabilities;
|
|
416
|
+
const resolvedCapabilities = yield* Match.value(maybeCapabilities).pipe(
|
|
417
|
+
// TODO(wittjosiah): Activate with an effect?
|
|
418
|
+
// Match.when(Effect.isEffect, (effect) => effect),
|
|
406
419
|
Match.when(isPromise, (promise) =>
|
|
407
420
|
Effect.tryPromise({
|
|
408
421
|
try: () => promise,
|
|
@@ -411,42 +424,48 @@ export class PluginManager {
|
|
|
411
424
|
),
|
|
412
425
|
Match.orElse((program) => Effect.succeed(program)),
|
|
413
426
|
);
|
|
414
|
-
const capabilities = Match.value(
|
|
427
|
+
const capabilities = Match.value(resolvedCapabilities).pipe(
|
|
415
428
|
Match.when(Array.isArray, (array) => array),
|
|
416
429
|
Match.orElse((value) => [value]),
|
|
417
430
|
);
|
|
418
431
|
capabilities.forEach((capability) => {
|
|
419
|
-
|
|
432
|
+
this.context.contributeCapability({ module: module.id, ...capability });
|
|
433
|
+
});
|
|
434
|
+
this._state.active.push(module.id);
|
|
435
|
+
this._capabilities.set(module.id, capabilities);
|
|
436
|
+
log('activated module', { module: module.id });
|
|
437
|
+
|
|
438
|
+
yield* Effect.all(module.activatesAfter?.map((event) => this._activate(event)) ?? [], {
|
|
439
|
+
concurrency: 'unbounded',
|
|
420
440
|
});
|
|
421
|
-
self._state.active.push(module.id);
|
|
422
|
-
self._capabilities.set(module.id, capabilities);
|
|
423
441
|
});
|
|
424
442
|
}
|
|
425
443
|
|
|
426
444
|
private _deactivate(id: string): Effect.Effect<boolean, Error> {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const plugin = self._getPlugin(id);
|
|
445
|
+
return Effect.gen(this, function* () {
|
|
446
|
+
const plugin = this._getPlugin(id);
|
|
430
447
|
if (!plugin) {
|
|
431
448
|
return false;
|
|
432
449
|
}
|
|
433
450
|
|
|
434
451
|
const modules = plugin.modules;
|
|
435
|
-
const results = yield* Effect.all(
|
|
452
|
+
const results = yield* Effect.all(
|
|
453
|
+
modules.map((module) => this._deactivateModule(module)),
|
|
454
|
+
{ concurrency: 'unbounded' },
|
|
455
|
+
);
|
|
436
456
|
return results.every((result) => result);
|
|
437
457
|
});
|
|
438
458
|
}
|
|
439
459
|
|
|
440
460
|
private _deactivateModule(module: PluginModule): Effect.Effect<boolean, Error> {
|
|
441
|
-
|
|
442
|
-
return Effect.gen(function* () {
|
|
461
|
+
return Effect.gen(this, function* () {
|
|
443
462
|
const id = module.id;
|
|
444
463
|
log('deactivating', { id });
|
|
445
464
|
|
|
446
|
-
const capabilities =
|
|
465
|
+
const capabilities = this._capabilities.get(id);
|
|
447
466
|
if (capabilities) {
|
|
448
467
|
for (const capability of capabilities) {
|
|
449
|
-
|
|
468
|
+
this.context.removeCapability(capability.interface, capability.implementation);
|
|
450
469
|
const program = capability.deactivate?.();
|
|
451
470
|
yield* Match.value(program).pipe(
|
|
452
471
|
Match.when(Effect.isEffect, (effect) => effect),
|
|
@@ -459,12 +478,12 @@ export class PluginManager {
|
|
|
459
478
|
Match.orElse((program) => Effect.succeed(program)),
|
|
460
479
|
);
|
|
461
480
|
}
|
|
462
|
-
|
|
481
|
+
this._capabilities.delete(id);
|
|
463
482
|
}
|
|
464
483
|
|
|
465
|
-
const activeIndex =
|
|
484
|
+
const activeIndex = this._state.active.findIndex((event) => event === id);
|
|
466
485
|
if (activeIndex !== -1) {
|
|
467
|
-
|
|
486
|
+
this._state.active.splice(activeIndex, 1);
|
|
468
487
|
}
|
|
469
488
|
|
|
470
489
|
log('deactivated', { id });
|
|
@@ -473,22 +492,17 @@ export class PluginManager {
|
|
|
473
492
|
}
|
|
474
493
|
|
|
475
494
|
private _reset(event: ActivationEvent | string): Effect.Effect<boolean, Error> {
|
|
476
|
-
|
|
477
|
-
return Effect.gen(function* () {
|
|
495
|
+
return Effect.gen(this, function* () {
|
|
478
496
|
const key = typeof event === 'string' ? event : eventKey(event);
|
|
479
497
|
log('reset', { key });
|
|
480
|
-
const modules =
|
|
481
|
-
const results = yield* Effect.all(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
self._removeModule(id);
|
|
486
|
-
});
|
|
487
|
-
self._state.pendingRemoval.splice(0, self._state.pendingRemoval.length);
|
|
488
|
-
}
|
|
498
|
+
const modules = this._getActiveModulesByEvent(key);
|
|
499
|
+
const results = yield* Effect.all(
|
|
500
|
+
modules.map((module) => this._deactivateModule(module)),
|
|
501
|
+
{ concurrency: 'unbounded' },
|
|
502
|
+
);
|
|
489
503
|
|
|
490
504
|
if (results.every((result) => result)) {
|
|
491
|
-
return yield*
|
|
505
|
+
return yield* this._activate(key);
|
|
492
506
|
} else {
|
|
493
507
|
return false;
|
|
494
508
|
}
|
package/src/core/plugin.ts
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Effect } from 'effect';
|
|
6
|
-
|
|
7
5
|
import { type MaybePromise } from '@dxos/util';
|
|
8
6
|
|
|
9
7
|
import { type AnyCapability, type PluginsContext } from './capabilities';
|
|
@@ -39,7 +37,7 @@ interface PluginModuleInterface {
|
|
|
39
37
|
*/
|
|
40
38
|
activate: (
|
|
41
39
|
context: PluginsContext,
|
|
42
|
-
) => MaybePromise<AnyCapability | AnyCapability[]> |
|
|
40
|
+
) => MaybePromise<AnyCapability | AnyCapability[]> | Promise<() => Promise<AnyCapability | AnyCapability[]>>;
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
/**
|
|
@@ -98,6 +96,11 @@ export type PluginMeta = {
|
|
|
98
96
|
*/
|
|
99
97
|
source?: string;
|
|
100
98
|
|
|
99
|
+
/**
|
|
100
|
+
* URL of screenshot.
|
|
101
|
+
*/
|
|
102
|
+
screenshots?: string[];
|
|
103
|
+
|
|
101
104
|
/**
|
|
102
105
|
* Tags to help categorize the plugin.
|
|
103
106
|
*/
|
|
@@ -6,34 +6,34 @@ import React, { useCallback } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { Button } from '@dxos/react-ui';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { createGeneratorIntent, createPluginId, Number } from './generator';
|
|
10
10
|
import { Capabilities } from '../../common';
|
|
11
11
|
import { contributes } from '../../core';
|
|
12
|
-
import {
|
|
12
|
+
import { createIntent } from '../../plugin-intent';
|
|
13
|
+
import { useCapabilities, useIntentDispatcher, usePluginManager } from '../../react';
|
|
13
14
|
|
|
14
15
|
export const Toolbar = () => {
|
|
15
16
|
const manager = usePluginManager();
|
|
17
|
+
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
16
18
|
|
|
17
19
|
const handleAdd = useCallback(async () => {
|
|
18
20
|
const id = createPluginId(Math.random().toString(16).substring(2, 8));
|
|
19
21
|
await manager.add(id);
|
|
20
22
|
}, [manager]);
|
|
21
23
|
|
|
22
|
-
const
|
|
23
|
-
if (manager.pendingReset.includes(CountEvent.id)) {
|
|
24
|
-
await manager.reset(CountEvent);
|
|
25
|
-
} else {
|
|
26
|
-
await manager.activate(CountEvent);
|
|
27
|
-
}
|
|
28
|
-
}, [manager]);
|
|
24
|
+
const count = useCapabilities(Number).reduce((acc, curr) => acc + curr, 0);
|
|
29
25
|
|
|
30
|
-
const
|
|
26
|
+
const generatorPlugins = manager.plugins.filter((plugin) => plugin.meta.id.startsWith('dxos.org/test/generator/'));
|
|
31
27
|
|
|
32
28
|
return (
|
|
33
29
|
<>
|
|
34
30
|
<Button onClick={handleAdd}>Add</Button>
|
|
35
|
-
<Button onClick={handleCount}>Count</Button>
|
|
36
31
|
<div className='flex items-center'>Count: {count}</div>
|
|
32
|
+
{generatorPlugins.map((plugin) => (
|
|
33
|
+
<Button key={plugin.meta.id} onClick={() => dispatch(createIntent(createGeneratorIntent(plugin.meta.id)))}>
|
|
34
|
+
{plugin.meta.id.replace('dxos.org/test/generator/', '')}
|
|
35
|
+
</Button>
|
|
36
|
+
))}
|
|
37
37
|
</>
|
|
38
38
|
);
|
|
39
39
|
};
|