@dxos/app-framework 0.8.4-main.fd6878d → 0.8.4-main.fffef41
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/.storybook/main.mts +11 -0
- package/.storybook/preview.mts +8 -0
- package/.swc/plugins/linux_x86_64_19.0.0/727453fb3a62f7f1d952a41e051ca8a6f88cadc45cee43c6a4d1aa45f9b75665.wasmer-v7 +0 -0
- package/.swc/plugins/{v7_linux_x86_64_13.0.0/fce1bdb8e20a094e4af08bad09cc81497ed0e2e7c51223b07d371063cca18429 → linux_x86_64_19.0.0/fce1bdb8e20a094e4af08bad09cc81497ed0e2e7c51223b07d371063cca18429.wasmer-v7} +0 -0
- package/dist/lib/browser/{app-graph-builder-MOVKFH3J.mjs → app-graph-builder-OIEZZC45.mjs} +31 -30
- package/dist/lib/browser/app-graph-builder-OIEZZC45.mjs.map +7 -0
- package/dist/lib/browser/{chunk-OSBZFKMO.mjs → chunk-6XKO24JP.mjs} +232 -177
- package/dist/lib/browser/chunk-6XKO24JP.mjs.map +7 -0
- package/dist/lib/browser/{chunk-ORWHM7CO.mjs → chunk-SCPE4ZO2.mjs} +11 -8
- package/dist/lib/browser/chunk-SCPE4ZO2.mjs.map +7 -0
- package/dist/lib/browser/{chunk-NKCIDYDI.mjs → chunk-WPW5VVAX.mjs} +189 -136
- package/dist/lib/browser/chunk-WPW5VVAX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +20 -56
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-dispatcher-FTTJLVGN.mjs → intent-dispatcher-LZ4AE66E.mjs} +2 -2
- package/dist/lib/browser/{intent-resolver-ZCGEAG3E.mjs → intent-resolver-QVCKRX6G.mjs} +7 -7
- package/dist/lib/browser/intent-resolver-QVCKRX6G.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react/index.mjs +34 -0
- package/dist/lib/browser/{store-3QB6Q2BC.mjs → store-CNPHOYTJ.mjs} +5 -5
- package/dist/lib/browser/store-CNPHOYTJ.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +17 -21
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/{app-graph-builder-ODE4B5GT.mjs → app-graph-builder-EBU4NVWD.mjs} +31 -30
- package/dist/lib/node-esm/app-graph-builder-EBU4NVWD.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-WU3QN5B6.mjs → chunk-3UPX5OIS.mjs} +232 -177
- package/dist/lib/node-esm/chunk-3UPX5OIS.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-YEN7NKTF.mjs → chunk-XJZGUJ3H.mjs} +189 -136
- package/dist/lib/node-esm/chunk-XJZGUJ3H.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-UMZQERLE.mjs → chunk-ZX63QUGE.mjs} +11 -8
- package/dist/lib/node-esm/chunk-ZX63QUGE.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +20 -56
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-dispatcher-YQIQ55LJ.mjs → intent-dispatcher-MGOJ3CHD.mjs} +2 -2
- package/dist/lib/node-esm/{intent-resolver-KG27L7EQ.mjs → intent-resolver-URF3HN3G.mjs} +7 -7
- package/dist/lib/node-esm/intent-resolver-URF3HN3G.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/react/index.mjs +35 -0
- package/dist/lib/node-esm/{store-TIJAVO3D.mjs → store-RK5B4XEL.mjs} +5 -5
- package/dist/lib/node-esm/store-RK5B4XEL.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +17 -21
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/common/capabilities.d.ts +41 -43
- package/dist/types/src/common/capabilities.d.ts.map +1 -1
- package/dist/types/src/common/collaboration.d.ts +10 -9
- package/dist/types/src/common/collaboration.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/layout.d.ts +1 -3
- package/dist/types/src/common/layout.d.ts.map +1 -1
- package/dist/types/src/common/surface.d.ts +19 -16
- package/dist/types/src/common/surface.d.ts.map +1 -1
- package/dist/types/src/common/translations.d.ts +1 -1
- package/dist/types/src/common/translations.d.ts.map +1 -1
- package/dist/types/src/core/capabilities.d.ts +19 -16
- package/dist/types/src/core/capabilities.d.ts.map +1 -1
- package/dist/types/src/core/manager.d.ts +1 -1
- package/dist/types/src/core/manager.d.ts.map +1 -1
- package/dist/types/src/core/plugin.d.ts +8 -1
- package/dist/types/src/core/plugin.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/playground/debug/Debug.d.ts +1 -1
- package/dist/types/src/playground/debug/plugin.d.ts +1 -1
- package/dist/types/src/playground/debug/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/generator/Main.d.ts +1 -1
- package/dist/types/src/playground/generator/Main.d.ts.map +1 -1
- package/dist/types/src/playground/generator/Toolbar.d.ts +1 -1
- package/dist/types/src/playground/generator/generator.d.ts +1 -1
- package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
- package/dist/types/src/playground/generator/plugin.d.ts +1 -1
- package/dist/types/src/playground/generator/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/layout/Layout.d.ts +2 -2
- package/dist/types/src/playground/layout/plugin.d.ts +1 -1
- package/dist/types/src/playground/layout/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/logger/Toolbar.d.ts +1 -1
- package/dist/types/src/playground/logger/plugin.d.ts +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/playground/playground.stories.d.ts +5 -4
- package/dist/types/src/playground/playground.stories.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/IntentPlugin.d.ts +1 -1
- package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/actions.d.ts +5 -7
- package/dist/types/src/plugin-intent/actions.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/errors.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/index.d.ts +1 -0
- package/dist/types/src/plugin-intent/index.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +5 -5
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/intent.d.ts +1 -1
- package/dist/types/src/plugin-intent/intent.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/meta.d.ts +3 -0
- package/dist/types/src/plugin-intent/meta.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/SettingsPlugin.d.ts +1 -1
- package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/actions.d.ts +5 -7
- package/dist/types/src/plugin-settings/actions.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/app-graph-builder.d.ts +1 -1
- package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/intent-resolver.d.ts +1 -1
- package/dist/types/src/plugin-settings/meta.d.ts +3 -0
- package/dist/types/src/plugin-settings/meta.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/store.d.ts +1 -1
- package/dist/types/src/plugin-settings/translations.d.ts +2 -1
- package/dist/types/src/plugin-settings/translations.d.ts.map +1 -1
- package/dist/types/src/react/App.d.ts +10 -0
- package/dist/types/src/react/App.d.ts.map +1 -0
- package/dist/types/src/react/App.stories.d.ts +14 -0
- package/dist/types/src/react/App.stories.d.ts.map +1 -0
- package/dist/types/src/react/DefaultFallback.d.ts +8 -0
- package/dist/types/src/react/DefaultFallback.d.ts.map +1 -0
- package/dist/types/src/react/ErrorBoundary.d.ts +2 -2
- package/dist/types/src/react/ErrorBoundary.d.ts.map +1 -1
- package/dist/types/src/react/Surface.d.ts +5 -5
- package/dist/types/src/react/Surface.d.ts.map +1 -1
- package/dist/types/src/react/Surface.stories.d.ts +8 -10
- package/dist/types/src/react/Surface.stories.d.ts.map +1 -1
- 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/types.d.ts +14 -0
- package/dist/types/src/react/types.d.ts.map +1 -0
- package/dist/types/src/{App.d.ts → react/useApp.d.ts} +7 -6
- package/dist/types/src/react/useApp.d.ts.map +1 -0
- package/dist/types/src/react/useLoading.d.ts +19 -0
- package/dist/types/src/react/useLoading.d.ts.map +1 -0
- package/dist/types/src/testing/withPluginManager.d.ts +7 -8
- package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
- package/dist/types/src/testing/withPluginManager.stories.d.ts +9 -3
- package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/moon.yml +5 -1
- package/package.json +44 -40
- package/src/common/capabilities.ts +33 -25
- package/src/common/collaboration.ts +6 -9
- package/src/common/file.ts +1 -1
- package/src/common/layout.ts +3 -4
- package/src/common/surface.ts +23 -21
- package/src/common/translations.ts +1 -1
- package/src/core/capabilities.test.ts +2 -2
- package/src/core/capabilities.ts +35 -27
- package/src/core/manager.test.ts +19 -19
- package/src/core/manager.ts +14 -7
- package/src/core/plugin.ts +13 -2
- package/src/index.ts +0 -2
- package/src/playground/debug/Debug.tsx +1 -1
- package/src/playground/debug/plugin.ts +7 -8
- package/src/playground/generator/Main.tsx +0 -1
- package/src/playground/generator/generator.ts +2 -2
- package/src/playground/generator/plugin.ts +12 -13
- package/src/playground/layout/plugin.ts +9 -8
- package/src/playground/logger/plugin.ts +27 -23
- package/src/playground/logger/schema.ts +1 -1
- package/src/playground/playground.stories.tsx +17 -14
- package/src/plugin-intent/IntentPlugin.ts +12 -13
- package/src/plugin-intent/actions.ts +4 -6
- package/src/plugin-intent/errors.ts +2 -1
- package/src/plugin-intent/index.ts +1 -0
- package/src/plugin-intent/intent-dispatcher.test.ts +10 -3
- package/src/plugin-intent/intent-dispatcher.ts +16 -8
- package/src/plugin-intent/intent.ts +1 -1
- package/src/plugin-intent/meta.ts +10 -0
- package/src/plugin-settings/SettingsPlugin.ts +25 -27
- package/src/plugin-settings/actions.ts +9 -13
- package/src/plugin-settings/app-graph-builder.ts +22 -20
- package/src/plugin-settings/intent-resolver.ts +2 -2
- package/src/plugin-settings/meta.ts +10 -0
- package/src/plugin-settings/store.ts +2 -2
- package/src/plugin-settings/translations.ts +4 -4
- package/src/react/App.stories.tsx +33 -0
- package/src/react/App.tsx +59 -0
- package/src/react/DefaultFallback.tsx +26 -0
- package/src/react/ErrorBoundary.tsx +10 -8
- package/src/react/Surface.stories.tsx +79 -51
- package/src/react/Surface.tsx +67 -36
- package/src/react/index.ts +4 -0
- package/src/react/types.ts +38 -0
- package/src/react/useApp.tsx +165 -0
- package/src/react/useCapabilities.ts +2 -2
- package/src/react/useLoading.tsx +70 -0
- package/src/testing/withPluginManager.stories.tsx +7 -4
- package/src/testing/withPluginManager.tsx +27 -29
- package/tsconfig.json +11 -9
- package/vitest.config.ts +8 -6
- package/.swc/plugins/v7_linux_x86_64_13.0.0/c614d7475354583212fbd7669acbae95b9832c305bf51bdaabe2e6de05abb6bf +0 -0
- package/dist/lib/browser/app-graph-builder-MOVKFH3J.mjs.map +0 -7
- package/dist/lib/browser/chunk-NKCIDYDI.mjs.map +0 -7
- package/dist/lib/browser/chunk-ORWHM7CO.mjs.map +0 -7
- package/dist/lib/browser/chunk-OSBZFKMO.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-ZCGEAG3E.mjs.map +0 -7
- package/dist/lib/browser/store-3QB6Q2BC.mjs.map +0 -7
- package/dist/lib/browser/worker.mjs +0 -79
- package/dist/lib/node-esm/app-graph-builder-ODE4B5GT.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UMZQERLE.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-WU3QN5B6.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YEN7NKTF.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-KG27L7EQ.mjs.map +0 -7
- package/dist/lib/node-esm/store-TIJAVO3D.mjs.map +0 -7
- package/dist/lib/node-esm/worker.mjs +0 -80
- package/dist/types/src/App.d.ts.map +0 -1
- package/dist/types/src/worker.d.ts +0 -4
- package/dist/types/src/worker.d.ts.map +0 -1
- package/src/App.tsx +0 -284
- package/src/worker.ts +0 -11
- /package/dist/lib/browser/{intent-dispatcher-FTTJLVGN.mjs.map → intent-dispatcher-LZ4AE66E.mjs.map} +0 -0
- /package/dist/lib/browser/{worker.mjs.map → react/index.mjs.map} +0 -0
- /package/dist/lib/node-esm/{intent-dispatcher-YQIQ55LJ.mjs.map → intent-dispatcher-MGOJ3CHD.mjs.map} +0 -0
- /package/dist/lib/node-esm/{worker.mjs.map → react/index.mjs.map} +0 -0
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Function from 'effect/Function';
|
|
7
|
+
import * as Option from 'effect/Option';
|
|
8
|
+
import * as Ref from 'effect/Ref';
|
|
9
|
+
import type * as Types from 'effect/Types';
|
|
7
10
|
|
|
8
11
|
import { live } from '@dxos/live-object';
|
|
9
12
|
import { log } from '@dxos/log';
|
|
@@ -132,7 +135,7 @@ export const createResolver = <Tag extends string, Fields extends IntentParams,
|
|
|
132
135
|
*/
|
|
133
136
|
export type PromiseIntentDispatcher = <Fields extends IntentParams>(
|
|
134
137
|
intent: IntentChain<any, any, any, Fields>,
|
|
135
|
-
) => Promise<Simplify<IntentDispatcherResult<IntentData<Fields>, IntentResultData<Fields>>>>;
|
|
138
|
+
) => Promise<Types.Simplify<IntentDispatcherResult<IntentData<Fields>, IntentResultData<Fields>>>>;
|
|
136
139
|
|
|
137
140
|
/**
|
|
138
141
|
* Creates an effect for intents.
|
|
@@ -141,7 +144,7 @@ export type IntentDispatcher = <Fields extends IntentParams>(
|
|
|
141
144
|
intent: IntentChain<any, any, any, Fields>,
|
|
142
145
|
depth?: number,
|
|
143
146
|
) => Effect.Effect<
|
|
144
|
-
Simplify<Required<IntentDispatcherResult<IntentData<Fields>, IntentResultData<Fields>>>['data']>,
|
|
147
|
+
Types.Simplify<Required<IntentDispatcherResult<IntentData<Fields>, IntentResultData<Fields>>>['data']>,
|
|
145
148
|
Error
|
|
146
149
|
>;
|
|
147
150
|
|
|
@@ -197,7 +200,7 @@ export const createDispatcher = (
|
|
|
197
200
|
.filter((resolver) => !resolver.filter || resolver.filter(intent.data))
|
|
198
201
|
.toSorted(byPosition);
|
|
199
202
|
if (candidates.length === 0) {
|
|
200
|
-
yield* Effect.fail(new NoResolversError(intent.id));
|
|
203
|
+
return yield* Effect.fail(new NoResolversError(intent.id));
|
|
201
204
|
}
|
|
202
205
|
|
|
203
206
|
const effect = candidates[0].resolve(intent.data, intent.undo ?? false);
|
|
@@ -206,15 +209,18 @@ export const createDispatcher = (
|
|
|
206
209
|
});
|
|
207
210
|
|
|
208
211
|
const dispatch: IntentDispatcher = (intentChain, depth = 0) => {
|
|
212
|
+
log('dispatch', { intentChain: intentChain.all.map((i) => i.id), depth });
|
|
209
213
|
return Effect.gen(function* () {
|
|
210
214
|
if (depth > executionLimit) {
|
|
211
|
-
yield* Effect.fail(new CycleDetectedError());
|
|
215
|
+
return yield* Effect.fail(new CycleDetectedError());
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
const resultsRef = yield* Ref.make<AnyIntentResult[]>([]);
|
|
215
219
|
for (const intent of intentChain.all) {
|
|
220
|
+
log('processing', { intent });
|
|
216
221
|
const { data: prev } = (yield* resultsRef.get)[0] ?? {};
|
|
217
222
|
const result = yield* handleIntent({ ...intent, data: { ...intent.data, ...prev } });
|
|
223
|
+
log('ok', { intent: intent.id, result });
|
|
218
224
|
yield* Ref.update(resultsRef, (results) => [result, ...results]);
|
|
219
225
|
if (result.intents) {
|
|
220
226
|
for (const intent of result.intents) {
|
|
@@ -231,7 +237,8 @@ export const createDispatcher = (
|
|
|
231
237
|
// error: result.error.message,
|
|
232
238
|
// }),
|
|
233
239
|
// );
|
|
234
|
-
|
|
240
|
+
log.error('failed', { intent: intent.id, error: result.error });
|
|
241
|
+
return yield* Effect.fail(result.error);
|
|
235
242
|
}
|
|
236
243
|
}
|
|
237
244
|
|
|
@@ -252,7 +259,7 @@ export const createDispatcher = (
|
|
|
252
259
|
|
|
253
260
|
if (result.undoable && isUndoable(results)) {
|
|
254
261
|
// TODO(wittjosiah): Is there a better way to handle showing undo for chains?
|
|
255
|
-
yield* pipe(
|
|
262
|
+
yield* Function.pipe(
|
|
256
263
|
dispatch(createIntent(IntentAction.ShowUndo, { message: result.undoable.message })),
|
|
257
264
|
Effect.catchSome((err) =>
|
|
258
265
|
err instanceof NoResolversError ? Option.some(Effect.succeed(undefined)) : Option.none(),
|
|
@@ -260,6 +267,7 @@ export const createDispatcher = (
|
|
|
260
267
|
);
|
|
261
268
|
}
|
|
262
269
|
|
|
270
|
+
log('done', { intent: intentChain.all.map((i) => i.id), result: result.data });
|
|
263
271
|
return result.data;
|
|
264
272
|
});
|
|
265
273
|
};
|
|
@@ -5,32 +5,30 @@
|
|
|
5
5
|
import { Capabilities, Events } from '../common';
|
|
6
6
|
import { contributes, defineModule, definePlugin, lazy } from '../core';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { meta } from './meta';
|
|
9
9
|
import { translations } from './translations';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}),
|
|
36
|
-
]);
|
|
11
|
+
export const SettingsPlugin = definePlugin(meta, () => [
|
|
12
|
+
defineModule({
|
|
13
|
+
id: `${meta.id}/module/store`,
|
|
14
|
+
activatesOn: Events.Startup,
|
|
15
|
+
activatesBefore: [Events.SetupSettings],
|
|
16
|
+
activatesAfter: [Events.SettingsReady],
|
|
17
|
+
activate: lazy(() => import('./store')),
|
|
18
|
+
}),
|
|
19
|
+
defineModule({
|
|
20
|
+
id: `${meta.id}/module/translations`,
|
|
21
|
+
activatesOn: Events.SetupTranslations,
|
|
22
|
+
activate: () => contributes(Capabilities.Translations, translations),
|
|
23
|
+
}),
|
|
24
|
+
defineModule({
|
|
25
|
+
id: `${meta.id}/module/intent-resolver`,
|
|
26
|
+
activatesOn: Events.SetupIntentResolver,
|
|
27
|
+
activate: lazy(() => import('./intent-resolver')),
|
|
28
|
+
}),
|
|
29
|
+
defineModule({
|
|
30
|
+
id: `${meta.id}/module/app-graph-builder`,
|
|
31
|
+
activatesOn: Events.SetupAppGraph,
|
|
32
|
+
activate: lazy(() => import('./app-graph-builder')),
|
|
33
|
+
}),
|
|
34
|
+
]);
|
|
@@ -2,28 +2,24 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// TODO(
|
|
10
|
-
// Ideally this should be worked into the data model in a generic way.
|
|
7
|
+
import { meta } from './meta';
|
|
8
|
+
|
|
9
|
+
// TODO(burdon): Document.
|
|
11
10
|
export const SETTINGS_ID = '!dxos:settings';
|
|
12
11
|
export const SETTINGS_KEY = 'settings';
|
|
13
12
|
|
|
14
13
|
export namespace SettingsAction {
|
|
15
|
-
export class Open extends Schema.TaggedClass<Open>()(`${
|
|
14
|
+
export class Open extends Schema.TaggedClass<Open>()(`${meta.id}/open`, {
|
|
16
15
|
input: Schema.Struct({
|
|
17
16
|
plugin: Schema.optional(Schema.String),
|
|
18
17
|
}),
|
|
19
18
|
output: Schema.Void,
|
|
20
19
|
}) {}
|
|
21
20
|
|
|
22
|
-
export class OpenPluginRegistry extends Schema.TaggedClass<OpenPluginRegistry>()(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
output: Schema.Void,
|
|
27
|
-
},
|
|
28
|
-
) {}
|
|
21
|
+
export class OpenPluginRegistry extends Schema.TaggedClass<OpenPluginRegistry>()(`${meta.id}/open-plugin-registry`, {
|
|
22
|
+
input: Schema.Void,
|
|
23
|
+
output: Schema.Void,
|
|
24
|
+
}) {}
|
|
29
25
|
}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { Atom } from '@effect-atom/atom-react';
|
|
6
|
+
import * as Function from 'effect/Function';
|
|
7
|
+
import * as Option from 'effect/Option';
|
|
7
8
|
|
|
8
9
|
import { ROOT_ID, createExtension } from '@dxos/app-graph';
|
|
9
10
|
import { type SettingsStore, type SettingsValue } from '@dxos/local-storage';
|
|
@@ -13,26 +14,27 @@ import { Capabilities } from '../common';
|
|
|
13
14
|
import { type PluginContext, type PluginMeta, contributes } from '../core';
|
|
14
15
|
import { createIntent } from '../plugin-intent';
|
|
15
16
|
|
|
16
|
-
import { SETTINGS_ID, SETTINGS_KEY,
|
|
17
|
+
import { SETTINGS_ID, SETTINGS_KEY, SettingsAction } from './actions';
|
|
18
|
+
import { meta } from './meta';
|
|
17
19
|
|
|
18
20
|
export default (context: PluginContext) =>
|
|
19
21
|
contributes(Capabilities.AppGraphBuilder, [
|
|
20
22
|
createExtension({
|
|
21
|
-
id: `${
|
|
23
|
+
id: `${meta.id}/action`,
|
|
22
24
|
actions: (node) =>
|
|
23
|
-
|
|
24
|
-
pipe(
|
|
25
|
+
Atom.make((get) =>
|
|
26
|
+
Function.pipe(
|
|
25
27
|
get(node),
|
|
26
28
|
Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
|
|
27
29
|
Option.map(() => [
|
|
28
30
|
{
|
|
29
|
-
id:
|
|
31
|
+
id: meta.id,
|
|
30
32
|
data: async () => {
|
|
31
33
|
const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);
|
|
32
34
|
await dispatch(createIntent(SettingsAction.Open));
|
|
33
35
|
},
|
|
34
36
|
properties: {
|
|
35
|
-
label: ['open settings label', { ns:
|
|
37
|
+
label: ['open settings label', { ns: meta.id }],
|
|
36
38
|
icon: 'ph--gear--regular',
|
|
37
39
|
disposition: 'menu',
|
|
38
40
|
keyBinding: {
|
|
@@ -47,18 +49,18 @@ export default (context: PluginContext) =>
|
|
|
47
49
|
),
|
|
48
50
|
}),
|
|
49
51
|
createExtension({
|
|
50
|
-
id: `${
|
|
52
|
+
id: `${meta.id}/core`,
|
|
51
53
|
connector: (node) =>
|
|
52
|
-
|
|
53
|
-
pipe(
|
|
54
|
+
Atom.make((get) =>
|
|
55
|
+
Function.pipe(
|
|
54
56
|
get(node),
|
|
55
57
|
Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
|
|
56
58
|
Option.map(() => [
|
|
57
59
|
{
|
|
58
60
|
id: SETTINGS_ID,
|
|
59
|
-
type:
|
|
61
|
+
type: meta.id,
|
|
60
62
|
properties: {
|
|
61
|
-
label: ['app settings label', { ns:
|
|
63
|
+
label: ['app settings label', { ns: meta.id }],
|
|
62
64
|
icon: 'ph--gear--regular',
|
|
63
65
|
disposition: 'pin-end',
|
|
64
66
|
position: 'hoist',
|
|
@@ -71,10 +73,10 @@ export default (context: PluginContext) =>
|
|
|
71
73
|
),
|
|
72
74
|
}),
|
|
73
75
|
createExtension({
|
|
74
|
-
id: `${
|
|
76
|
+
id: `${meta.id}/core-plugins`,
|
|
75
77
|
connector: (node) =>
|
|
76
|
-
|
|
77
|
-
pipe(
|
|
78
|
+
Atom.make((get) =>
|
|
79
|
+
Function.pipe(
|
|
78
80
|
get(node),
|
|
79
81
|
Option.flatMap((node) => (node.id !== SETTINGS_ID ? Option.none() : Option.some(node))),
|
|
80
82
|
Option.map(() => {
|
|
@@ -106,7 +108,7 @@ export default (context: PluginContext) =>
|
|
|
106
108
|
id: `${SETTINGS_KEY}:custom-plugins`,
|
|
107
109
|
type: 'category',
|
|
108
110
|
properties: {
|
|
109
|
-
label: ['custom plugins label', { ns:
|
|
111
|
+
label: ['custom plugins label', { ns: meta.id }],
|
|
110
112
|
icon: 'ph--squares-four--regular',
|
|
111
113
|
role: 'branch',
|
|
112
114
|
disposition: 'collection',
|
|
@@ -119,10 +121,10 @@ export default (context: PluginContext) =>
|
|
|
119
121
|
),
|
|
120
122
|
}),
|
|
121
123
|
createExtension({
|
|
122
|
-
id: `${
|
|
124
|
+
id: `${meta.id}/custom-plugins`,
|
|
123
125
|
connector: (node) =>
|
|
124
|
-
|
|
125
|
-
pipe(
|
|
126
|
+
Atom.make((get) =>
|
|
127
|
+
Function.pipe(
|
|
126
128
|
get(node),
|
|
127
129
|
Option.flatMap((node) =>
|
|
128
130
|
node.id !== `${SETTINGS_KEY}:custom-plugins` ? Option.none() : Option.some(node),
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Function from 'effect/Function';
|
|
6
6
|
|
|
7
7
|
import { Capabilities, LayoutAction } from '../common';
|
|
8
8
|
import { contributes } from '../core';
|
|
@@ -20,7 +20,7 @@ export default () =>
|
|
|
20
20
|
return {
|
|
21
21
|
intents: [
|
|
22
22
|
plugin
|
|
23
|
-
? pipe(
|
|
23
|
+
? Function.pipe(
|
|
24
24
|
openSettings,
|
|
25
25
|
chain(LayoutAction.Open, {
|
|
26
26
|
part: 'main',
|
|
@@ -8,11 +8,11 @@ import { Capabilities } from '../common';
|
|
|
8
8
|
import { type PluginContext, contributes } from '../core';
|
|
9
9
|
|
|
10
10
|
export default (context: PluginContext) => {
|
|
11
|
-
// TODO(wittjosiah): Replace with
|
|
11
|
+
// TODO(wittjosiah): Replace with atom?
|
|
12
12
|
const settingsStore = new RootSettingsStore();
|
|
13
13
|
|
|
14
14
|
let previous: Capabilities.Settings[] = [];
|
|
15
|
-
const registry = context.getCapability(Capabilities.
|
|
15
|
+
const registry = context.getCapability(Capabilities.AtomRegistry);
|
|
16
16
|
const cancel = registry.subscribe(
|
|
17
17
|
context.capabilities(Capabilities.Settings),
|
|
18
18
|
(allSettings) => {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Resource } from '
|
|
5
|
+
import { type Resource } from '../common';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { meta } from './meta';
|
|
8
8
|
|
|
9
9
|
export const translations = [
|
|
10
10
|
{
|
|
11
11
|
'en-US': {
|
|
12
|
-
[
|
|
12
|
+
[meta.id]: {
|
|
13
13
|
'open settings label': 'Open settings',
|
|
14
14
|
'app settings label': 'Settings',
|
|
15
15
|
'custom plugins label': 'Plugins',
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
9
|
+
|
|
10
|
+
import { useApp } from './useApp';
|
|
11
|
+
|
|
12
|
+
const DefaultStory = () => {
|
|
13
|
+
const App = useApp({
|
|
14
|
+
placeholder: () => <div className='fixed inset-0 flex items-center justify-center'>Loading...</div>,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return <App />;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const meta = {
|
|
21
|
+
title: 'sdk/app-framework/App',
|
|
22
|
+
render: DefaultStory,
|
|
23
|
+
decorators: [withTheme],
|
|
24
|
+
parameters: {
|
|
25
|
+
layout: 'fullscreen',
|
|
26
|
+
},
|
|
27
|
+
} satisfies Meta;
|
|
28
|
+
|
|
29
|
+
export default meta;
|
|
30
|
+
|
|
31
|
+
type Story = StoryObj<typeof meta>;
|
|
32
|
+
|
|
33
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { type PropsWithChildren } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Capabilities } from '../common';
|
|
8
|
+
import { topologicalSort } from '../helpers';
|
|
9
|
+
|
|
10
|
+
import { type UseAppOptions } from './useApp';
|
|
11
|
+
import { useCapabilities } from './useCapabilities';
|
|
12
|
+
import { LoadingState, useLoading } from './useLoading';
|
|
13
|
+
|
|
14
|
+
export type AppProps = Pick<UseAppOptions, 'placeholder' | 'debounce'> & {
|
|
15
|
+
state: { ready: boolean; error: unknown };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const App = ({ placeholder: Placeholder, state, debounce }: AppProps) => {
|
|
19
|
+
const reactContexts = useCapabilities(Capabilities.ReactContext);
|
|
20
|
+
const reactRoots = useCapabilities(Capabilities.ReactRoot);
|
|
21
|
+
const stage = useLoading(state, debounce);
|
|
22
|
+
|
|
23
|
+
if (state.error) {
|
|
24
|
+
// This triggers the error boundary to provide UI feedback for the startup error.
|
|
25
|
+
throw state.error;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// TODO(wittjosiah): Consider using Suspense instead.
|
|
29
|
+
if (stage < LoadingState.Done) {
|
|
30
|
+
if (!Placeholder) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return <Placeholder stage={stage} />;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const ComposedContext = composeContexts(reactContexts);
|
|
38
|
+
return (
|
|
39
|
+
<ComposedContext>
|
|
40
|
+
{reactRoots.map(({ id, root: Component }) => (
|
|
41
|
+
<Component key={id} />
|
|
42
|
+
))}
|
|
43
|
+
</ComposedContext>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const composeContexts = (contexts: Capabilities.ReactContext[]) => {
|
|
48
|
+
if (contexts.length === 0) {
|
|
49
|
+
return ({ children }: PropsWithChildren) => <>{children}</>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return topologicalSort(contexts)
|
|
53
|
+
.map(({ context }) => context)
|
|
54
|
+
.reduce((Acc, Next) => ({ children }) => (
|
|
55
|
+
<Acc>
|
|
56
|
+
<Next>{children}</Next>
|
|
57
|
+
</Acc>
|
|
58
|
+
));
|
|
59
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* NOTE: Default fallback should not use tailwind or theme.
|
|
9
|
+
*/
|
|
10
|
+
export const DefaultFallback = ({ error }: { error: Error }) => {
|
|
11
|
+
return (
|
|
12
|
+
<div
|
|
13
|
+
style={{
|
|
14
|
+
margin: '1rem',
|
|
15
|
+
padding: '1rem',
|
|
16
|
+
overflow: 'hidden',
|
|
17
|
+
border: '4px solid teal',
|
|
18
|
+
borderRadius: '1rem',
|
|
19
|
+
}}
|
|
20
|
+
>
|
|
21
|
+
{/* TODO(wittjosiah): Link to docs for replacing default. */}
|
|
22
|
+
<h1 style={{ margin: '0.5rem 0', fontSize: '1.2rem' }}>ERROR: {error.message}</h1>
|
|
23
|
+
<pre style={{ overflow: 'auto', fontSize: '1rem', whiteSpace: 'pre-wrap', color: '#888888' }}>{error.stack}</pre>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { Component, type FC, type
|
|
5
|
+
import React, { Component, type FC, type PropsWithChildren, type ReactNode } from 'react';
|
|
6
6
|
|
|
7
7
|
type State = {
|
|
8
8
|
error: Error | undefined;
|
|
@@ -32,7 +32,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, State> {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
override render():
|
|
35
|
+
override render(): ReactNode {
|
|
36
36
|
if (this.state.error) {
|
|
37
37
|
const Fallback = this.props.fallback ?? DefaultFallback;
|
|
38
38
|
return <Fallback data={this.props.data} error={this.state.error} />;
|
|
@@ -46,9 +46,11 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, State> {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
const DefaultFallback: NonNullable<ErrorBoundaryProps['fallback']> = ({ data, error }) =>
|
|
50
|
-
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
const DefaultFallback: NonNullable<ErrorBoundaryProps['fallback']> = ({ data, error }) => {
|
|
50
|
+
return (
|
|
51
|
+
<div className='flex flex-col gap-2 overflow-hidden border border-red-500 rounded-sm'>
|
|
52
|
+
<h1 className='p-2'>ERROR: {error.message}</h1>
|
|
53
|
+
<pre className='p-2 overflow-y-auto text-sm text-subdued'>{JSON.stringify(data, null, 2)}</pre>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
};
|