@dxos/plugin-registry 0.8.4-main.bc674ce → 0.8.4-main.c351d160a8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/lib/browser/PluginArticle-N2ITBUGD.mjs +29 -0
  2. package/dist/lib/browser/PluginArticle-N2ITBUGD.mjs.map +7 -0
  3. package/dist/lib/browser/PluginRegistry-DKO4UEYH.mjs +78 -0
  4. package/dist/lib/browser/PluginRegistry-DKO4UEYH.mjs.map +7 -0
  5. package/dist/lib/browser/{app-graph-builder-P3ZGGFAR.mjs → app-graph-builder-AHS5BI4Y.mjs} +21 -20
  6. package/dist/lib/browser/app-graph-builder-AHS5BI4Y.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-2YWVCU2W.mjs +191 -0
  8. package/dist/lib/browser/chunk-2YWVCU2W.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-VOAOTNGS.mjs → chunk-KMUDYITM.mjs} +4 -2
  10. package/dist/lib/browser/chunk-KMUDYITM.mjs.map +7 -0
  11. package/dist/lib/browser/cli/index.mjs +15 -16
  12. package/dist/lib/browser/cli/index.mjs.map +3 -3
  13. package/dist/lib/browser/index.mjs +15 -12
  14. package/dist/lib/browser/index.mjs.map +3 -3
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/{operation-resolver-P5PKLPRT.mjs → operation-resolver-PK4B2BZQ.mjs} +7 -6
  17. package/dist/lib/browser/operation-resolver-PK4B2BZQ.mjs.map +7 -0
  18. package/dist/lib/browser/react-surface-ZBP7YXKO.mjs +85 -0
  19. package/dist/lib/browser/react-surface-ZBP7YXKO.mjs.map +7 -0
  20. package/dist/lib/node-esm/PluginArticle-3NEYDKN5.mjs +30 -0
  21. package/dist/lib/node-esm/PluginArticle-3NEYDKN5.mjs.map +7 -0
  22. package/dist/lib/node-esm/PluginRegistry-BYKWC732.mjs +79 -0
  23. package/dist/lib/node-esm/PluginRegistry-BYKWC732.mjs.map +7 -0
  24. package/dist/lib/node-esm/{app-graph-builder-56JXLOGZ.mjs → app-graph-builder-DBDL5WWF.mjs} +21 -20
  25. package/dist/lib/node-esm/app-graph-builder-DBDL5WWF.mjs.map +7 -0
  26. package/dist/lib/node-esm/chunk-BOCFM775.mjs +192 -0
  27. package/dist/lib/node-esm/chunk-BOCFM775.mjs.map +7 -0
  28. package/dist/lib/node-esm/{chunk-SALMIZ2W.mjs → chunk-ENSNUFQK.mjs} +4 -2
  29. package/dist/lib/node-esm/chunk-ENSNUFQK.mjs.map +7 -0
  30. package/dist/lib/node-esm/cli/index.mjs +15 -16
  31. package/dist/lib/node-esm/cli/index.mjs.map +3 -3
  32. package/dist/lib/node-esm/index.mjs +15 -12
  33. package/dist/lib/node-esm/index.mjs.map +3 -3
  34. package/dist/lib/node-esm/meta.json +1 -1
  35. package/dist/lib/node-esm/{operation-resolver-3ZB5W3T3.mjs → operation-resolver-CCHN4NBP.mjs} +7 -6
  36. package/dist/lib/node-esm/operation-resolver-CCHN4NBP.mjs.map +7 -0
  37. package/dist/lib/node-esm/react-surface-FJHMLGZF.mjs +86 -0
  38. package/dist/lib/node-esm/react-surface-FJHMLGZF.mjs.map +7 -0
  39. package/dist/types/src/RegistryPlugin.d.ts.map +1 -1
  40. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +1 -1
  41. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +1 -1
  42. package/dist/types/src/capabilities/operation-resolver/index.d.ts +1 -1
  43. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +1 -1
  44. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +2 -2
  45. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -1
  46. package/dist/types/src/capabilities/react-surface/index.d.ts +1 -1
  47. package/dist/types/src/capabilities/react-surface/index.d.ts.map +1 -1
  48. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +2 -2
  49. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +1 -1
  50. package/dist/types/src/cli/commands/disable.d.ts +2 -2
  51. package/dist/types/src/cli/commands/enable.d.ts +2 -2
  52. package/dist/types/src/cli/plugin.d.ts.map +1 -1
  53. package/dist/types/src/cli/storage.d.ts +4 -4
  54. package/dist/types/src/cli/storage.d.ts.map +1 -1
  55. package/dist/types/src/components/PluginDetail/PluginDetail.d.ts.map +1 -0
  56. package/dist/types/src/components/{PluginDetail.stories.d.ts → PluginDetail/PluginDetail.stories.d.ts} +1 -0
  57. package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts.map +1 -0
  58. package/dist/types/src/components/PluginDetail/index.d.ts +2 -0
  59. package/dist/types/src/components/PluginDetail/index.d.ts.map +1 -0
  60. package/dist/types/src/components/PluginList/PluginItem.d.ts.map +1 -0
  61. package/dist/types/src/components/PluginList/PluginList.d.ts.map +1 -0
  62. package/dist/types/src/components/PluginList/PluginList.stories.d.ts.map +1 -0
  63. package/dist/types/src/components/PluginList/index.d.ts +2 -0
  64. package/dist/types/src/components/PluginList/index.d.ts.map +1 -0
  65. package/dist/types/src/components/index.d.ts +0 -1
  66. package/dist/types/src/components/index.d.ts.map +1 -1
  67. package/dist/types/src/containers/PluginArticle/PluginArticle.d.ts +7 -0
  68. package/dist/types/src/containers/PluginArticle/PluginArticle.d.ts.map +1 -0
  69. package/dist/types/src/containers/PluginArticle/index.d.ts +3 -0
  70. package/dist/types/src/containers/PluginArticle/index.d.ts.map +1 -0
  71. package/dist/types/src/containers/PluginRegistry/PluginRegistry.d.ts +8 -0
  72. package/dist/types/src/containers/PluginRegistry/PluginRegistry.d.ts.map +1 -0
  73. package/dist/types/src/containers/PluginRegistry/index.d.ts +3 -0
  74. package/dist/types/src/containers/PluginRegistry/index.d.ts.map +1 -0
  75. package/dist/types/src/containers/index.d.ts +4 -0
  76. package/dist/types/src/containers/index.d.ts.map +1 -0
  77. package/dist/types/src/meta.d.ts +2 -0
  78. package/dist/types/src/meta.d.ts.map +1 -1
  79. package/dist/types/tsconfig.tsbuildinfo +1 -1
  80. package/package.json +33 -31
  81. package/src/RegistryPlugin.tsx +6 -5
  82. package/src/capabilities/app-graph-builder/app-graph-builder.ts +23 -22
  83. package/src/capabilities/operation-resolver/operation-resolver.ts +4 -3
  84. package/src/capabilities/react-surface/react-surface.tsx +24 -35
  85. package/src/cli/plugin.ts +3 -2
  86. package/src/cli/storage.ts +14 -21
  87. package/src/components/{PluginDetail.stories.tsx → PluginDetail/PluginDetail.stories.tsx} +4 -3
  88. package/src/components/PluginDetail/PluginDetail.tsx +81 -0
  89. package/src/components/PluginDetail/index.ts +5 -0
  90. package/src/components/{PluginItem.tsx → PluginList/PluginItem.tsx} +14 -10
  91. package/src/components/{PluginList.stories.tsx → PluginList/PluginList.stories.tsx} +14 -7
  92. package/src/components/PluginList/index.ts +5 -0
  93. package/src/components/index.ts +0 -1
  94. package/src/containers/PluginArticle/PluginArticle.tsx +28 -0
  95. package/src/containers/PluginArticle/index.ts +7 -0
  96. package/src/{components/RegistryContainer.tsx → containers/PluginRegistry/PluginRegistry.tsx} +23 -20
  97. package/src/containers/PluginRegistry/index.ts +7 -0
  98. package/src/containers/index.ts +8 -0
  99. package/src/meta.ts +4 -4
  100. package/dist/lib/browser/app-graph-builder-P3ZGGFAR.mjs.map +0 -7
  101. package/dist/lib/browser/chunk-VOAOTNGS.mjs.map +0 -7
  102. package/dist/lib/browser/operation-resolver-P5PKLPRT.mjs.map +0 -7
  103. package/dist/lib/browser/react-surface-IIM6T7IA.mjs +0 -337
  104. package/dist/lib/browser/react-surface-IIM6T7IA.mjs.map +0 -7
  105. package/dist/lib/node-esm/app-graph-builder-56JXLOGZ.mjs.map +0 -7
  106. package/dist/lib/node-esm/chunk-SALMIZ2W.mjs.map +0 -7
  107. package/dist/lib/node-esm/operation-resolver-3ZB5W3T3.mjs.map +0 -7
  108. package/dist/lib/node-esm/react-surface-F67P7RC3.mjs +0 -338
  109. package/dist/lib/node-esm/react-surface-F67P7RC3.mjs.map +0 -7
  110. package/dist/types/src/components/PluginDetail.d.ts.map +0 -1
  111. package/dist/types/src/components/PluginDetail.stories.d.ts.map +0 -1
  112. package/dist/types/src/components/PluginItem.d.ts.map +0 -1
  113. package/dist/types/src/components/PluginList.d.ts.map +0 -1
  114. package/dist/types/src/components/PluginList.stories.d.ts.map +0 -1
  115. package/dist/types/src/components/RegistryContainer.d.ts +0 -8
  116. package/dist/types/src/components/RegistryContainer.d.ts.map +0 -1
  117. package/src/components/PluginDetail.tsx +0 -79
  118. /package/dist/types/src/components/{PluginDetail.d.ts → PluginDetail/PluginDetail.d.ts} +0 -0
  119. /package/dist/types/src/components/{PluginItem.d.ts → PluginList/PluginItem.d.ts} +0 -0
  120. /package/dist/types/src/components/{PluginList.d.ts → PluginList/PluginList.d.ts} +0 -0
  121. /package/dist/types/src/components/{PluginList.stories.d.ts → PluginList/PluginList.stories.d.ts} +0 -0
  122. /package/src/components/{PluginList.tsx → PluginList/PluginList.tsx} +0 -0
@@ -7,11 +7,12 @@ import React, { useState } from 'react';
7
7
 
8
8
  import { type Plugin, Plugin as PluginNS } from '@dxos/app-framework';
9
9
  import { faker } from '@dxos/random';
10
+ import { ScrollArea } from '@dxos/react-ui';
10
11
  import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
12
  import { getHashHue } from '@dxos/ui-theme';
12
13
 
13
- import { translations } from '../translations';
14
- import { RegistryTagType } from '../types';
14
+ import { translations } from '../../translations';
15
+ import { RegistryTagType } from '../../types';
15
16
 
16
17
  import { PluginList } from './PluginList';
17
18
 
@@ -31,7 +32,7 @@ const DefaultStory = () => {
31
32
  faker.helpers.multiple(
32
33
  () =>
33
34
  PluginNS.define({
34
- id: `dxos.org/plugin/plugin-${faker.string.uuid()}`,
35
+ id: `org.dxos.plugin.plugin-${faker.string.uuid()}`,
35
36
  name: `${faker.commerce.productName()}`,
36
37
  description: faker.lorem.sentences(Math.ceil(Math.random() * 3)),
37
38
  tags: faker.helpers.uniqueArray(RegistryTagType.literals as any, Math.floor(Math.random() * 3)),
@@ -49,11 +50,17 @@ const DefaultStory = () => {
49
50
  setEnabled((plugins) => (enabled ? [...plugins, id] : plugins.filter((plugin) => plugin === id)));
50
51
  };
51
52
 
52
- return <PluginList plugins={plugins} enabled={enabled} onChange={handleChange} hasSettings={() => true} />;
53
+ return (
54
+ <ScrollArea.Root orientation='vertical'>
55
+ <ScrollArea.Viewport>
56
+ <PluginList plugins={plugins} enabled={enabled} onChange={handleChange} hasSettings={() => true} />
57
+ </ScrollArea.Viewport>
58
+ </ScrollArea.Root>
59
+ );
53
60
  };
54
61
 
55
62
  const meta = {
56
- title: 'plugins/plugin-registry/PluginList',
63
+ title: 'plugins/plugin-registry/components/PluginList',
57
64
  component: PluginList,
58
65
  render: DefaultStory,
59
66
  parameters: {
@@ -66,11 +73,11 @@ export default meta;
66
73
  type Story = StoryObj<typeof meta>;
67
74
 
68
75
  export const Default: Story = {
69
- decorators: [withTheme, withLayout({ layout: 'column', scroll: true })],
76
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
70
77
  };
71
78
 
72
79
  export const FullScreen: Story = {
73
- decorators: [withTheme, withLayout({ scroll: true })],
80
+ decorators: [withTheme(), withLayout({ scroll: true })],
74
81
  parameters: {
75
82
  layout: 'fullscreen',
76
83
  },
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './PluginList';
@@ -4,4 +4,3 @@
4
4
 
5
5
  export * from './PluginDetail';
6
6
  export * from './PluginList';
7
- export * from './RegistryContainer';
@@ -0,0 +1,28 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback } from 'react';
6
+
7
+ import { type Plugin } from '@dxos/app-framework';
8
+ import { usePluginManager } from '@dxos/app-framework/ui';
9
+ import { runAndForwardErrors } from '@dxos/effect';
10
+
11
+ import { PluginDetail } from '../../components';
12
+
13
+ // TODO(burdon): Convert to ECHO type.
14
+ export type PluginArticleProps = { subject: Plugin.Plugin };
15
+
16
+ export const PluginArticle = ({ subject: plugin }: PluginArticleProps) => {
17
+ const manager = usePluginManager();
18
+ const enabled = manager.getEnabled().includes(plugin.meta.id);
19
+ const handleEnableChange = useCallback(
20
+ (enabled: boolean) =>
21
+ enabled
22
+ ? runAndForwardErrors(manager.enable(plugin.meta.id))
23
+ : runAndForwardErrors(manager.disable(plugin.meta.id)),
24
+ [manager, plugin.meta.id],
25
+ );
26
+
27
+ return <PluginDetail plugin={plugin} enabled={enabled} onEnabledChange={handleEnableChange} />;
28
+ };
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { PluginArticle } from './PluginArticle';
6
+
7
+ export default PluginArticle;
@@ -6,28 +6,30 @@ import { useAtomValue } from '@effect-atom/atom-react';
6
6
  import * as Effect from 'effect/Effect';
7
7
  import React, { useCallback, useMemo } from 'react';
8
8
 
9
- import { Common, type Plugin, SettingsOperation } from '@dxos/app-framework';
10
- import { useCapabilities, useOperationInvoker, usePluginManager } from '@dxos/app-framework/react';
9
+ import { type Plugin } from '@dxos/app-framework';
10
+ import { useCapabilities, useOperationInvoker, usePluginManager } from '@dxos/app-framework/ui';
11
+ import { AppCapabilities, LayoutOperation, SettingsOperation } from '@dxos/app-toolkit';
11
12
  import { runAndForwardErrors } from '@dxos/effect';
12
13
  import { ObservabilityOperation } from '@dxos/plugin-observability/types';
13
- import { Layout } from '@dxos/react-ui-mosaic';
14
+ import { ScrollArea } from '@dxos/react-ui';
14
15
 
15
- import { PluginList } from './PluginList';
16
+ import { PluginList } from '../../components';
17
+ import { getPluginPath } from '../../meta';
16
18
 
17
19
  const sortByPluginMeta = ({ meta: { name: a = '' } }: Plugin.Plugin, { meta: { name: b = '' } }: Plugin.Plugin) =>
18
20
  a.localeCompare(b);
19
21
 
20
- export type RegistryContainerProps = {
22
+ export type PluginRegistryProps = {
21
23
  id: string;
22
24
  plugins: Plugin.Plugin[];
23
25
  };
24
26
 
25
- export const RegistryContainer = ({ id, plugins: pluginsProp }: RegistryContainerProps) => {
27
+ export const PluginRegistry = ({ id, plugins: pluginsProp }: PluginRegistryProps) => {
26
28
  const manager = usePluginManager();
27
29
  const { invoke, invokePromise } = useOperationInvoker();
28
30
  const plugins = useMemo(() => pluginsProp.sort(sortByPluginMeta), [pluginsProp]);
29
31
  const enabled = useAtomValue(manager.enabled);
30
- const allSettings = useCapabilities(Common.Capability.Settings);
32
+ const allSettings = useCapabilities(AppCapabilities.Settings);
31
33
 
32
34
  // TODO(wittjosiah): Factor out to an intent?
33
35
  const handleChange = useCallback(
@@ -52,9 +54,8 @@ export const RegistryContainer = ({ id, plugins: pluginsProp }: RegistryContaine
52
54
 
53
55
  const handleClick = useCallback(
54
56
  (pluginId: string) =>
55
- invokePromise(Common.LayoutOperation.Open, {
56
- // TODO(wittjosiah): `/` currently is not supported in ids.
57
- subject: [pluginId.replaceAll('/', ':')],
57
+ invokePromise(LayoutOperation.Open, {
58
+ subject: [getPluginPath(pluginId)],
58
59
  pivotId: id,
59
60
  positioning: 'end',
60
61
  }),
@@ -69,15 +70,17 @@ export const RegistryContainer = ({ id, plugins: pluginsProp }: RegistryContaine
69
70
  );
70
71
 
71
72
  return (
72
- <Layout.Container scrollable>
73
- <PluginList
74
- plugins={plugins}
75
- enabled={enabled}
76
- onClick={handleClick}
77
- onChange={handleChange}
78
- hasSettings={hasSettings}
79
- onSettings={handleSettings}
80
- />
81
- </Layout.Container>
73
+ <ScrollArea.Root orientation='vertical'>
74
+ <ScrollArea.Viewport>
75
+ <PluginList
76
+ plugins={plugins}
77
+ enabled={enabled}
78
+ onClick={handleClick}
79
+ onChange={handleChange}
80
+ hasSettings={hasSettings}
81
+ onSettings={handleSettings}
82
+ />
83
+ </ScrollArea.Viewport>
84
+ </ScrollArea.Root>
82
85
  );
83
86
  };
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { PluginRegistry } from './PluginRegistry';
6
+
7
+ export default PluginRegistry;
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type ComponentType, lazy } from 'react';
6
+
7
+ export const PluginArticle: ComponentType<any> = lazy(() => import('./PluginArticle'));
8
+ export const PluginRegistry: ComponentType<any> = lazy(() => import('./PluginRegistry'));
package/src/meta.ts CHANGED
@@ -5,14 +5,14 @@
5
5
  import { type Plugin } from '@dxos/app-framework';
6
6
  import { trim } from '@dxos/util';
7
7
 
8
- // TODO(wittjosiah): Deck does not currently support `/` in ids.
9
- // TODO(wittjosiah): This is a hack to prevent the previous deck from being set for pinned items.
10
- // Ideally this should be worked into the data model in a generic way.
11
8
  export const REGISTRY_ID = '!dxos:plugin-registry';
12
9
  export const REGISTRY_KEY = 'plugin-registry';
13
10
 
11
+ /** Qualified graph path to a specific plugin node. */
12
+ export const getPluginPath = (pluginId: string): string => `root/${REGISTRY_ID}/${pluginId}`;
13
+
14
14
  export const meta: Plugin.Meta = {
15
- id: 'dxos.org/plugin/registry',
15
+ id: 'org.dxos.plugin.registry',
16
16
  name: 'Plugins',
17
17
  description: trim`
18
18
  Plugin management system for discovering, installing, and configuring workspace extensions.
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/capabilities/app-graph-builder/app-graph-builder.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capability, Common, SettingsOperation } from '@dxos/app-framework';\nimport { Operation } from '@dxos/operation';\nimport { GraphBuilder, NodeMatcher } from '@dxos/plugin-graph';\n\nimport { REGISTRY_ID, REGISTRY_KEY, meta } from '../../meta';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const capabilities = yield* Capability.Service;\n\n const extensions = yield* Effect.all([\n GraphBuilder.createExtension({\n id: meta.id,\n match: NodeMatcher.whenRoot,\n actions: () =>\n Effect.succeed([\n {\n id: meta.id,\n data: () => Operation.invoke(SettingsOperation.OpenPluginRegistry),\n properties: {\n label: ['open plugin registry label', { ns: meta.id }],\n icon: 'ph--squares-four--regular',\n disposition: 'menu',\n },\n },\n ]),\n }),\n GraphBuilder.createExtension({\n id: meta.id,\n match: NodeMatcher.whenRoot,\n connector: () =>\n Effect.succeed([\n {\n id: REGISTRY_ID,\n type: meta.id,\n properties: {\n label: ['plugin registry label', { ns: meta.id }],\n icon: 'ph--squares-four--regular',\n disposition: 'pin-end',\n testId: 'treeView.pluginRegistry',\n },\n nodes: [\n {\n id: `${REGISTRY_KEY}+all`,\n type: 'category',\n data: `${REGISTRY_KEY}+all`,\n properties: {\n label: ['all plugins label', { ns: meta.id }],\n icon: 'ph--squares-four--regular',\n key: REGISTRY_KEY,\n testId: 'pluginRegistry.all',\n },\n },\n {\n id: `${REGISTRY_KEY}+installed`,\n type: 'category',\n data: `${REGISTRY_KEY}+installed`,\n properties: {\n label: ['installed plugins label', { ns: meta.id }],\n icon: 'ph--check--regular',\n key: REGISTRY_KEY,\n testId: 'pluginRegistry.installed',\n },\n },\n {\n id: `${REGISTRY_KEY}+recommended`,\n type: 'category',\n data: `${REGISTRY_KEY}+recommended`,\n properties: {\n label: ['recommended plugins label', { ns: meta.id }],\n icon: 'ph--star--regular',\n key: REGISTRY_KEY,\n testId: 'pluginRegistry.recommended',\n },\n },\n {\n id: `${REGISTRY_KEY}+labs`,\n type: 'category',\n data: `${REGISTRY_KEY}+labs`,\n properties: {\n label: ['labs plugins label', { ns: meta.id }],\n icon: 'ph--flask--regular',\n key: REGISTRY_KEY,\n testId: 'pluginRegistry.labs',\n },\n },\n ],\n },\n ]),\n }),\n GraphBuilder.createExtension({\n id: `${meta.id}/actions`,\n match: NodeMatcher.whenId(REGISTRY_ID),\n actions: () =>\n Effect.succeed([\n {\n id: `${meta.id}/load-by-url`,\n data: Effect.fnUntraced(function* () {}),\n properties: {\n label: ['load by url label', { ns: meta.id }],\n icon: 'ph--cloud-arrow-down--regular',\n disabled: true,\n },\n },\n ]),\n }),\n GraphBuilder.createExtension({\n id: `${meta.id}/plugins`,\n match: NodeMatcher.whenId(REGISTRY_ID),\n connector: () => {\n const manager = capabilities.get(Common.Capability.PluginManager);\n return Effect.succeed(\n manager.getPlugins().map((plugin) => ({\n id: plugin.meta.id.replaceAll('/', ':'),\n type: 'dxos.org/plugin',\n data: plugin,\n properties: {\n label: plugin.meta.name ?? plugin.meta.id,\n icon: plugin.meta.icon ?? 'ph--circle--regular',\n disposition: 'hidden',\n },\n })),\n );\n },\n }),\n ]);\n\n return Capability.contributes(Common.Capability.AppGraphBuilder, extensions);\n }),\n);\n"],
5
- "mappings": "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",
6
- "names": ["Effect", "Capability", "Common", "SettingsOperation", "Operation", "GraphBuilder", "NodeMatcher", "Capability", "makeModule", "fnUntraced", "capabilities", "Service", "extensions", "all", "GraphBuilder", "createExtension", "id", "meta", "match", "NodeMatcher", "whenRoot", "actions", "succeed", "data", "Operation", "invoke", "SettingsOperation", "OpenPluginRegistry", "properties", "label", "ns", "icon", "disposition", "connector", "REGISTRY_ID", "type", "testId", "nodes", "REGISTRY_KEY", "key", "whenId", "disabled", "manager", "get", "Common", "PluginManager", "getPlugins", "map", "plugin", "replaceAll", "name", "contributes", "AppGraphBuilder"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/meta.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Plugin } from '@dxos/app-framework';\nimport { trim } from '@dxos/util';\n\n// TODO(wittjosiah): Deck does not currently support `/` in ids.\n// TODO(wittjosiah): This is a hack to prevent the previous deck from being set for pinned items.\n// Ideally this should be worked into the data model in a generic way.\nexport const REGISTRY_ID = '!dxos:plugin-registry';\nexport const REGISTRY_KEY = 'plugin-registry';\n\nexport const meta: Plugin.Meta = {\n id: 'dxos.org/plugin/registry',\n name: 'Plugins',\n description: trim`\n Plugin management system for discovering, installing, and configuring workspace extensions.\n Browse available plugins and customize your workspace capabilities.\n `,\n};\n"],
5
- "mappings": ";AAKA,SAASA,YAAY;AAKd,IAAMC,cAAc;AACpB,IAAMC,eAAe;AAErB,IAAMC,OAAoB;EAC/BC,IAAI;EACJC,MAAM;EACNC,aAAaC;;;;AAIf;",
6
- "names": ["trim", "REGISTRY_ID", "REGISTRY_KEY", "meta", "id", "name", "description", "trim"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/capabilities/operation-resolver/operation-resolver.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capability, Common, SettingsOperation } from '@dxos/app-framework';\nimport { Operation, OperationResolver } from '@dxos/operation';\n\nimport { REGISTRY_ID } from '../../meta';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contributes(Common.Capability.OperationResolver, [\n OperationResolver.make({\n operation: SettingsOperation.OpenPluginRegistry,\n handler: Effect.fnUntraced(function* () {\n yield* Operation.invoke(Common.LayoutOperation.SwitchWorkspace, { subject: REGISTRY_ID });\n }),\n }),\n ]);\n }),\n);\n"],
5
- "mappings": ";;;;;AAIA,YAAYA,YAAY;AAExB,SAASC,YAAYC,QAAQC,yBAAyB;AACtD,SAASC,WAAWC,yBAAyB;AAI7C,IAAA,6BAAeC,WAAWC,WACjBC,kBAAW,aAAA;AAChB,SAAOF,WAAWG,YAAYC,OAAOJ,WAAWK,mBAAmB;IACjEA,kBAAkBC,KAAK;MACrBC,WAAWC,kBAAkBC;MAC7BC,SAAgBR,kBAAW,aAAA;AACzB,eAAOS,UAAUC,OAAOR,OAAOS,gBAAgBC,iBAAiB;UAAEC,SAASC;QAAY,CAAA;MACzF,CAAA;IACF,CAAA;GACD;AACH,CAAA,CAAA;",
6
- "names": ["Effect", "Capability", "Common", "SettingsOperation", "Operation", "OperationResolver", "Capability", "makeModule", "fnUntraced", "contributes", "Common", "OperationResolver", "make", "operation", "SettingsOperation", "OpenPluginRegistry", "handler", "Operation", "invoke", "LayoutOperation", "SwitchWorkspace", "subject", "REGISTRY_ID"]
7
- }
@@ -1,337 +0,0 @@
1
- import {
2
- REGISTRY_KEY,
3
- meta
4
- } from "./chunk-VOAOTNGS.mjs";
5
-
6
- // src/capabilities/react-surface/react-surface.tsx
7
- import * as Effect2 from "effect/Effect";
8
- import React5, { useCallback as useCallback3, useMemo as useMemo2 } from "react";
9
- import { Capability, Common as Common2, Plugin } from "@dxos/app-framework";
10
- import { usePluginManager as usePluginManager2 } from "@dxos/app-framework/react";
11
- import { runAndForwardErrors as runAndForwardErrors2 } from "@dxos/effect";
12
-
13
- // src/components/PluginDetail.tsx
14
- import React from "react";
15
- import { Icon, Input, Link, useTranslation } from "@dxos/react-ui";
16
- import { Layout } from "@dxos/react-ui-mosaic";
17
- import { getStyles, mx } from "@dxos/ui-theme";
18
- var PluginDetail = ({ plugin, enabled, onEnabledChange }) => {
19
- const { t } = useTranslation(meta.id);
20
- const { id, name, description, homePage, source, screenshots, icon = "ph--circle--regular", iconHue = "neutral" } = plugin.meta;
21
- const styles = getStyles(iconHue);
22
- return /* @__PURE__ */ React.createElement(Layout.Container, {
23
- scrollable: true
24
- }, /* @__PURE__ */ React.createElement("div", {
25
- role: "none",
26
- className: "grid grid-cols-[min-content_1fr] gap-4 container-max-width p-4"
27
- }, /* @__PURE__ */ React.createElement("div", {
28
- role: "none"
29
- }, /* @__PURE__ */ React.createElement(Icon, {
30
- classNames: mx("p-1 rounded", styles.bg, styles.icon),
31
- icon,
32
- size: 14
33
- })), /* @__PURE__ */ React.createElement("div", {
34
- role: "none",
35
- className: "flex flex-col gap-6"
36
- }, /* @__PURE__ */ React.createElement("div", {
37
- role: "none",
38
- className: "grid grid-cols-[1fr_min-content] gap-x-3 is-full pbs-1"
39
- }, /* @__PURE__ */ React.createElement("h2", {
40
- className: "text-xl"
41
- }, name), /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement(Input.Switch, {
42
- classNames: "self-center",
43
- checked: enabled,
44
- onCheckedChange: onEnabledChange
45
- })), /* @__PURE__ */ React.createElement("p", {
46
- className: "pbs-0.5 text-sm text-description"
47
- }, id)), /* @__PURE__ */ React.createElement("div", {
48
- role: "none"
49
- }, /* @__PURE__ */ React.createElement("p", {
50
- className: "text-description"
51
- }, description)), screenshots && screenshots.length > 0 && /* @__PURE__ */ React.createElement("div", {
52
- role: "none",
53
- className: "flex flex-col gap-2"
54
- }, /* @__PURE__ */ React.createElement("h2", null, "Preview"), /* @__PURE__ */ React.createElement("img", {
55
- src: screenshots[0],
56
- alt: name,
57
- className: "aspect-video object-fit"
58
- })), /* @__PURE__ */ React.createElement("div", {
59
- role: "none",
60
- className: "flex flex-col gap-2"
61
- }, /* @__PURE__ */ React.createElement("h2", null, "Resources"), /* @__PURE__ */ React.createElement("div", {
62
- className: "flex gap-2"
63
- }, homePage && /* @__PURE__ */ React.createElement(Link, {
64
- href: homePage,
65
- target: "_blank",
66
- rel: "noreferrer",
67
- classNames: "text-sm text-description"
68
- }, t("home page label"), /* @__PURE__ */ React.createElement(Icon, {
69
- icon: "ph--arrow-square-out--bold",
70
- size: 3,
71
- classNames: "inline-block leading-none mli-1"
72
- })), source && /* @__PURE__ */ React.createElement(Link, {
73
- href: source,
74
- target: "_blank",
75
- rel: "noreferrer",
76
- classNames: "text-sm text-description"
77
- }, t("source label"), /* @__PURE__ */ React.createElement(Icon, {
78
- icon: "ph--arrow-square-out--bold",
79
- size: 3,
80
- classNames: "inline-block leading-none mli-1"
81
- })))))));
82
- };
83
-
84
- // src/components/PluginList.tsx
85
- import React3 from "react";
86
- import { List } from "@dxos/react-ui";
87
-
88
- // src/components/PluginItem.tsx
89
- import React2, { useCallback } from "react";
90
- import { Icon as Icon2, IconButton, Input as Input2, Link as Link2, ListItem, Tag, useTranslation as useTranslation2 } from "@dxos/react-ui";
91
- import { descriptionText, mx as mx2 } from "@dxos/ui-theme";
92
- import { getStyles as getStyles2 } from "@dxos/ui-theme";
93
- var PluginItem = ({ plugin, enabled = [], onClick, onChange, hasSettings: hasSettingsProp, onSettings }) => {
94
- const { t } = useTranslation2(meta.id);
95
- const { id, name, description, tags, icon = "ph--circle--regular", iconHue = "neutral" } = plugin.meta;
96
- const isEnabled = enabled.includes(id);
97
- const inputId = `${id}-input`;
98
- const labelId = `${id}-label`;
99
- const descriptionId = `${id}-description`;
100
- const handleClick = useCallback(() => onClick?.(id), [
101
- id,
102
- onClick
103
- ]);
104
- const handleChange = useCallback((event) => {
105
- event.stopPropagation();
106
- onChange?.(id, !isEnabled);
107
- }, [
108
- id,
109
- isEnabled,
110
- onChange
111
- ]);
112
- const hasSettings = hasSettingsProp?.(id) ?? false;
113
- const handleSettings = useCallback(() => onSettings?.(id), [
114
- id,
115
- onSettings
116
- ]);
117
- const styles = getStyles2(iconHue);
118
- const gridCols = "grid grid-cols-[5rem_1fr]";
119
- const gridRows = "grid grid-rows-[40px_1fr_min-content_40px]";
120
- return /* @__PURE__ */ React2.createElement(ListItem.Root, {
121
- key: id,
122
- labelId,
123
- "data-testid": `pluginList.${id}`,
124
- "aria-describedby": descriptionId,
125
- classNames: mx2(gridCols, "bs-[12rem] is-full gap-3 pie-2 border border-separator rounded-md overflow-hidden")
126
- }, /* @__PURE__ */ React2.createElement("div", {
127
- className: mx2(gridRows, "justify-center rounded-l-md", styles.bg)
128
- }, /* @__PURE__ */ React2.createElement("div", null), /* @__PURE__ */ React2.createElement(Icon2, {
129
- classNames: mx2("cursor-pointer", styles.icon),
130
- icon,
131
- size: 14,
132
- onClick: handleClick
133
- })), /* @__PURE__ */ React2.createElement("div", {
134
- className: mx2(gridRows)
135
- }, /* @__PURE__ */ React2.createElement("div", {
136
- className: "flex items-center overflow-hidden cursor-pointer",
137
- onClick: handleClick
138
- }, /* @__PURE__ */ React2.createElement("span", {
139
- className: "text-lg truncate"
140
- }, name ?? id)), /* @__PURE__ */ React2.createElement("div", null, /* @__PURE__ */ React2.createElement("p", {
141
- className: mx2(descriptionText, "line-clamp-4 min-is-0")
142
- }, description)), /* @__PURE__ */ React2.createElement("div", {
143
- className: "flex -mis-0.5 overflow-x-auto scrollbar-none"
144
- }, tags?.map((tag) => /* @__PURE__ */ React2.createElement(Tag, {
145
- key: tag,
146
- palette: tagColors[tag],
147
- classNames: "text-xs uppercase font-thin"
148
- }, tag))), /* @__PURE__ */ React2.createElement("div", {
149
- className: "flex gap-2 items-center text-sm"
150
- }, /* @__PURE__ */ React2.createElement(IconButton, {
151
- "aria-describedby": descriptionId,
152
- classNames: "cursor-pointer",
153
- icon: "ph--gear--regular",
154
- label: t("settings label"),
155
- iconOnly: true,
156
- size: 4,
157
- onClick: handleSettings,
158
- disabled: !hasSettings
159
- }), /* @__PURE__ */ React2.createElement(Link2, {
160
- "aria-describedby": descriptionId,
161
- classNames: "text-description cursor-pointer",
162
- onClick: handleClick
163
- }, t("details label")), /* @__PURE__ */ React2.createElement("div", {
164
- className: "grow"
165
- }), /* @__PURE__ */ React2.createElement("div", {
166
- className: "pie-1"
167
- }, /* @__PURE__ */ React2.createElement(Input2.Root, {
168
- id: inputId
169
- }, /* @__PURE__ */ React2.createElement(Input2.Switch, {
170
- classNames: "self-center",
171
- checked: isEnabled,
172
- onClick: handleChange
173
- }))))));
174
- };
175
- var tagColors = {
176
- new: "rose",
177
- beta: "teal",
178
- labs: "blue",
179
- popular: "green",
180
- featured: "pink",
181
- experimental: "amber"
182
- };
183
-
184
- // src/components/PluginList.tsx
185
- var PluginList = ({ plugins = [], ...props }) => {
186
- return /* @__PURE__ */ React3.createElement(List, {
187
- classNames: "grid grid-cols-[repeat(auto-fill,minmax(18rem,1fr))] auto-rows-[max-content] gap-4 p-4"
188
- }, plugins.map((plugin) => /* @__PURE__ */ React3.createElement(PluginItem, {
189
- key: plugin.meta.id,
190
- plugin,
191
- ...props
192
- })));
193
- };
194
-
195
- // src/components/RegistryContainer.tsx
196
- import { useAtomValue } from "@effect-atom/atom-react";
197
- import * as Effect from "effect/Effect";
198
- import React4, { useCallback as useCallback2, useMemo } from "react";
199
- import { Common, SettingsOperation } from "@dxos/app-framework";
200
- import { useCapabilities, useOperationInvoker, usePluginManager } from "@dxos/app-framework/react";
201
- import { runAndForwardErrors } from "@dxos/effect";
202
- import { ObservabilityOperation } from "@dxos/plugin-observability/types";
203
- import { Layout as Layout2 } from "@dxos/react-ui-mosaic";
204
- var sortByPluginMeta = ({ meta: { name: a = "" } }, { meta: { name: b = "" } }) => a.localeCompare(b);
205
- var RegistryContainer = ({ id, plugins: pluginsProp }) => {
206
- const manager = usePluginManager();
207
- const { invoke, invokePromise } = useOperationInvoker();
208
- const plugins = useMemo(() => pluginsProp.sort(sortByPluginMeta), [
209
- pluginsProp
210
- ]);
211
- const enabled = useAtomValue(manager.enabled);
212
- const allSettings = useCapabilities(Common.Capability.Settings);
213
- const handleChange = useCallback2((id2, enabled2) => Effect.gen(function* () {
214
- if (enabled2) {
215
- yield* manager.enable(id2);
216
- } else {
217
- yield* manager.disable(id2);
218
- }
219
- yield* invoke(ObservabilityOperation.SendEvent, {
220
- name: "plugins.toggle",
221
- properties: {
222
- plugin: id2,
223
- enabled: enabled2
224
- }
225
- });
226
- }).pipe(runAndForwardErrors), [
227
- invoke,
228
- manager
229
- ]);
230
- const handleClick = useCallback2((pluginId) => invokePromise(Common.LayoutOperation.Open, {
231
- // TODO(wittjosiah): `/` currently is not supported in ids.
232
- subject: [
233
- pluginId.replaceAll("/", ":")
234
- ],
235
- pivotId: id,
236
- positioning: "end"
237
- }), [
238
- invokePromise,
239
- id
240
- ]);
241
- const hasSettings = useCallback2((pluginId) => allSettings.some((s) => s.prefix === pluginId), [
242
- allSettings
243
- ]);
244
- const handleSettings = useCallback2((pluginId) => invokePromise(SettingsOperation.Open, {
245
- plugin: pluginId
246
- }), [
247
- invokePromise
248
- ]);
249
- return /* @__PURE__ */ React4.createElement(Layout2.Container, {
250
- scrollable: true
251
- }, /* @__PURE__ */ React4.createElement(PluginList, {
252
- plugins,
253
- enabled,
254
- onClick: handleClick,
255
- onChange: handleChange,
256
- hasSettings,
257
- onSettings: handleSettings
258
- }));
259
- };
260
-
261
- // src/capabilities/react-surface/react-surface.tsx
262
- var react_surface_default = Capability.makeModule(() => Effect2.succeed(Capability.contributes(Common2.Capability.ReactSurface, [
263
- Common2.createSurface({
264
- id: `${meta.id}/all`,
265
- role: "article",
266
- filter: (data) => data.subject === `${REGISTRY_KEY}+all`,
267
- component: () => {
268
- const manager = usePluginManager2();
269
- const filtered = useMemo2(() => manager.getPlugins().filter(({ meta: meta2 }) => !manager.getCore().includes(meta2.id)), []);
270
- return /* @__PURE__ */ React5.createElement(RegistryContainer, {
271
- id: `${REGISTRY_KEY}+all`,
272
- plugins: filtered
273
- });
274
- }
275
- }),
276
- Common2.createSurface({
277
- id: `${meta.id}/installed`,
278
- role: "article",
279
- filter: (data) => data.subject === `${REGISTRY_KEY}+installed`,
280
- component: () => {
281
- const manager = usePluginManager2();
282
- const filtered = useMemo2(() => manager.getPlugins().filter(({ meta: meta2 }) => !manager.getCore().includes(meta2.id)).filter(({ meta: meta2 }) => manager.getEnabled().includes(meta2.id)), []);
283
- return /* @__PURE__ */ React5.createElement(RegistryContainer, {
284
- id: `${REGISTRY_KEY}+installed`,
285
- plugins: filtered
286
- });
287
- }
288
- }),
289
- Common2.createSurface({
290
- id: `${meta.id}/recommended`,
291
- role: "article",
292
- filter: (data) => data.subject === `${REGISTRY_KEY}+recommended`,
293
- component: () => {
294
- const manager = usePluginManager2();
295
- const filtered = useMemo2(() => manager.getPlugins().filter(({ meta: meta2 }) => !manager.getCore().includes(meta2.id)).filter(({ meta: meta2 }) => !meta2.tags?.includes("labs")), []);
296
- return /* @__PURE__ */ React5.createElement(RegistryContainer, {
297
- id: `${REGISTRY_KEY}+recommended`,
298
- plugins: filtered
299
- });
300
- }
301
- }),
302
- Common2.createSurface({
303
- id: `${meta.id}/labs`,
304
- role: "article",
305
- filter: (data) => data.subject === `${REGISTRY_KEY}+labs`,
306
- component: () => {
307
- const manager = usePluginManager2();
308
- const filtered = useMemo2(() => manager.getPlugins().filter(({ meta: meta2 }) => meta2.tags?.includes("labs")), []);
309
- return /* @__PURE__ */ React5.createElement(RegistryContainer, {
310
- id: `${REGISTRY_KEY}+labs`,
311
- plugins: filtered
312
- });
313
- }
314
- }),
315
- Common2.createSurface({
316
- id: `${meta.id}/plugin-details`,
317
- role: "article",
318
- filter: (data) => Plugin.isPlugin(data.subject),
319
- component: ({ data: { subject } }) => {
320
- const manager = usePluginManager2();
321
- const enabled = manager.getEnabled().includes(subject.meta.id);
322
- const handleEnableChange = useCallback3((enabled2) => enabled2 ? runAndForwardErrors2(manager.enable(subject.meta.id)) : runAndForwardErrors2(manager.disable(subject.meta.id)), [
323
- manager,
324
- subject.meta.id
325
- ]);
326
- return /* @__PURE__ */ React5.createElement(PluginDetail, {
327
- plugin: subject,
328
- enabled,
329
- onEnabledChange: handleEnableChange
330
- });
331
- }
332
- })
333
- ])));
334
- export {
335
- react_surface_default as default
336
- };
337
- //# sourceMappingURL=react-surface-IIM6T7IA.mjs.map