@dxos/plugin-registry 0.13.0 → 0.14.0

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 (35) hide show
  1. package/dist/lib/chunk-BaseRegistryArticle.mjs +6 -7
  2. package/dist/lib/chunk-BaseRegistryArticle.mjs.map +1 -1
  3. package/dist/lib/chunk-PluginArticle.mjs +2 -2
  4. package/dist/lib/chunk-PluginArticle.mjs.map +1 -1
  5. package/dist/lib/chunk-PublicRegistryArticle.mjs +2 -2
  6. package/dist/lib/chunk-PublicRegistryArticle.mjs.map +1 -1
  7. package/dist/lib/chunk-RegistryArticle.mjs +2 -2
  8. package/dist/lib/chunk-RegistryArticle.mjs.map +1 -1
  9. package/dist/lib/chunk-react-surface.mjs +19 -7
  10. package/dist/lib/chunk-react-surface.mjs.map +1 -1
  11. package/dist/lib/components.mjs +31 -19
  12. package/dist/lib/components.mjs.map +1 -1
  13. package/dist/types/src/capabilities/RegistryCategoryArticle.d.ts +2 -1
  14. package/dist/types/src/capabilities/RegistryCategoryArticle.d.ts.map +1 -1
  15. package/dist/types/src/components/PluginFailureBadge/PluginFailureBadge.d.ts.map +1 -1
  16. package/dist/types/src/components/PluginList/PluginItem.d.ts +2 -1
  17. package/dist/types/src/components/PluginList/PluginItem.d.ts.map +1 -1
  18. package/dist/types/src/containers/BaseRegistryArticle/BaseRegistryArticle.d.ts +1 -2
  19. package/dist/types/src/containers/BaseRegistryArticle/BaseRegistryArticle.d.ts.map +1 -1
  20. package/dist/types/src/containers/PublicRegistryArticle/PublicRegistryArticle.d.ts +1 -1
  21. package/dist/types/src/containers/PublicRegistryArticle/PublicRegistryArticle.d.ts.map +1 -1
  22. package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts +1 -1
  23. package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts.map +1 -1
  24. package/dist/types/tsconfig.tsbuildinfo +1 -1
  25. package/package.json +30 -30
  26. package/src/capabilities/RegistryCategoryArticle.tsx +8 -2
  27. package/src/capabilities/react-surface.ts +5 -5
  28. package/src/components/PluginDetail/PluginDetail.tsx +17 -15
  29. package/src/components/PluginFailureBadge/PluginFailureBadge.tsx +3 -2
  30. package/src/components/PluginList/PluginItem.tsx +7 -3
  31. package/src/containers/BaseRegistryArticle/BaseRegistryArticle.tsx +4 -13
  32. package/src/containers/PluginArticle/PluginArticle.tsx +1 -1
  33. package/src/containers/PublicRegistryArticle/PublicRegistryArticle.tsx +3 -3
  34. package/src/containers/RegistryArticle/RegistryArticle.tsx +3 -3
  35. package/src/hooks/usePluginActions.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-registry",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Braneframe plugin gallery",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -122,29 +122,29 @@
122
122
  "dependencies": {
123
123
  "@effect/atom-react": "4.0.0",
124
124
  "yaml": "^2.8.2",
125
- "@dxos/app-framework": "0.13.0",
126
- "@dxos/app-graph": "0.13.0",
127
- "@dxos/app-toolkit": "0.13.0",
128
- "@dxos/cli-util": "0.13.0",
129
- "@dxos/client": "0.13.0",
130
- "@dxos/client-protocol": "0.13.0",
131
- "@dxos/compute": "0.13.0",
132
- "@dxos/context": "0.13.0",
133
- "@dxos/echo": "0.13.0",
134
- "@dxos/edge-client": "0.13.0",
135
- "@dxos/effect": "0.13.0",
136
- "@dxos/errors": "0.13.0",
137
- "@dxos/graph": "0.13.0",
138
- "@dxos/keys": "0.13.0",
139
- "@dxos/link": "0.13.0",
140
- "@dxos/log": "0.13.0",
141
- "@dxos/plugin-client": "0.13.0",
142
- "@dxos/plugin-graph": "0.13.0",
143
- "@dxos/plugin-observability": "0.13.0",
144
- "@dxos/protocols": "0.13.0",
145
- "@dxos/react-ui-form": "0.13.0",
146
- "@dxos/react-ui-markdown": "0.13.0",
147
- "@dxos/util": "0.13.0"
125
+ "@dxos/app-framework": "0.14.0",
126
+ "@dxos/app-graph": "0.14.0",
127
+ "@dxos/app-toolkit": "0.14.0",
128
+ "@dxos/cli-util": "0.14.0",
129
+ "@dxos/client": "0.14.0",
130
+ "@dxos/client-protocol": "0.14.0",
131
+ "@dxos/compute": "0.14.0",
132
+ "@dxos/context": "0.14.0",
133
+ "@dxos/echo": "0.14.0",
134
+ "@dxos/edge-client": "0.14.0",
135
+ "@dxos/effect": "0.14.0",
136
+ "@dxos/errors": "0.14.0",
137
+ "@dxos/graph": "0.14.0",
138
+ "@dxos/keys": "0.14.0",
139
+ "@dxos/link": "0.14.0",
140
+ "@dxos/log": "0.14.0",
141
+ "@dxos/plugin-client": "0.14.0",
142
+ "@dxos/plugin-graph": "0.14.0",
143
+ "@dxos/plugin-observability": "0.14.0",
144
+ "@dxos/protocols": "0.14.0",
145
+ "@dxos/react-ui-form": "0.14.0",
146
+ "@dxos/react-ui-markdown": "0.14.0",
147
+ "@dxos/util": "0.14.0"
148
148
  },
149
149
  "devDependencies": {
150
150
  "@effect/atom-react": "4.0.0",
@@ -155,18 +155,18 @@
155
155
  "react": "~19.2.7",
156
156
  "react-dom": "~19.2.7",
157
157
  "vite": "^8.2.2",
158
- "@dxos/plugin-testing": "0.13.0",
159
- "@dxos/random": "0.13.0",
160
- "@dxos/react-ui": "0.13.0",
161
- "@dxos/ui-theme": "0.13.0"
158
+ "@dxos/plugin-testing": "0.14.0",
159
+ "@dxos/random": "0.14.0",
160
+ "@dxos/react-ui": "0.14.0",
161
+ "@dxos/ui-theme": "0.14.0"
162
162
  },
163
163
  "peerDependencies": {
164
164
  "@effect/atom-react": "4.0.0",
165
165
  "effect": "4.0.0",
166
166
  "react": "~19.2.7",
167
167
  "react-dom": "~19.2.7",
168
- "@dxos/react-ui": "^0.13.0",
169
- "@dxos/ui-theme": "^0.13.0"
168
+ "@dxos/react-ui": "^0.14.0",
169
+ "@dxos/ui-theme": "^0.14.0"
170
170
  },
171
171
  "publishConfig": {
172
172
  "access": "public"
@@ -29,6 +29,7 @@ const useCategoryPredicate = (category: string): PluginPredicate => {
29
29
  };
30
30
 
31
31
  export type RegistryCategoryArticleProps = {
32
+ contextId: string;
32
33
  category: string;
33
34
  };
34
35
 
@@ -37,7 +38,7 @@ export type RegistryCategoryArticleProps = {
37
38
  * `usePluginManager` + `useRegistryPlugins` + `useAutoTags` wiring shared by every category surface,
38
39
  * none of which can live in a surface's `props` mapper.
39
40
  */
40
- export const RegistryCategoryArticle = ({ category }: RegistryCategoryArticleProps) => {
41
+ export const RegistryCategoryArticle = ({ contextId, category }: RegistryCategoryArticleProps) => {
41
42
  const manager = PluginManagerProvider.usePluginManager();
42
43
  const filter = useCategoryPredicate(category);
43
44
  const { entries } = useRegistryPlugins();
@@ -46,6 +47,11 @@ export const RegistryCategoryArticle = ({ category }: RegistryCategoryArticlePro
46
47
  const filtered = useMemo(() => manager.getPlugins().filter(filter), [manager, filter]);
47
48
 
48
49
  return (
49
- <RegistryArticle id={category} plugins={filtered} extraTagsById={extraTagsById} deviceOnlyIds={deviceOnlyIds} />
50
+ <RegistryArticle
51
+ contextId={contextId}
52
+ plugins={filtered}
53
+ extraTagsById={extraTagsById}
54
+ deviceOnlyIds={deviceOnlyIds}
55
+ />
50
56
  );
51
57
  };
@@ -26,7 +26,7 @@ export default Capability.makeModule(({ externalPlugins = true }: RegistryPlugin
26
26
  id: 'registry',
27
27
  filter: AppSurface.literal(AppSurface.Article, 'registry'),
28
28
  component: PublicRegistryArticle,
29
- props: () => ({ id: 'registry' }),
29
+ props: ({ data: { attendableId } }) => ({ contextId: attendableId }),
30
30
  }),
31
31
  Surface.create({
32
32
  id: LOAD_PLUGIN_DIALOG,
@@ -48,25 +48,25 @@ export default Capability.makeModule(({ externalPlugins = true }: RegistryPlugin
48
48
  id: 'bundled',
49
49
  filter: AppSurface.literal(AppSurface.Article, 'bundled'),
50
50
  component: RegistryCategoryArticle,
51
- props: () => ({ category: 'bundled' }),
51
+ props: ({ data: { attendableId } }) => ({ contextId: attendableId, category: 'bundled' }),
52
52
  }),
53
53
  Surface.create({
54
54
  id: 'installed',
55
55
  filter: AppSurface.literal(AppSurface.Article, 'installed'),
56
56
  component: RegistryCategoryArticle,
57
- props: () => ({ category: 'installed' }),
57
+ props: ({ data: { attendableId } }) => ({ contextId: attendableId, category: 'installed' }),
58
58
  }),
59
59
  Surface.create({
60
60
  id: 'recommended',
61
61
  filter: AppSurface.literal(AppSurface.Article, 'recommended'),
62
62
  component: RegistryCategoryArticle,
63
- props: () => ({ category: 'recommended' }),
63
+ props: ({ data: { attendableId } }) => ({ contextId: attendableId, category: 'recommended' }),
64
64
  }),
65
65
  Surface.create({
66
66
  id: 'labs',
67
67
  filter: AppSurface.literal(AppSurface.Article, 'labs'),
68
68
  component: RegistryCategoryArticle,
69
- props: () => ({ category: 'labs' }),
69
+ props: ({ data: { attendableId } }) => ({ contextId: attendableId, category: 'labs' }),
70
70
  }),
71
71
  Surface.create({
72
72
  id: 'pluginDetails',
@@ -180,10 +180,10 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
180
180
  />
181
181
 
182
182
  <Layout.Grid cols={['fill', 'min']} classNames='row-start-1 col-start-2 col-span-2 gap-x-3 w-full pt-1'>
183
- <div className='flex items-center gap-2'>
183
+ <Layout.Flex align='center' gap='sm'>
184
184
  <h2 className='text-xl'>{name}</h2>
185
185
  {failure && <PluginFailureBadge failure={failure} size='lg' />}
186
- </div>
186
+ </Layout.Flex>
187
187
  {onInstall ? (
188
188
  <Button.Root size='md' variant='primary' disabled={installing} onClick={onInstall}>
189
189
  {installing ? t('installing.label') : t('install.label')}
@@ -197,14 +197,14 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
197
197
  />
198
198
  </Field.Root>
199
199
  )}
200
- <div className='flex items-center gap-1 pt-0.5 text-sm text-fg-muted'>
200
+ <Layout.Flex align='center' gap='xs' classNames='pt-0.5 text-sm text-fg-muted'>
201
201
  {slug}
202
202
  {author && (
203
203
  <span className='dx-tag dx-tag-inline' data-hue='info'>
204
204
  {author}
205
205
  </span>
206
206
  )}
207
- </div>
207
+ </Layout.Flex>
208
208
  </Layout.Grid>
209
209
 
210
210
  {scope && (
@@ -242,7 +242,7 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
242
242
  <Section.Root>
243
243
  <Section.Heading title={t('resources.label')} />
244
244
  <Section.Body>
245
- <div className='flex gap-3 items-center'>
245
+ <Layout.Flex gap='md' align='center'>
246
246
  {homePage && (
247
247
  <Typography.Link href={homePage} classNames='text-sm text-fg-muted'>
248
248
  {t('home-page.label')}
@@ -266,7 +266,7 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
266
266
  )}
267
267
 
268
268
  {onOpenSpec && <Chip id={slug} name={t('open-spec.label')} onClick={onOpenSpec} />}
269
- </div>
269
+ </Layout.Flex>
270
270
  </Section.Body>
271
271
  </Section.Root>
272
272
 
@@ -274,7 +274,7 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
274
274
  <Section.Root>
275
275
  <Section.Heading title={t('dependencies.label')} />
276
276
  <Section.Body>
277
- <div className='flex flex-wrap gap-1'>
277
+ <Layout.Flex wrap gap='xs'>
278
278
  {dependencies.map((depId) => (
279
279
  <Chip
280
280
  key={depId}
@@ -283,7 +283,7 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
283
283
  onClick={onNavigateToPlugin}
284
284
  />
285
285
  ))}
286
- </div>
286
+ </Layout.Flex>
287
287
  </Section.Body>
288
288
  </Section.Root>
289
289
  )}
@@ -292,7 +292,7 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
292
292
  <Section.Root>
293
293
  <Section.Heading title={t('dependents.label')} />
294
294
  <Section.Body>
295
- <div className='flex flex-wrap gap-1'>
295
+ <Layout.Flex wrap gap='xs'>
296
296
  {dependents.map((dependentId) => (
297
297
  <Chip
298
298
  key={dependentId}
@@ -301,7 +301,7 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
301
301
  onClick={onNavigateToPlugin}
302
302
  />
303
303
  ))}
304
- </div>
304
+ </Layout.Flex>
305
305
  </Section.Body>
306
306
  </Section.Root>
307
307
  )}
@@ -310,7 +310,7 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
310
310
  <Section.Root>
311
311
  <Section.Heading title={t('versions.label')} />
312
312
  <Section.Body>
313
- <div className='flex gap-2 items-center'>
313
+ <Layout.Flex gap='sm' align='center'>
314
314
  <Select.Root
315
315
  items={versionItems}
316
316
  value={selectedVersionTag ? [selectedVersionTag] : []}
@@ -333,13 +333,13 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
333
333
  {installing ? t('installing.label') : t('install-version.label')}
334
334
  </Button.Root>
335
335
  )}
336
- </div>
336
+ </Layout.Flex>
337
337
  </Section.Body>
338
338
  </Section.Root>
339
339
  )}
340
340
 
341
341
  {(onUninstall || (hasUpdate && onUpdate) || updating) && (
342
- <div className='col-start-2 col-span-2 flex gap-2'>
342
+ <Layout.Flex gap='sm' classNames='col-start-2 col-span-2'>
343
343
  {updating ? (
344
344
  <Button.Root variant='primary' disabled>
345
345
  {t('updating.label')}
@@ -350,7 +350,7 @@ export const PluginDetail = Util.composable<HTMLDivElement, PluginDetailProps>(
350
350
  </Button.Root>
351
351
  ) : null}
352
352
  {onUninstall && <Button.Root onClick={onUninstall}>{t('uninstall.label')}</Button.Root>}
353
- </div>
353
+ </Layout.Flex>
354
354
  )}
355
355
  </Layout.Grid>
356
356
  </ScrollArea.Viewport>
@@ -368,7 +368,9 @@ const SectionHeading = ({ title }: { title: string }) => (
368
368
  );
369
369
 
370
370
  const SectionBody = ({ classNames, children }: Util.ThemedClassName<PropsWithChildren>) => (
371
- <div className={mx('col-start-2 flex flex-col gap-2', classNames)}>{children}</div>
371
+ <Layout.Flex column gap='sm' classNames={['col-start-2', classNames]}>
372
+ {children}
373
+ </Layout.Flex>
372
374
  );
373
375
 
374
376
  const Section = {
@@ -7,6 +7,7 @@ import React, { type ComponentPropsWithoutRef } from 'react';
7
7
  import type * as PluginManager from '@dxos/app-framework/PluginManager';
8
8
  import * as Button from '@dxos/react-ui/Button';
9
9
  import * as Hooks from '@dxos/react-ui/Hooks';
10
+ import * as Layout from '@dxos/react-ui/Layout';
10
11
  import * as Popover from '@dxos/react-ui/Popover';
11
12
 
12
13
  import { meta } from '#meta';
@@ -43,7 +44,7 @@ export const PluginFailureBadge = ({ failure, size }: PluginFailureBadgeProps) =
43
44
  </Popover.Trigger>
44
45
  <Popover.Content>
45
46
  <Popover.Body>
46
- <div className='px-3 py-2 min-w-[18rem] max-w-[28rem] flex flex-col gap-1'>
47
+ <Layout.Flex column gap='xs' classNames='px-3 py-2 min-w-[18rem] max-w-[28rem]'>
47
48
  <p className='font-medium text-sm'>
48
49
  {t('failure-title.label', {
49
50
  phase: failure.phase === 'load' ? t('failure-phase-load.label') : t('failure-phase-activation.label'),
@@ -52,7 +53,7 @@ export const PluginFailureBadge = ({ failure, size }: PluginFailureBadgeProps) =
52
53
  })}
53
54
  </p>
54
55
  <p className='text-fg-muted text-sm break-words'>{failure.error.message}</p>
55
- </div>
56
+ </Layout.Flex>
56
57
  </Popover.Body>
57
58
  </Popover.Content>
58
59
  </Popover.Root>
@@ -2,10 +2,11 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useMemo } from 'react';
5
+ import React, { type MouseEvent, useCallback, useMemo } from 'react';
6
6
 
7
7
  import type * as Plugin from '@dxos/app-framework/Plugin';
8
8
  import type * as PluginManager from '@dxos/app-framework/PluginManager';
9
+ import type * as ToolkitHooks from '@dxos/app-toolkit/Hooks';
9
10
  import * as Button from '@dxos/react-ui/Button';
10
11
  import * as Card from '@dxos/react-ui/Card';
11
12
  import * as Hooks from '@dxos/react-ui/Hooks';
@@ -34,7 +35,7 @@ export type PluginItemProps = {
34
35
  extraTags?: readonly string[];
35
36
  /** Whether this device's answer for this plugin differs from the account's. */
36
37
  deviceOnly?: boolean;
37
- onClick?: (id: string) => void;
38
+ onClick?: (id: string, activation: ToolkitHooks.DetailActivation) => void;
38
39
  onChange?: (id: string, enabled: boolean) => void;
39
40
  /**
40
41
  * Install handler. When provided and the plugin is not installed, an Install button
@@ -101,7 +102,10 @@ export const PluginItem = ({
101
102
  const showUpdateButton = !!onUpdate && isInstalled && !!hasUpdate;
102
103
  const hasSettings = hasSettingsProp?.(id) ?? false;
103
104
  const titleId = `${id}-title`;
104
- const handleClick = useCallback(() => onClick?.(id), [id, onClick]);
105
+ const handleClick = useCallback(
106
+ (event: MouseEvent) => onClick?.(id, { modified: event.metaKey || event.ctrlKey }),
107
+ [id, onClick],
108
+ );
105
109
  const handleSettings = useCallback(() => onSettings?.(id), [id, onSettings]);
106
110
  const handleInstall = useCallback(() => onInstall?.(id), [id, onInstall]);
107
111
  const handleUpdate = useCallback(() => onUpdate?.(id), [id, onUpdate]);
@@ -12,7 +12,7 @@ import '@dxos/react-ui/theme.css';
12
12
  import type * as Plugin from '@dxos/app-framework/Plugin';
13
13
  import * as PluginManagerProvider from '@dxos/app-framework/PluginManagerProvider';
14
14
  import * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';
15
- import * as LayoutOperation from '@dxos/app-toolkit/LayoutOperation';
15
+ import * as ToolkitHooks from '@dxos/app-toolkit/Hooks';
16
16
  import * as SettingsOperation from '@dxos/app-toolkit/SettingsOperation';
17
17
  import * as EffectEx from '@dxos/effect/EffectEx';
18
18
  import * as ObservabilityOperation from '@dxos/plugin-observability/ObservabilityOperation';
@@ -36,8 +36,7 @@ const matchesFilter = (plugin: Plugin.Plugin, query: string) => {
36
36
  };
37
37
 
38
38
  export type BaseRegistryArticleProps = {
39
- /** Article id used as the pivotId when opening a plugin's detail surface. */
40
- id: string;
39
+ contextId: string;
41
40
  /** Plugins to display, pre-sorted by the caller. */
42
41
  plugins: readonly Plugin.Plugin[];
43
42
  /**
@@ -63,7 +62,7 @@ export type BaseRegistryArticleProps = {
63
62
  export const BaseRegistryArticle = Util.composable<HTMLDivElement, BaseRegistryArticleProps>(
64
63
  (
65
64
  {
66
- id,
65
+ contextId,
67
66
  plugins,
68
67
  source,
69
68
  empty,
@@ -124,15 +123,7 @@ export const BaseRegistryArticle = Util.composable<HTMLDivElement, BaseRegistryA
124
123
  [dispatchToggle, requestDisable],
125
124
  );
126
125
 
127
- const handleClick = useCallback(
128
- (pluginId: string) =>
129
- invokePromise(LayoutOperation.Open, {
130
- subject: [getPluginPath(pluginId)],
131
- pivotId: getPluginPath(id),
132
- disposition: 'add',
133
- }),
134
- [invokePromise, id],
135
- );
126
+ const handleClick = ToolkitHooks.useDetailNavigation({ contextId, getPath: getPluginPath });
136
127
 
137
128
  const hasSettings = useCallback(
138
129
  (pluginId: string) => allSettings.some((setting) => setting.prefix === pluginId),
@@ -82,7 +82,7 @@ export const PluginArticle = ({ subject: plugin }: PluginArticleProps) => {
82
82
  void invokePromise(LayoutOperation.Open, {
83
83
  subject: [getPluginPath(targetId)],
84
84
  pivotId: getPluginPath(pluginId),
85
- disposition: 'add',
85
+ disposition: 'detail',
86
86
  });
87
87
  },
88
88
  [invokePromise, pluginId],
@@ -52,11 +52,11 @@ const toDisplayPlugin = (plugin: Plugin.Meta): Plugin.Plugin =>
52
52
  }) as Plugin.Plugin;
53
53
 
54
54
  export type PublicRegistryArticleProps = {
55
- id: string;
55
+ contextId: string;
56
56
  };
57
57
 
58
58
  export const PublicRegistryArticle = Util.composable<HTMLDivElement, PublicRegistryArticleProps>(
59
- ({ id, ...props }, forwardedRef) => {
59
+ ({ contextId, ...props }, forwardedRef) => {
60
60
  const { t } = UiHooks.useTranslation(meta.profile.key);
61
61
  const manager = PluginManagerProvider.usePluginManager();
62
62
  const { invoke } = Hooks.useOperationInvoker();
@@ -187,7 +187,7 @@ export const PublicRegistryArticle = Util.composable<HTMLDivElement, PublicRegis
187
187
  return (
188
188
  <BaseRegistryArticle
189
189
  {...props}
190
- id={id}
190
+ contextId={contextId}
191
191
  source='registry'
192
192
  plugins={items}
193
193
  installed={installedIds}
@@ -16,7 +16,7 @@ const sortByPluginMeta = (a: Plugin.Plugin, b: Plugin.Plugin) =>
16
16
  (a.meta.profile.name ?? a.meta.profile.key).localeCompare(b.meta.profile.name ?? b.meta.profile.key);
17
17
 
18
18
  export type RegistryArticleProps = {
19
- id: string;
19
+ contextId: string;
20
20
  plugins: Plugin.Plugin[];
21
21
  /**
22
22
  * Map from plugin id → display-only tags (e.g. `registry`, `local`) computed by the caller.
@@ -25,7 +25,7 @@ export type RegistryArticleProps = {
25
25
  };
26
26
 
27
27
  export const RegistryArticle = Util.composable<HTMLDivElement, RegistryArticleProps>(
28
- ({ id, plugins: pluginsProp, extraTagsById, ...props }, forwardedRef) => {
28
+ ({ contextId, plugins: pluginsProp, extraTagsById, ...props }, forwardedRef) => {
29
29
  const manager = PluginManagerProvider.usePluginManager();
30
30
  const failed = useAtomValue(manager.failed);
31
31
  const plugins = useMemo(() => [...pluginsProp].sort(sortByPluginMeta), [pluginsProp]);
@@ -41,7 +41,7 @@ export const RegistryArticle = Util.composable<HTMLDivElement, RegistryArticlePr
41
41
  return (
42
42
  <BaseRegistryArticle
43
43
  {...props}
44
- id={id}
44
+ contextId={contextId}
45
45
  plugins={plugins}
46
46
  extraTagsById={extraTagsById}
47
47
  failuresById={failuresById}
@@ -78,7 +78,7 @@ export const usePluginActions = ({
78
78
  void invokePromise(LayoutOperation.Open, {
79
79
  subject: [specPath],
80
80
  pivotId: getPluginPath(pluginId),
81
- disposition: 'add',
81
+ disposition: 'detail',
82
82
  });
83
83
  }, [invokePromise, specPath, pluginId]);
84
84