@dxos/app-framework 0.8.4-main.e098934 → 0.8.4-main.ead640a
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/dist/lib/browser/{app-graph-builder-AFFC6VB2.mjs → app-graph-builder-LG4RG2LM.mjs} +30 -29
- package/dist/lib/browser/app-graph-builder-LG4RG2LM.mjs.map +7 -0
- package/dist/lib/browser/{chunk-OZY7HV2A.mjs → chunk-2GRQ4QXA.mjs} +96 -93
- package/dist/lib/browser/chunk-2GRQ4QXA.mjs.map +7 -0
- package/dist/lib/browser/{chunk-T6M7JB7M.mjs → chunk-FRUTKCPG.mjs} +16 -20
- package/dist/lib/browser/chunk-FRUTKCPG.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/index.mjs +14 -28
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-dispatcher-QG7UPGQX.mjs → intent-dispatcher-6SHA5B3N.mjs} +2 -2
- package/dist/lib/browser/{intent-resolver-4S4PSTM5.mjs → intent-resolver-UZZ4OANZ.mjs} +7 -7
- package/dist/lib/browser/intent-resolver-UZZ4OANZ.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{store-6E33KLGK.mjs → store-ACBEYK4B.mjs} +4 -4
- package/dist/lib/browser/{store-6E33KLGK.mjs.map → store-ACBEYK4B.mjs.map} +1 -1
- package/dist/lib/browser/testing/index.mjs +11 -14
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/worker.mjs +1 -9
- package/dist/lib/node-esm/{app-graph-builder-S4OAULX5.mjs → app-graph-builder-FMHVHPWA.mjs} +30 -29
- package/dist/lib/node-esm/app-graph-builder-FMHVHPWA.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-HJFU7QOR.mjs → chunk-CXT6CYPE.mjs} +16 -20
- package/dist/lib/node-esm/chunk-CXT6CYPE.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-F63ZRXMK.mjs → chunk-KSPOOYT3.mjs} +96 -93
- package/dist/lib/node-esm/chunk-KSPOOYT3.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 +14 -28
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-dispatcher-NXBGPJOX.mjs → intent-dispatcher-SIYQ5ZIU.mjs} +2 -2
- package/dist/lib/node-esm/{intent-resolver-2ZKXI5ET.mjs → intent-resolver-7FYJMXAG.mjs} +7 -7
- package/dist/lib/node-esm/intent-resolver-7FYJMXAG.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{store-QQUTQHHT.mjs → store-6OBLTVXC.mjs} +4 -4
- package/dist/lib/node-esm/{store-QQUTQHHT.mjs.map → store-6OBLTVXC.mjs.map} +1 -1
- package/dist/lib/node-esm/testing/index.mjs +11 -14
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/worker.mjs +1 -9
- package/dist/types/src/common/capabilities.d.ts +14 -4
- package/dist/types/src/common/capabilities.d.ts.map +1 -1
- package/dist/types/src/common/collaboration.d.ts +1 -1
- 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 +7 -13
- 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/components/App.stories.d.ts +0 -1
- package/dist/types/src/components/App.stories.d.ts.map +1 -1
- package/dist/types/src/components/useApp.d.ts.map +1 -1
- package/dist/types/src/core/capabilities.d.ts +1 -1
- package/dist/types/src/core/capabilities.d.ts.map +1 -1
- package/dist/types/src/core/manager.d.ts.map +1 -1
- package/dist/types/src/core/plugin.d.ts +4 -1
- package/dist/types/src/core/plugin.d.ts.map +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/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/plugin.d.ts +1 -1
- package/dist/types/src/playground/layout/plugin.d.ts.map +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 +0 -1
- 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/intent-dispatcher.d.ts +4 -4
- 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.map +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/translations.d.ts +2 -1
- package/dist/types/src/plugin-settings/translations.d.ts.map +1 -1
- 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 +2 -2
- package/dist/types/src/react/Surface.d.ts.map +1 -1
- package/dist/types/src/react/Surface.stories.d.ts +0 -1
- package/dist/types/src/react/Surface.stories.d.ts.map +1 -1
- package/dist/types/src/testing/withPluginManager.d.ts +2 -4
- package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/moon.yml +4 -0
- package/package.json +31 -30
- package/src/common/capabilities.ts +22 -4
- package/src/common/collaboration.ts +1 -1
- package/src/common/file.ts +1 -1
- package/src/common/layout.ts +3 -4
- package/src/common/surface.ts +15 -18
- package/src/common/translations.ts +1 -1
- package/src/components/App.stories.tsx +1 -3
- package/src/components/useApp.tsx +9 -11
- package/src/core/capabilities.test.ts +1 -1
- package/src/core/capabilities.ts +1 -1
- package/src/core/manager.test.ts +19 -19
- package/src/core/manager.ts +12 -5
- package/src/core/plugin.ts +8 -2
- package/src/playground/debug/plugin.ts +7 -8
- 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 +5 -6
- 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/intent-dispatcher.test.ts +10 -3
- package/src/plugin-intent/intent-dispatcher.ts +8 -6
- 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 +17 -15
- package/src/plugin-settings/intent-resolver.ts +2 -2
- package/src/plugin-settings/meta.ts +10 -0
- package/src/plugin-settings/translations.ts +3 -3
- package/src/react/ErrorBoundary.tsx +10 -8
- package/src/react/Surface.stories.tsx +2 -5
- package/src/react/Surface.tsx +11 -3
- package/src/testing/withPluginManager.stories.tsx +1 -1
- package/src/testing/withPluginManager.tsx +13 -17
- package/tsconfig.json +1 -1
- package/vitest.config.ts +8 -6
- package/dist/lib/browser/app-graph-builder-AFFC6VB2.mjs.map +0 -7
- package/dist/lib/browser/chunk-ORWHM7CO.mjs.map +0 -7
- package/dist/lib/browser/chunk-OZY7HV2A.mjs.map +0 -7
- package/dist/lib/browser/chunk-T6M7JB7M.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-4S4PSTM5.mjs.map +0 -7
- package/dist/lib/node-esm/app-graph-builder-S4OAULX5.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-F63ZRXMK.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HJFU7QOR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UMZQERLE.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-2ZKXI5ET.mjs.map +0 -7
- /package/dist/lib/browser/{intent-dispatcher-QG7UPGQX.mjs.map → intent-dispatcher-6SHA5B3N.mjs.map} +0 -0
- /package/dist/lib/node-esm/{intent-dispatcher-NXBGPJOX.mjs.map → intent-dispatcher-SIYQ5ZIU.mjs.map} +0 -0
|
@@ -7,11 +7,12 @@ import { defineModule, definePlugin, lazy } from '../../core';
|
|
|
7
7
|
|
|
8
8
|
const Layout = lazy(() => import('./Layout'));
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
const meta = { id: 'dxos.org/test/layout', name: 'Layout' };
|
|
11
|
+
|
|
12
|
+
export const LayoutPlugin = definePlugin(meta, () => [
|
|
13
|
+
defineModule({
|
|
14
|
+
id: 'dxos.org/test/layout/root',
|
|
15
|
+
activatesOn: Events.Startup,
|
|
16
|
+
activate: Layout,
|
|
17
|
+
}),
|
|
18
|
+
]);
|
|
@@ -12,26 +12,30 @@ import { Log } from './schema';
|
|
|
12
12
|
|
|
13
13
|
const Toolbar = lazy(() => import('./Toolbar'));
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
15
|
+
const meta = {
|
|
16
|
+
id: 'dxos.org/test/logger',
|
|
17
|
+
name: 'Logger',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const LoggerPlugin = definePlugin(meta, () => [
|
|
21
|
+
defineModule({
|
|
22
|
+
id: 'dxos.org/test/logger/intents',
|
|
23
|
+
activatesOn: Events.SetupIntentResolver,
|
|
24
|
+
activate: () => [
|
|
25
|
+
contributes(
|
|
26
|
+
Capabilities.IntentResolver,
|
|
27
|
+
createResolver({
|
|
28
|
+
intent: Log,
|
|
29
|
+
resolve: ({ message }) => {
|
|
30
|
+
log.info(message);
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
),
|
|
34
|
+
],
|
|
35
|
+
}),
|
|
36
|
+
defineModule({
|
|
37
|
+
id: 'dxos.org/test/logger/surfaces',
|
|
38
|
+
activatesOn: Events.Startup,
|
|
39
|
+
activate: Toolbar,
|
|
40
|
+
}),
|
|
41
|
+
]);
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
import React from 'react';
|
|
9
7
|
|
|
10
|
-
import {
|
|
8
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
11
9
|
|
|
12
10
|
import { useApp } from '../components';
|
|
13
11
|
import { IntentPlugin } from '../plugin-intent';
|
|
@@ -17,7 +15,8 @@ import { GeneratorPlugin, createNumberPlugin } from './generator';
|
|
|
17
15
|
import { LayoutPlugin } from './layout';
|
|
18
16
|
import { LoggerPlugin } from './logger';
|
|
19
17
|
|
|
20
|
-
const
|
|
18
|
+
const pluginFactories = [IntentPlugin, LayoutPlugin, DebugPlugin(), LoggerPlugin(), GeneratorPlugin()];
|
|
19
|
+
const plugins = pluginFactories.map((factory) => (typeof factory === 'function' ? factory() : factory));
|
|
21
20
|
|
|
22
21
|
const Placeholder = () => {
|
|
23
22
|
return <div>Loading...</div>;
|
|
@@ -25,7 +24,7 @@ const Placeholder = () => {
|
|
|
25
24
|
|
|
26
25
|
const DefaultStory = () => {
|
|
27
26
|
const App = useApp({
|
|
28
|
-
pluginLoader: (id) => createNumberPlugin(id),
|
|
27
|
+
pluginLoader: (id) => createNumberPlugin(id)(),
|
|
29
28
|
plugins,
|
|
30
29
|
core: plugins.map((plugin) => plugin.meta.id),
|
|
31
30
|
placeholder: Placeholder,
|
|
@@ -37,7 +36,7 @@ const DefaultStory = () => {
|
|
|
37
36
|
const meta = {
|
|
38
37
|
title: 'sdk/app-framework/playground',
|
|
39
38
|
render: DefaultStory,
|
|
40
|
-
decorators: [withTheme
|
|
39
|
+
decorators: [withTheme],
|
|
41
40
|
} satisfies Meta<typeof DefaultStory>;
|
|
42
41
|
|
|
43
42
|
export default meta;
|
|
@@ -5,17 +5,16 @@
|
|
|
5
5
|
import { Events } from '../common';
|
|
6
6
|
import { defineModule, definePlugin, lazy } from '../core';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { meta } from './meta';
|
|
9
9
|
|
|
10
|
-
export const IntentPlugin = () =>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
]);
|
|
10
|
+
export const IntentPlugin = definePlugin(meta, () => [
|
|
11
|
+
defineModule({
|
|
12
|
+
id: `${meta.id}/module/dispatcher`,
|
|
13
|
+
// TODO(wittjosiah): This will mean that startup needs to be reset when intents are added or removed.
|
|
14
|
+
// This is fine for now because it's how it worked prior to capabilities api anyways.
|
|
15
|
+
// In the future, the intent dispatcher should be able to be reset without resetting the entire app.
|
|
16
|
+
activatesOn: Events.Startup,
|
|
17
|
+
activatesAfter: [Events.DispatcherReady],
|
|
18
|
+
activate: lazy(() => import('./intent-dispatcher')),
|
|
19
|
+
}),
|
|
20
|
+
]);
|
|
@@ -2,18 +2,16 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
7
|
import { Label } from './intent';
|
|
8
|
-
|
|
9
|
-
export const INTENT_PLUGIN = 'dxos.org/plugin/intent';
|
|
10
|
-
export const INTENT_ACTION = `${INTENT_PLUGIN}/action`;
|
|
8
|
+
import { meta } from './meta';
|
|
11
9
|
|
|
12
10
|
export namespace IntentAction {
|
|
13
11
|
/**
|
|
14
12
|
* Log an intent.
|
|
15
13
|
*/
|
|
16
|
-
export class Track extends Schema.TaggedClass<Track>()(`${
|
|
14
|
+
export class Track extends Schema.TaggedClass<Track>()(`${meta.id}/action/track`, {
|
|
17
15
|
input: Schema.Struct({
|
|
18
16
|
intents: Schema.Array(Schema.String),
|
|
19
17
|
error: Schema.optional(Schema.String),
|
|
@@ -24,7 +22,7 @@ export namespace IntentAction {
|
|
|
24
22
|
/**
|
|
25
23
|
* Fired after an intent is dispatched if the intent is undoable.
|
|
26
24
|
*/
|
|
27
|
-
export class ShowUndo extends Schema.TaggedClass<ShowUndo>()(`${
|
|
25
|
+
export class ShowUndo extends Schema.TaggedClass<ShowUndo>()(`${meta.id}/action/show-undo`, {
|
|
28
26
|
input: Schema.Struct({
|
|
29
27
|
message: Label,
|
|
30
28
|
}),
|
|
@@ -24,10 +24,11 @@ export class BaseError extends Error {
|
|
|
24
24
|
|
|
25
25
|
export class NoResolversError extends BaseError {
|
|
26
26
|
constructor(action: string) {
|
|
27
|
-
super('NO_RESOLVERS',
|
|
27
|
+
super('NO_RESOLVERS', `No resolvers were found for the action: ${action}`, { action });
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// TODO(burdon): Detect loops.
|
|
31
32
|
export class CycleDetectedError extends BaseError {
|
|
32
33
|
constructor(context?: Record<string, any>) {
|
|
33
34
|
super(
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Fiber from 'effect/Fiber';
|
|
7
|
+
import * as Function from 'effect/Function';
|
|
8
|
+
import * as Schema from 'effect/Schema';
|
|
6
9
|
import { describe, expect, test } from 'vitest';
|
|
7
10
|
|
|
8
11
|
import { chain, createIntent } from './intent';
|
|
@@ -104,7 +107,11 @@ describe('Intent dispatcher', () => {
|
|
|
104
107
|
|
|
105
108
|
test('chain intents', async () => {
|
|
106
109
|
const { dispatch } = createDispatcher(() => [computeResolver, toStringResolver, concatResolver]);
|
|
107
|
-
const intent = pipe(
|
|
110
|
+
const intent = Function.pipe(
|
|
111
|
+
createIntent(Compute, { value: 1 }),
|
|
112
|
+
chain(ToString, {}),
|
|
113
|
+
chain(Concat, { plus: '!' }),
|
|
114
|
+
);
|
|
108
115
|
|
|
109
116
|
expect(intent.first.id).toBe(Compute._tag);
|
|
110
117
|
expect(intent.last.id).toBe(Concat._tag);
|
|
@@ -120,7 +127,7 @@ describe('Intent dispatcher', () => {
|
|
|
120
127
|
|
|
121
128
|
test('undo chained intent', async () => {
|
|
122
129
|
const { dispatch, undo } = createDispatcher(() => [computeResolver, toStringResolver, concatResolver]);
|
|
123
|
-
const intent = pipe(createIntent(Compute, { value: 1 }), chain(Compute, {}), chain(Compute, {}));
|
|
130
|
+
const intent = Function.pipe(createIntent(Compute, { value: 1 }), chain(Compute, {}), chain(Compute, {}));
|
|
124
131
|
const program = Effect.gen(function* () {
|
|
125
132
|
const a = yield* dispatch(intent);
|
|
126
133
|
|
|
@@ -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,6 @@ export const createDispatcher = (
|
|
|
197
200
|
.filter((resolver) => !resolver.filter || resolver.filter(intent.data))
|
|
198
201
|
.toSorted(byPosition);
|
|
199
202
|
if (candidates.length === 0) {
|
|
200
|
-
log.info('no resolvers found', { intent: intent.id });
|
|
201
203
|
return yield* Effect.fail(new NoResolversError(intent.id));
|
|
202
204
|
}
|
|
203
205
|
|
|
@@ -253,7 +255,7 @@ export const createDispatcher = (
|
|
|
253
255
|
|
|
254
256
|
if (result.undoable && isUndoable(results)) {
|
|
255
257
|
// TODO(wittjosiah): Is there a better way to handle showing undo for chains?
|
|
256
|
-
yield* pipe(
|
|
258
|
+
yield* Function.pipe(
|
|
257
259
|
dispatch(createIntent(IntentAction.ShowUndo, { message: result.undoable.message })),
|
|
258
260
|
Effect.catchSome((err) =>
|
|
259
261
|
err instanceof NoResolversError ? Option.some(Effect.succeed(undefined)) : Option.none(),
|
|
@@ -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
|
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Rx } from '@effect-rx/rx-react';
|
|
6
|
-
import
|
|
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
25
|
Rx.make((get) =>
|
|
24
|
-
pipe(
|
|
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
54
|
Rx.make((get) =>
|
|
53
|
-
pipe(
|
|
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
78
|
Rx.make((get) =>
|
|
77
|
-
pipe(
|
|
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
126
|
Rx.make((get) =>
|
|
125
|
-
pipe(
|
|
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',
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Resource } from '@dxos/react-ui';
|
|
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',
|
|
@@ -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
|
+
};
|
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
import React, { useCallback, useState } from 'react';
|
|
9
7
|
|
|
10
8
|
import { faker } from '@dxos/random';
|
|
11
9
|
import { Button, List, ListItem } from '@dxos/react-ui';
|
|
12
|
-
import {
|
|
10
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
13
11
|
|
|
14
12
|
import { Capabilities, createSurface } from '../common';
|
|
15
13
|
import { type PluginManager } from '../core';
|
|
@@ -90,8 +88,7 @@ const DefaultStory = (props: { manager: PluginManager }) => {
|
|
|
90
88
|
const meta = {
|
|
91
89
|
title: 'sdk/app-framework/Surface',
|
|
92
90
|
render: DefaultStory,
|
|
93
|
-
|
|
94
|
-
decorators: [withTheme, withLayout()],
|
|
91
|
+
decorators: [withTheme],
|
|
95
92
|
args: {
|
|
96
93
|
manager: setupPluginManager(),
|
|
97
94
|
},
|
package/src/react/Surface.tsx
CHANGED
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, {
|
|
5
|
+
import React, {
|
|
6
|
+
Fragment,
|
|
7
|
+
type NamedExoticComponent,
|
|
8
|
+
type RefAttributes,
|
|
9
|
+
Suspense,
|
|
10
|
+
forwardRef,
|
|
11
|
+
memo,
|
|
12
|
+
useMemo,
|
|
13
|
+
} from 'react';
|
|
6
14
|
|
|
7
15
|
import { useDefaultValue } from '@dxos/react-hooks';
|
|
8
16
|
import { byPosition } from '@dxos/util';
|
|
@@ -44,8 +52,8 @@ export const isSurfaceAvailable = (context: PluginContext, { role, data }: Pick<
|
|
|
44
52
|
/**
|
|
45
53
|
* A surface is a named region of the screen that can be populated by plugins.
|
|
46
54
|
*/
|
|
47
|
-
export const Surface = memo(
|
|
48
|
-
forwardRef
|
|
55
|
+
export const Surface: NamedExoticComponent<SurfaceProps & RefAttributes<HTMLElement>> = memo(
|
|
56
|
+
forwardRef(
|
|
49
57
|
({ id: _id, role, data: _data, limit, fallback, placeholder = DEFAULT_PLACEHOLDER, ...rest }, forwardedRef) => {
|
|
50
58
|
// TODO(wittjosiah): This will make all surfaces depend on a single signal.
|
|
51
59
|
// This isn't ideal because it means that any change to the data will cause all surfaces to re-render.
|