@dxos/plugin-registry 0.8.4-main.ead640a → 0.8.4-main.effb148878
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/LICENSE +102 -5
- package/dist/lib/neutral/RegistryPlugin.mjs +27 -0
- package/dist/lib/neutral/RegistryPlugin.mjs.map +7 -0
- package/dist/lib/neutral/RegistryPlugin.node.mjs +153 -0
- package/dist/lib/neutral/RegistryPlugin.node.mjs.map +7 -0
- package/dist/lib/neutral/RegistryPlugin.workerd.mjs +10 -0
- package/dist/lib/neutral/RegistryPlugin.workerd.mjs.map +7 -0
- package/dist/lib/neutral/chunk-MYLRMFLY.mjs +34 -0
- package/dist/lib/neutral/chunk-MYLRMFLY.mjs.map +7 -0
- package/dist/lib/neutral/chunk-XK2JMH3H.mjs +33 -0
- package/dist/lib/neutral/chunk-XK2JMH3H.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +25 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/open-plugin-registry-II735N76.mjs +15 -0
- package/dist/lib/neutral/open-plugin-registry-II735N76.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +18 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +70 -0
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/types/src/RegistryPlugin.d.ts +3 -1
- package/dist/types/src/RegistryPlugin.d.ts.map +1 -1
- package/dist/types/src/RegistryPlugin.node.d.ts +4 -0
- package/dist/types/src/RegistryPlugin.node.d.ts.map +1 -0
- package/dist/types/src/RegistryPlugin.test.d.ts +2 -0
- package/dist/types/src/RegistryPlugin.test.d.ts.map +1 -0
- package/dist/types/src/RegistryPlugin.workerd.d.ts +4 -0
- package/dist/types/src/RegistryPlugin.workerd.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +4 -2
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/dev-plugin-loader.d.ts +11 -0
- package/dist/types/src/capabilities/dev-plugin-loader.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +15 -3
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +3 -2
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts +14 -0
- package/dist/types/src/capabilities/settings.d.ts.map +1 -0
- package/dist/types/src/commands/disable.d.ts +11 -0
- package/dist/types/src/commands/disable.d.ts.map +1 -0
- package/dist/types/src/commands/enable.d.ts +11 -0
- package/dist/types/src/commands/enable.d.ts.map +1 -0
- package/dist/types/src/commands/index.d.ts +3 -0
- package/dist/types/src/commands/index.d.ts.map +1 -0
- package/dist/types/src/commands/list.d.ts +7 -0
- package/dist/types/src/commands/list.d.ts.map +1 -0
- package/dist/types/src/commands/util.d.ts +11 -0
- package/dist/types/src/commands/util.d.ts.map +1 -0
- package/dist/types/src/components/DisableDependentsAlert/DisableDependentsAlert.d.ts +24 -0
- package/dist/types/src/components/DisableDependentsAlert/DisableDependentsAlert.d.ts.map +1 -0
- package/dist/types/src/components/DisableDependentsAlert/index.d.ts +2 -0
- package/dist/types/src/components/DisableDependentsAlert/index.d.ts.map +1 -0
- package/dist/types/src/components/PluginDetail/PluginDetail.d.ts +82 -0
- package/dist/types/src/components/PluginDetail/PluginDetail.d.ts.map +1 -0
- package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts +77 -0
- package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts.map +1 -0
- package/dist/types/src/components/PluginDetail/index.d.ts +2 -0
- package/dist/types/src/components/PluginDetail/index.d.ts.map +1 -0
- package/dist/types/src/components/PluginFailureBadge/PluginFailureBadge.d.ts +20 -0
- package/dist/types/src/components/PluginFailureBadge/PluginFailureBadge.d.ts.map +1 -0
- package/dist/types/src/components/PluginFailureBadge/index.d.ts +2 -0
- package/dist/types/src/components/PluginFailureBadge/index.d.ts.map +1 -0
- package/dist/types/src/components/PluginList/PluginItem.d.ts +40 -0
- package/dist/types/src/components/PluginList/PluginItem.d.ts.map +1 -0
- package/dist/types/src/components/PluginList/PluginList.d.ts +23 -0
- package/dist/types/src/components/PluginList/PluginList.d.ts.map +1 -0
- package/dist/types/src/components/PluginList/PluginList.stories.d.ts +76 -0
- package/dist/types/src/components/PluginList/PluginList.stories.d.ts.map +1 -0
- package/dist/types/src/components/PluginList/index.d.ts +2 -0
- package/dist/types/src/components/PluginList/index.d.ts.map +1 -0
- package/dist/types/src/components/RegistrySettings/RegistrySettings.d.ts +18 -0
- package/dist/types/src/components/RegistrySettings/RegistrySettings.d.ts.map +1 -0
- package/dist/types/src/components/RegistrySettings/index.d.ts +2 -0
- package/dist/types/src/components/RegistrySettings/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +3 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/BaseRegistryArticle/BaseRegistryArticle.d.ts +20 -0
- package/dist/types/src/containers/BaseRegistryArticle/BaseRegistryArticle.d.ts.map +1 -0
- package/dist/types/src/containers/BaseRegistryArticle/index.d.ts +2 -0
- package/dist/types/src/containers/BaseRegistryArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/LoadPluginDialog/LoadPluginDialog.d.ts +4 -0
- package/dist/types/src/containers/LoadPluginDialog/LoadPluginDialog.d.ts.map +1 -0
- package/dist/types/src/containers/LoadPluginDialog/index.d.ts +2 -0
- package/dist/types/src/containers/LoadPluginDialog/index.d.ts.map +1 -0
- package/dist/types/src/containers/PluginArticle/PluginArticle.d.ts +7 -0
- package/dist/types/src/containers/PluginArticle/PluginArticle.d.ts.map +1 -0
- package/dist/types/src/containers/PluginArticle/index.d.ts +2 -0
- package/dist/types/src/containers/PluginArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/PublicRegistryArticle/PublicRegistryArticle.d.ts +8 -0
- package/dist/types/src/containers/PublicRegistryArticle/PublicRegistryArticle.d.ts.map +1 -0
- package/dist/types/src/containers/PublicRegistryArticle/index.d.ts +2 -0
- package/dist/types/src/containers/PublicRegistryArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts +14 -0
- package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts.map +1 -0
- package/dist/types/src/containers/RegistryArticle/index.d.ts +2 -0
- package/dist/types/src/containers/RegistryArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.d.ts +13 -0
- package/dist/types/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.d.ts.map +1 -0
- package/dist/types/src/containers/RegistrySettingsContainer/index.d.ts +2 -0
- package/dist/types/src/containers/RegistrySettingsContainer/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +8 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +9 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useAutoTags.d.ts +20 -0
- package/dist/types/src/hooks/useAutoTags.d.ts.map +1 -0
- package/dist/types/src/hooks/useCatalogEntry.d.ts +11 -0
- package/dist/types/src/hooks/useCatalogEntry.d.ts.map +1 -0
- package/dist/types/src/hooks/useDisableConfirmation.d.ts +19 -0
- package/dist/types/src/hooks/useDisableConfirmation.d.ts.map +1 -0
- package/dist/types/src/hooks/useInstalledVersionTag.d.ts +18 -0
- package/dist/types/src/hooks/useInstalledVersionTag.d.ts.map +1 -0
- package/dist/types/src/hooks/usePluginActions.d.ts +36 -0
- package/dist/types/src/hooks/usePluginActions.d.ts.map +1 -0
- package/dist/types/src/hooks/useRegistryPlugins.d.ts +15 -0
- package/dist/types/src/hooks/useRegistryPlugins.d.ts.map +1 -0
- package/dist/types/src/hooks/useUpdateAvailable.d.ts +18 -0
- package/dist/types/src/hooks/useUpdateAvailable.d.ts.map +1 -0
- package/dist/types/src/hooks/useVersionPicker.d.ts +21 -0
- package/dist/types/src/hooks/useVersionPicker.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +20 -3
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts +3 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/operations/open-plugin-registry.d.ts +5 -0
- package/dist/types/src/operations/open-plugin-registry.d.ts.map +1 -0
- package/dist/types/src/plugin.d.ts +4 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/storage.d.ts +18 -0
- package/dist/types/src/storage.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +57 -16
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +31 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +76 -36
- package/src/RegistryPlugin.node.ts +19 -0
- package/src/RegistryPlugin.test.ts +24 -0
- package/src/RegistryPlugin.tsx +19 -25
- package/src/RegistryPlugin.workerd.ts +11 -0
- package/src/capabilities/app-graph-builder.ts +180 -136
- package/src/capabilities/dev-plugin-loader.ts +39 -0
- package/src/capabilities/index.ts +10 -4
- package/src/capabilities/operation-handler.ts +16 -0
- package/src/capabilities/react-surface.tsx +133 -73
- package/src/capabilities/settings.ts +34 -0
- package/src/commands/disable.ts +47 -0
- package/src/commands/enable.ts +44 -0
- package/src/commands/index.ts +14 -0
- package/src/commands/list.ts +41 -0
- package/src/commands/util.ts +24 -0
- package/src/components/DisableDependentsAlert/DisableDependentsAlert.tsx +69 -0
- package/src/components/DisableDependentsAlert/index.ts +5 -0
- package/src/components/PluginDetail/PluginDetail.stories.tsx +45 -0
- package/src/components/PluginDetail/PluginDetail.tsx +340 -0
- package/src/components/PluginDetail/index.ts +5 -0
- package/src/components/PluginFailureBadge/PluginFailureBadge.tsx +68 -0
- package/src/components/PluginFailureBadge/index.ts +5 -0
- package/src/components/PluginList/PluginItem.tsx +226 -0
- package/src/components/PluginList/PluginList.stories.tsx +87 -0
- package/src/components/PluginList/PluginList.tsx +52 -0
- package/src/components/PluginList/index.ts +5 -0
- package/src/components/RegistrySettings/RegistrySettings.tsx +120 -0
- package/src/components/RegistrySettings/index.ts +5 -0
- package/src/components/index.ts +3 -1
- package/src/containers/BaseRegistryArticle/BaseRegistryArticle.tsx +178 -0
- package/src/containers/BaseRegistryArticle/index.ts +5 -0
- package/src/containers/LoadPluginDialog/LoadPluginDialog.tsx +87 -0
- package/src/containers/LoadPluginDialog/index.ts +5 -0
- package/src/containers/PluginArticle/PluginArticle.tsx +117 -0
- package/src/containers/PluginArticle/index.ts +5 -0
- package/src/containers/PublicRegistryArticle/PublicRegistryArticle.tsx +192 -0
- package/src/containers/PublicRegistryArticle/index.ts +5 -0
- package/src/containers/RegistryArticle/RegistryArticle.tsx +53 -0
- package/src/containers/RegistryArticle/index.ts +5 -0
- package/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.tsx +59 -0
- package/src/containers/RegistrySettingsContainer/index.ts +5 -0
- package/src/containers/index.ts +12 -0
- package/src/hooks/index.ts +12 -0
- package/src/hooks/useAutoTags.ts +51 -0
- package/src/hooks/useCatalogEntry.ts +25 -0
- package/src/hooks/useDisableConfirmation.ts +58 -0
- package/src/hooks/useInstalledVersionTag.ts +41 -0
- package/src/hooks/usePluginActions.ts +174 -0
- package/src/hooks/useRegistryPlugins.ts +29 -0
- package/src/hooks/useUpdateAvailable.ts +31 -0
- package/src/hooks/useVersionPicker.ts +112 -0
- package/src/index.ts +1 -1
- package/src/meta.ts +37 -7
- package/src/operations/index.ts +7 -0
- package/src/operations/open-plugin-registry.ts +21 -0
- package/src/plugin.ts +11 -0
- package/src/storage.ts +50 -0
- package/src/translations.ts +62 -15
- package/src/types.ts +36 -0
- package/dist/lib/browser/app-graph-builder-5BKKIS5T.mjs +0 -162
- package/dist/lib/browser/app-graph-builder-5BKKIS5T.mjs.map +0 -7
- package/dist/lib/browser/chunk-MWZPWWWF.mjs +0 -14
- package/dist/lib/browser/chunk-MWZPWWWF.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -69
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-RUD6WFGT.mjs +0 -23
- package/dist/lib/browser/intent-resolver-RUD6WFGT.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/react-surface-FYRVOQGA.mjs +0 -335
- package/dist/lib/browser/react-surface-FYRVOQGA.mjs.map +0 -7
- package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
- package/dist/types/src/components/Icon.stories.d.ts +0 -14
- package/dist/types/src/components/Icon.stories.d.ts.map +0 -1
- package/dist/types/src/components/PluginDetail.d.ts +0 -9
- package/dist/types/src/components/PluginDetail.d.ts.map +0 -1
- package/dist/types/src/components/PluginDetail.stories.d.ts +0 -32
- package/dist/types/src/components/PluginDetail.stories.d.ts.map +0 -1
- package/dist/types/src/components/PluginItem.d.ts +0 -13
- package/dist/types/src/components/PluginItem.d.ts.map +0 -1
- package/dist/types/src/components/PluginList.d.ts +0 -8
- package/dist/types/src/components/PluginList.d.ts.map +0 -1
- package/dist/types/src/components/PluginList.stories.d.ts +0 -36
- package/dist/types/src/components/PluginList.stories.d.ts.map +0 -1
- package/dist/types/src/components/RegistryContainer.d.ts +0 -7
- package/dist/types/src/components/RegistryContainer.d.ts.map +0 -1
- package/src/capabilities/intent-resolver.ts +0 -27
- package/src/components/Icon.stories.tsx +0 -110
- package/src/components/PluginDetail.stories.tsx +0 -44
- package/src/components/PluginDetail.tsx +0 -65
- package/src/components/PluginItem.tsx +0 -119
- package/src/components/PluginList.stories.tsx +0 -82
- package/src/components/PluginList.tsx +0 -26
- package/src/components/RegistryContainer.tsx +0 -84
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import { useCallback, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import { type PluginManager, type Registry, UrlLoader } from '@dxos/app-framework';
|
|
9
|
+
import { useOperationInvoker } from '@dxos/app-framework/ui';
|
|
10
|
+
import { LayoutOperation } from '@dxos/app-toolkit';
|
|
11
|
+
import { useAppGraph } from '@dxos/app-toolkit/ui';
|
|
12
|
+
import { runAndForwardErrors } from '@dxos/effect';
|
|
13
|
+
import { useNode } from '@dxos/plugin-graph';
|
|
14
|
+
|
|
15
|
+
import { getPluginSpecPath } from '#meta';
|
|
16
|
+
|
|
17
|
+
import { useDisableConfirmation } from './useDisableConfirmation';
|
|
18
|
+
|
|
19
|
+
export type PluginActionsProps = {
|
|
20
|
+
manager: PluginManager.PluginManager;
|
|
21
|
+
pluginId: string;
|
|
22
|
+
isInstalled: boolean;
|
|
23
|
+
moduleUrl: string | undefined;
|
|
24
|
+
catalogEntry: Registry.Plugin | undefined;
|
|
25
|
+
pickerVersions: readonly Registry.PluginVersion[];
|
|
26
|
+
selectedVersionTag: string | undefined;
|
|
27
|
+
syncInstalledVersion: () => void;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type PluginActions = {
|
|
31
|
+
installing: boolean;
|
|
32
|
+
updating: boolean;
|
|
33
|
+
handleEnableChange: (enabled: boolean) => void;
|
|
34
|
+
handleUninstall: () => void;
|
|
35
|
+
handleInstall: () => void;
|
|
36
|
+
handleUpdate: () => void;
|
|
37
|
+
handleInstallVersion: () => void;
|
|
38
|
+
handleOpenSpec?: () => void;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The user-facing actions the article exposes — enable/disable, uninstall,
|
|
43
|
+
* install (latest), update (to latest catalog version), and install-from-picker —
|
|
44
|
+
* plus the `installing`/`updating` flags they drive. Each handler ends with a
|
|
45
|
+
* `syncInstalledVersion()` call inside its `Effect.ensuring` so the cached
|
|
46
|
+
* installed version snaps to the freshly-written localStorage value in the same
|
|
47
|
+
* render that clears the in-flight flag.
|
|
48
|
+
*
|
|
49
|
+
* `handleOpenSpec` is included only when a `spec` child graph node exists for
|
|
50
|
+
* this plugin — contributed by whichever plugin can render MDL (today
|
|
51
|
+
* `plugin-code`). When that contributor isn't enabled, the action is absent
|
|
52
|
+
* and the detail view hides its "Open Specification" chip.
|
|
53
|
+
*/
|
|
54
|
+
export const usePluginActions = ({
|
|
55
|
+
manager,
|
|
56
|
+
pluginId,
|
|
57
|
+
isInstalled,
|
|
58
|
+
moduleUrl,
|
|
59
|
+
catalogEntry,
|
|
60
|
+
pickerVersions,
|
|
61
|
+
selectedVersionTag,
|
|
62
|
+
syncInstalledVersion,
|
|
63
|
+
}: PluginActionsProps): PluginActions => {
|
|
64
|
+
const { invokePromise } = useOperationInvoker();
|
|
65
|
+
const { graph } = useAppGraph();
|
|
66
|
+
|
|
67
|
+
const [installing, setInstalling] = useState(false);
|
|
68
|
+
const [updating, setUpdating] = useState(false);
|
|
69
|
+
const requestDisable = useDisableConfirmation(manager, (id) => void runAndForwardErrors(manager.disable(id)));
|
|
70
|
+
|
|
71
|
+
const specPath = getPluginSpecPath(pluginId);
|
|
72
|
+
const hasSpecNode = !!useNode(graph, specPath);
|
|
73
|
+
const handleOpenSpec = useCallback(() => {
|
|
74
|
+
void invokePromise(LayoutOperation.Open, { subject: [specPath] });
|
|
75
|
+
}, [invokePromise, specPath]);
|
|
76
|
+
|
|
77
|
+
const handleEnableChange = useCallback(
|
|
78
|
+
(enabled: boolean) => {
|
|
79
|
+
if (enabled) {
|
|
80
|
+
void runAndForwardErrors(manager.enable(pluginId));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
requestDisable(pluginId);
|
|
85
|
+
},
|
|
86
|
+
[manager, pluginId, requestDisable],
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const handleUninstall = useCallback(() => {
|
|
90
|
+
void runAndForwardErrors(manager.remove(pluginId));
|
|
91
|
+
}, [manager, pluginId]);
|
|
92
|
+
|
|
93
|
+
const handleInstall = useCallback(() => {
|
|
94
|
+
if (!moduleUrl) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
setInstalling(true);
|
|
99
|
+
void Effect.gen(function* () {
|
|
100
|
+
const added = yield* manager.add(moduleUrl);
|
|
101
|
+
yield* manager.enable(added.meta.id);
|
|
102
|
+
if (catalogEntry) {
|
|
103
|
+
UrlLoader.setInstalledVersion(added.meta.id, catalogEntry.version);
|
|
104
|
+
}
|
|
105
|
+
}).pipe(
|
|
106
|
+
Effect.ensuring(
|
|
107
|
+
Effect.sync(() => {
|
|
108
|
+
setInstalling(false);
|
|
109
|
+
syncInstalledVersion();
|
|
110
|
+
}),
|
|
111
|
+
),
|
|
112
|
+
runAndForwardErrors,
|
|
113
|
+
);
|
|
114
|
+
}, [manager, moduleUrl, catalogEntry, syncInstalledVersion]);
|
|
115
|
+
|
|
116
|
+
const handleUpdate = useCallback(() => {
|
|
117
|
+
if (!moduleUrl || !catalogEntry) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
setUpdating(true);
|
|
122
|
+
void Effect.gen(function* () {
|
|
123
|
+
yield* manager.remove(pluginId);
|
|
124
|
+
const added = yield* manager.add(moduleUrl);
|
|
125
|
+
yield* manager.enable(added.meta.id);
|
|
126
|
+
UrlLoader.setInstalledVersion(added.meta.id, catalogEntry.version);
|
|
127
|
+
}).pipe(
|
|
128
|
+
Effect.ensuring(
|
|
129
|
+
Effect.sync(() => {
|
|
130
|
+
setUpdating(false);
|
|
131
|
+
syncInstalledVersion();
|
|
132
|
+
}),
|
|
133
|
+
),
|
|
134
|
+
runAndForwardErrors,
|
|
135
|
+
);
|
|
136
|
+
}, [manager, pluginId, moduleUrl, catalogEntry, syncInstalledVersion]);
|
|
137
|
+
|
|
138
|
+
const handleInstallVersion = useCallback(() => {
|
|
139
|
+
const version = pickerVersions.find((candidate) => candidate.tag === selectedVersionTag);
|
|
140
|
+
if (!version || !version.moduleUrl) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
setInstalling(true);
|
|
145
|
+
void Effect.gen(function* () {
|
|
146
|
+
// Remove existing version before installing a different one.
|
|
147
|
+
if (isInstalled) {
|
|
148
|
+
yield* manager.remove(pluginId);
|
|
149
|
+
}
|
|
150
|
+
const added = yield* manager.add(version.moduleUrl);
|
|
151
|
+
yield* manager.enable(added.meta.id);
|
|
152
|
+
UrlLoader.setInstalledVersion(added.meta.id, version.tag);
|
|
153
|
+
}).pipe(
|
|
154
|
+
Effect.ensuring(
|
|
155
|
+
Effect.sync(() => {
|
|
156
|
+
setInstalling(false);
|
|
157
|
+
syncInstalledVersion();
|
|
158
|
+
}),
|
|
159
|
+
),
|
|
160
|
+
runAndForwardErrors,
|
|
161
|
+
);
|
|
162
|
+
}, [manager, pluginId, isInstalled, selectedVersionTag, pickerVersions, syncInstalledVersion]);
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
installing,
|
|
166
|
+
updating,
|
|
167
|
+
handleEnableChange,
|
|
168
|
+
handleUninstall,
|
|
169
|
+
handleInstall,
|
|
170
|
+
handleUpdate,
|
|
171
|
+
handleInstallVersion,
|
|
172
|
+
handleOpenSpec: hasSpecNode ? handleOpenSpec : undefined,
|
|
173
|
+
};
|
|
174
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
6
|
+
|
|
7
|
+
import { type Registry } from '@dxos/app-framework';
|
|
8
|
+
import { usePluginManager } from '@dxos/app-framework/ui';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reads the registry plugin catalog from `manager.pluginRegistry.plugins`.
|
|
12
|
+
* The catalog is loaded once when the plugin manager is constructed (with a
|
|
13
|
+
* provider) so this hook is purely reactive — subscribers re-render as the
|
|
14
|
+
* `{entries, loading, error}` state settles.
|
|
15
|
+
*/
|
|
16
|
+
export const useRegistryPlugins = (): Registry.PluginsState => {
|
|
17
|
+
const manager = usePluginManager();
|
|
18
|
+
return useAtomValue(manager.pluginRegistry.plugins);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the live `Registry.Manager` from the plugin manager so callers can
|
|
23
|
+
* issue `listVersions` / `getPlugin` calls directly. The catalog state itself
|
|
24
|
+
* is best read through {@link useRegistryPlugins} above.
|
|
25
|
+
*/
|
|
26
|
+
export const useRegistryPluginProvider = (): Registry.Manager => {
|
|
27
|
+
const manager = usePluginManager();
|
|
28
|
+
return manager.pluginRegistry;
|
|
29
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Registry, UrlLoader } from '@dxos/app-framework';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns a set of plugin ids for which the registry has a newer version
|
|
9
|
+
* than what was recorded at install time.
|
|
10
|
+
*
|
|
11
|
+
* Only flags plugins where a version was recorded at install time AND it differs
|
|
12
|
+
* from the catalog's current version. Legacy installs (no version stored) are ignored.
|
|
13
|
+
*
|
|
14
|
+
* NOTE: this is intentionally NOT memoised. The installed-version side of the
|
|
15
|
+
* comparison lives in localStorage and is mutated by `manager.add` /
|
|
16
|
+
* `manager.remove` / `UrlLoader.setInstalledVersion` outside React's view, so a
|
|
17
|
+
* memo keyed on `entries` would happily return stale data for the rest of the
|
|
18
|
+
* session after an update completes (the bug that produced "Update button
|
|
19
|
+
* reappears after Updating…"). The loop is O(catalog size) sync reads — cheap
|
|
20
|
+
* enough to do every render.
|
|
21
|
+
*/
|
|
22
|
+
export const useUpdateAvailableIds = (entries: readonly Registry.Plugin[]): ReadonlySet<string> => {
|
|
23
|
+
const ids = new Set<string>();
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
const installedVersion = UrlLoader.getInstalledVersion(entry.id);
|
|
26
|
+
if (installedVersion !== undefined && installedVersion !== entry.version) {
|
|
27
|
+
ids.add(entry.id);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return ids;
|
|
31
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import { type Dispatch, type SetStateAction, useEffect, useMemo, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import { type Registry, UrlLoader } from '@dxos/app-framework';
|
|
9
|
+
import { runAndForwardErrors } from '@dxos/effect';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Owns the version picker's state machine: fetches the available versions list
|
|
13
|
+
* from the provider, prepends the installed version when the catalog stub omits
|
|
14
|
+
* it, and keeps the selection clamped to whatever's currently in the list (so
|
|
15
|
+
* an external update doesn't strand the trigger on a tag that's no longer
|
|
16
|
+
* available).
|
|
17
|
+
*/
|
|
18
|
+
export const useVersionPicker = ({
|
|
19
|
+
provider,
|
|
20
|
+
pluginId,
|
|
21
|
+
repo,
|
|
22
|
+
moduleUrl,
|
|
23
|
+
installedVersionTag,
|
|
24
|
+
}: {
|
|
25
|
+
provider: Registry.Manager;
|
|
26
|
+
pluginId: string;
|
|
27
|
+
repo: string | undefined;
|
|
28
|
+
moduleUrl: string | undefined;
|
|
29
|
+
installedVersionTag: string | undefined;
|
|
30
|
+
}): {
|
|
31
|
+
pickerVersions: readonly Registry.PluginVersion[];
|
|
32
|
+
selectedVersionTag: string | undefined;
|
|
33
|
+
setSelectedVersionTag: Dispatch<SetStateAction<string | undefined>>;
|
|
34
|
+
} => {
|
|
35
|
+
const [versions, setVersions] = useState<readonly Registry.PluginVersion[]>([]);
|
|
36
|
+
const [selectedVersionTag, setSelectedVersionTag] = useState<string | undefined>();
|
|
37
|
+
|
|
38
|
+
// Load version list once the catalog entry's repo is known. Reset state
|
|
39
|
+
// when `repo` is absent or the fetch fails so a previous plugin's
|
|
40
|
+
// versions don't leak into the picker for the current plugin. The
|
|
41
|
+
// `cancelled` flag guards against a stale in-flight `listVersions`
|
|
42
|
+
// response overwriting the newer state after `repo`/`pluginId` changes.
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (!repo) {
|
|
45
|
+
setVersions([]);
|
|
46
|
+
setSelectedVersionTag(undefined);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Clear stale picker state before fetching so the UI doesn't display the
|
|
50
|
+
// previous plugin's versions/selection while `listVersions` is pending.
|
|
51
|
+
setVersions([]);
|
|
52
|
+
setSelectedVersionTag(undefined);
|
|
53
|
+
let cancelled = false;
|
|
54
|
+
void provider.listVersions(repo).pipe(
|
|
55
|
+
Effect.match({
|
|
56
|
+
onSuccess: (vs) => {
|
|
57
|
+
if (cancelled) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
setVersions(vs);
|
|
61
|
+
// Default selection: the currently installed version, or the latest.
|
|
62
|
+
const installedVersion = UrlLoader.getInstalledVersion(pluginId);
|
|
63
|
+
setSelectedVersionTag(installedVersion ?? vs[0]?.tag);
|
|
64
|
+
},
|
|
65
|
+
onFailure: () => {
|
|
66
|
+
if (cancelled) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
setVersions([]);
|
|
70
|
+
setSelectedVersionTag(undefined);
|
|
71
|
+
},
|
|
72
|
+
}),
|
|
73
|
+
runAndForwardErrors,
|
|
74
|
+
);
|
|
75
|
+
return () => {
|
|
76
|
+
cancelled = true;
|
|
77
|
+
};
|
|
78
|
+
}, [provider, repo, pluginId]);
|
|
79
|
+
|
|
80
|
+
// Make sure the picker always lists the installed version, even if the catalog
|
|
81
|
+
// hasn't surfaced it (the current `listVersions` stub only returns latest).
|
|
82
|
+
const pickerVersions = useMemo<readonly Registry.PluginVersion[]>(() => {
|
|
83
|
+
if (!installedVersionTag) {
|
|
84
|
+
return versions;
|
|
85
|
+
}
|
|
86
|
+
if (versions.some((entry) => entry.tag === installedVersionTag)) {
|
|
87
|
+
return versions;
|
|
88
|
+
}
|
|
89
|
+
const installedEntry: Registry.PluginVersion = {
|
|
90
|
+
tag: installedVersionTag,
|
|
91
|
+
// Picker won't be re-installing this entry unless the user selects + clicks Install,
|
|
92
|
+
// and the catalog moduleUrl is the closest stand-in we have.
|
|
93
|
+
moduleUrl: moduleUrl ?? '',
|
|
94
|
+
};
|
|
95
|
+
return [installedEntry, ...versions];
|
|
96
|
+
}, [versions, installedVersionTag, moduleUrl]);
|
|
97
|
+
|
|
98
|
+
// Keep `selectedVersionTag` in sync when picker contents change (e.g. the user
|
|
99
|
+
// updated the plugin from the list view — installed version moved, picker
|
|
100
|
+
// shrunk, prior selection is no longer in the list).
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (pickerVersions.length === 0) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (selectedVersionTag && pickerVersions.some((entry) => entry.tag === selectedVersionTag)) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
setSelectedVersionTag(installedVersionTag ?? pickerVersions[0]?.tag);
|
|
109
|
+
}, [pickerVersions, selectedVersionTag, installedVersionTag]);
|
|
110
|
+
|
|
111
|
+
return { pickerVersions, selectedVersionTag, setSelectedVersionTag };
|
|
112
|
+
};
|
package/src/index.ts
CHANGED
package/src/meta.ts
CHANGED
|
@@ -2,15 +2,45 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type Plugin } from '@dxos/app-framework';
|
|
6
|
+
import { pinnedWorkspaceId } from '@dxos/app-toolkit';
|
|
7
|
+
import { trim } from '@dxos/util';
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
// TODO(wittjosiah): This is a hack to prevent the previous deck from being set for pinned items.
|
|
9
|
-
// Ideally this should be worked into the data model in a generic way.
|
|
10
|
-
export const REGISTRY_ID = '!dxos:plugin-registry';
|
|
9
|
+
export const REGISTRY_ID = pinnedWorkspaceId('dxos:plugin-registry');
|
|
11
10
|
export const REGISTRY_KEY = 'plugin-registry';
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
// TODO(wittjosiah): Should this be a special separator or use the standard path separator?
|
|
13
|
+
const CATEGORY_SEPARATOR = '>';
|
|
14
|
+
|
|
15
|
+
/** Build a registry category node ID. */
|
|
16
|
+
export const registryCategoryId = (category: string): string => `${REGISTRY_KEY}${CATEGORY_SEPARATOR}${category}`;
|
|
17
|
+
|
|
18
|
+
/** Qualified graph path to a specific plugin node. */
|
|
19
|
+
export const getPluginPath = (pluginId: string): string => `root/${REGISTRY_ID}/${pluginId}`;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Qualified graph path to the bundled MDL spec child node for a plugin.
|
|
23
|
+
*
|
|
24
|
+
* The child is contributed by whichever plugin can render MDL (today:
|
|
25
|
+
* `plugin-code`). plugin-registry only knows the path convention so it can:
|
|
26
|
+
* - dispatch `LayoutOperation.Open` to open the spec viewer, and
|
|
27
|
+
* - probe the app graph for the child's existence to gate the "View
|
|
28
|
+
* specification" button. If no plugin contributes a renderer for the
|
|
29
|
+
* child, the node is absent and the button stays hidden.
|
|
30
|
+
*/
|
|
31
|
+
export const getPluginSpecPath = (pluginId: string): string => `${getPluginPath(pluginId)}/spec`;
|
|
32
|
+
|
|
33
|
+
export const meta: Plugin.Meta = {
|
|
34
|
+
id: 'org.dxos.plugin.registry',
|
|
15
35
|
name: 'Plugins',
|
|
36
|
+
author: 'DXOS',
|
|
37
|
+
description: trim`
|
|
38
|
+
Plugin management system for discovering, installing, and configuring workspace extensions.
|
|
39
|
+
Browse available plugins and customize your workspace capabilities.
|
|
40
|
+
`,
|
|
41
|
+
icon: 'ph--squares-four--regular',
|
|
42
|
+
tags: ['system'],
|
|
16
43
|
};
|
|
44
|
+
|
|
45
|
+
/** Cascade-disable confirmation dialog surface id. */
|
|
46
|
+
export const DISABLE_DEPENDENTS_DIALOG = `${meta.id}.disable-dependents-dialog`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import { LayoutOperation, SettingsOperation, getSpacePath } from '@dxos/app-toolkit';
|
|
8
|
+
import { Operation } from '@dxos/compute';
|
|
9
|
+
|
|
10
|
+
import { REGISTRY_ID } from '#meta';
|
|
11
|
+
|
|
12
|
+
const handler: Operation.WithHandler<typeof SettingsOperation.OpenPluginRegistry> =
|
|
13
|
+
SettingsOperation.OpenPluginRegistry.pipe(
|
|
14
|
+
Operation.withHandler(
|
|
15
|
+
Effect.fnUntraced(function* () {
|
|
16
|
+
yield* Operation.invoke(LayoutOperation.SwitchWorkspace, { subject: getSpacePath(REGISTRY_ID) });
|
|
17
|
+
}),
|
|
18
|
+
),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export default handler;
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Plugin } from '@dxos/app-framework';
|
|
6
|
+
|
|
7
|
+
import { meta } from './meta';
|
|
8
|
+
|
|
9
|
+
export const RegistryPlugin = Plugin.lazy(meta, () => import('#plugin'));
|
|
10
|
+
|
|
11
|
+
export { RegistryOperationHandlerSet } from './operations';
|
package/src/storage.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as FileSystem from '@effect/platform/FileSystem';
|
|
6
|
+
import * as Path from '@effect/platform/Path';
|
|
7
|
+
import * as Effect from 'effect/Effect';
|
|
8
|
+
import * as Schema from 'effect/Schema';
|
|
9
|
+
import * as Yaml from 'yaml';
|
|
10
|
+
|
|
11
|
+
import { DX_CONFIG } from '@dxos/client-protocol';
|
|
12
|
+
|
|
13
|
+
// TODO(wittjosiah): Factor out to app-framework?
|
|
14
|
+
|
|
15
|
+
const PluginsSchema = Schema.Array(Schema.String);
|
|
16
|
+
|
|
17
|
+
/** CLI-only: path to plugins/<profile>.yml (sibling to profile/). */
|
|
18
|
+
const getPluginsConfigPath = (profile: string) => `${DX_CONFIG}/plugins/${profile}.yml`;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load enabled plugins from plugins/<profile>.yml (sibling to profile/).
|
|
22
|
+
* Returns the list of enabled plugin IDs, or an empty array if the file doesn't exist.
|
|
23
|
+
*/
|
|
24
|
+
export const loadEnabledPlugins = Effect.fn(function* ({ profile }: { profile: string }) {
|
|
25
|
+
const fs = yield* FileSystem.FileSystem;
|
|
26
|
+
const pluginsPath = getPluginsConfigPath(profile);
|
|
27
|
+
|
|
28
|
+
const content = yield* fs
|
|
29
|
+
.readFileString(pluginsPath)
|
|
30
|
+
.pipe(Effect.catchTag('SystemError', () => Effect.succeed('[]')));
|
|
31
|
+
|
|
32
|
+
const raw = Yaml.parse(content);
|
|
33
|
+
const parsed = yield* Schema.decodeUnknown(PluginsSchema)(raw ?? []).pipe(
|
|
34
|
+
Effect.catchAll(() => Effect.succeed([] as string[])),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return parsed;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Save enabled plugins to plugins/<profile>.yml.
|
|
42
|
+
*/
|
|
43
|
+
export const saveEnabledPlugins = Effect.fn(function* ({ profile, enabled }: { profile: string; enabled: string[] }) {
|
|
44
|
+
const fs = yield* FileSystem.FileSystem;
|
|
45
|
+
const path = yield* Path.Path;
|
|
46
|
+
const pluginsPath = getPluginsConfigPath(profile);
|
|
47
|
+
yield* fs.makeDirectory(path.dirname(pluginsPath), { recursive: true });
|
|
48
|
+
const encoded = Yaml.stringify(enabled);
|
|
49
|
+
yield* fs.writeFileString(pluginsPath, encoded);
|
|
50
|
+
});
|
package/src/translations.ts
CHANGED
|
@@ -4,26 +4,73 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Resource } from '@dxos/react-ui';
|
|
6
6
|
|
|
7
|
-
import { meta } from '
|
|
7
|
+
import { meta } from '#meta';
|
|
8
8
|
|
|
9
9
|
export const translations = [
|
|
10
10
|
{
|
|
11
11
|
'en-US': {
|
|
12
12
|
[meta.id]: {
|
|
13
|
-
'plugin
|
|
14
|
-
'details
|
|
15
|
-
'home
|
|
16
|
-
'source
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
'
|
|
13
|
+
'plugin.name': 'Registry',
|
|
14
|
+
'details.label': 'Details',
|
|
15
|
+
'home-page.label': 'Website',
|
|
16
|
+
'source.label': 'Source',
|
|
17
|
+
'resources.label': 'Resources',
|
|
18
|
+
'plugin-registry.label': 'Plugins',
|
|
19
|
+
'plugin-settings.label': 'Plugin Settings',
|
|
20
|
+
'bundled-plugins.label': 'Bundled',
|
|
21
|
+
'installed-plugins.label': 'Enabled',
|
|
22
|
+
'recommended-plugins.label': 'Recommended',
|
|
23
|
+
'labs-plugins.label': 'Labs',
|
|
24
|
+
'registry-plugins.label': 'Registry',
|
|
25
|
+
'load-by-url.label': 'Load from URL',
|
|
26
|
+
'load-by-url-dialog.title': 'Load Plugin from URL',
|
|
27
|
+
'plugin-url.label': 'Plugin URL',
|
|
28
|
+
'load-plugin.label': 'Load Plugin',
|
|
29
|
+
'loading.label': 'Loading...',
|
|
30
|
+
'filter.label': 'Filter plugins',
|
|
31
|
+
'filter.placeholder': 'Filter…',
|
|
32
|
+
'registry.loading.label': 'Loading registry plugins…',
|
|
33
|
+
'registry.error.label': 'Failed to load registry plugins: {{message}}',
|
|
34
|
+
'registry.empty.label': 'No registry plugins available.',
|
|
35
|
+
'dev-plugin.section.title': 'Dev plugin',
|
|
36
|
+
'dev-plugin.description':
|
|
37
|
+
'Load a plugin from a local Vite dev server (the `composerPlugin` defaults to port 3967). Composer reattaches it on every reload, surviving HMR — useful when iterating on a community plugin against a live registry version.',
|
|
38
|
+
'dev-plugin.url.label': 'Manifest URL',
|
|
39
|
+
'dev-plugin.url.description':
|
|
40
|
+
'Defaults to the local dev server. Edit if your dev server runs on a different port.',
|
|
41
|
+
'dev-plugin.toggle.label': 'Dev plugin',
|
|
42
|
+
'dev-plugin.toggle.description':
|
|
43
|
+
'Stays on across reloads. If the dev server is offline at boot, a warning is logged and the next reload retries.',
|
|
44
|
+
'dev-plugin.enable.label': 'Enable',
|
|
45
|
+
'dev-plugin.disable.label': 'Disable',
|
|
46
|
+
'dev-plugin.busy.label': 'Loading…',
|
|
47
|
+
'dev-plugin.not-loaded.message':
|
|
48
|
+
'Dev plugin is enabled but not currently loaded. Check that the dev server is running, then reload.',
|
|
49
|
+
'coming-soon.label': 'Coming soon!',
|
|
50
|
+
'open-plugin-registry.label': 'Open plugin registry',
|
|
51
|
+
'install.label': 'Install',
|
|
52
|
+
'installing.label': 'Installing…',
|
|
53
|
+
'uninstall.label': 'Uninstall',
|
|
54
|
+
'update.label': 'Update',
|
|
55
|
+
'updating.label': 'Updating…',
|
|
56
|
+
'versions.label': 'Versions',
|
|
57
|
+
'installed.label': 'installed',
|
|
58
|
+
'install-version.label': 'Install version',
|
|
59
|
+
'failure-badge.label': 'Plugin failure details',
|
|
60
|
+
'failure-title.label': 'Plugin {{phase}} failed: {{reason}}',
|
|
61
|
+
'failure-phase-load.label': 'load',
|
|
62
|
+
'failure-phase-activation.label': 'activation',
|
|
63
|
+
'failure-reason-timeout.label': 'timed out',
|
|
64
|
+
'failure-reason-error.label': 'error',
|
|
65
|
+
'dependencies.label': 'Dependencies',
|
|
66
|
+
'dependents.label': 'Required by',
|
|
67
|
+
'spec.label': 'Specification',
|
|
68
|
+
'open-spec.label': 'Open Specification',
|
|
69
|
+
'disable-dependents-dialog.title': 'Disable dependent plugins?',
|
|
70
|
+
'disable-dependents-dialog.description':
|
|
71
|
+
'Disabling {{plugin}} will also disable the following plugins that depend on it:',
|
|
72
|
+
'disable-dependents-dialog.confirm.label': 'Disable',
|
|
73
|
+
'cancel.label': 'Cancel',
|
|
27
74
|
},
|
|
28
75
|
},
|
|
29
76
|
},
|
package/src/types.ts
CHANGED
|
@@ -2,12 +2,48 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Atom } from '@effect-atom/atom-react';
|
|
5
6
|
import * as Schema from 'effect/Schema';
|
|
6
7
|
|
|
8
|
+
import { Capability } from '@dxos/app-framework';
|
|
9
|
+
|
|
7
10
|
export const RegistrySettingsSchema = Schema.mutable(
|
|
8
11
|
Schema.Struct({
|
|
9
12
|
experimental: Schema.optional(Schema.Boolean),
|
|
13
|
+
/**
|
|
14
|
+
* Manifest URL for a plugin served by a local Vite dev server. The
|
|
15
|
+
* registry settings panel pre-fills this with `localhost:3967`; authors
|
|
16
|
+
* iterating on a different port can edit it.
|
|
17
|
+
*/
|
|
18
|
+
devPluginUrl: Schema.optional(Schema.String),
|
|
19
|
+
/**
|
|
20
|
+
* When true, the registry plugin attempts to load `devPluginUrl` on every
|
|
21
|
+
* app boot. Failures (dev server offline, manifest 404) are logged and
|
|
22
|
+
* the flag stays on so the next boot retries — the user explicitly turns
|
|
23
|
+
* it off when they're done iterating.
|
|
24
|
+
*/
|
|
25
|
+
devPluginEnabled: Schema.optional(Schema.Boolean),
|
|
10
26
|
}),
|
|
11
27
|
);
|
|
12
28
|
|
|
13
29
|
export type RegistrySettings = Schema.Schema.Type<typeof RegistrySettingsSchema>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Per-plugin capabilities exposed by `@dxos/plugin-registry`.
|
|
33
|
+
*/
|
|
34
|
+
export namespace RegistryCapabilities {
|
|
35
|
+
export const Settings = Capability.make<Atom.Writable<RegistrySettings>>('@dxos/plugin-registry/settings');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const RegistryTagType = Schema.Literal(
|
|
39
|
+
'new',
|
|
40
|
+
'beta',
|
|
41
|
+
'labs',
|
|
42
|
+
'popular',
|
|
43
|
+
'featured',
|
|
44
|
+
'experimental',
|
|
45
|
+
'registry',
|
|
46
|
+
'local',
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
export type RegistryTagType = Schema.Schema.Type<typeof RegistryTagType>;
|