@dxos/plugin-space 0.6.11-staging.e6894a4 → 0.6.12-main.15a606f

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 (70) hide show
  1. package/dist/lib/browser/{chunk-DTVUOG2C.mjs → chunk-WBMH5WIP.mjs} +14 -2
  2. package/dist/lib/browser/chunk-WBMH5WIP.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +500 -186
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/types/index.mjs +7 -3
  7. package/dist/lib/node/{chunk-CVZPI2P3.cjs → chunk-GF3SRAQM.cjs} +20 -6
  8. package/dist/lib/node/chunk-GF3SRAQM.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +589 -279
  10. package/dist/lib/node/index.cjs.map +4 -4
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/types/index.cjs +14 -10
  13. package/dist/lib/node/types/index.cjs.map +2 -2
  14. package/dist/lib/node-esm/chunk-GM2YUC77.mjs +37 -0
  15. package/dist/lib/node-esm/chunk-GM2YUC77.mjs.map +7 -0
  16. package/dist/lib/node-esm/chunk-N5VC55UM.mjs +109 -0
  17. package/dist/lib/node-esm/chunk-N5VC55UM.mjs.map +7 -0
  18. package/dist/lib/node-esm/index.mjs +2953 -0
  19. package/dist/lib/node-esm/index.mjs.map +7 -0
  20. package/dist/lib/node-esm/meta.json +1 -0
  21. package/dist/lib/node-esm/meta.mjs +14 -0
  22. package/dist/lib/node-esm/meta.mjs.map +7 -0
  23. package/dist/lib/node-esm/types/index.mjs +26 -0
  24. package/dist/lib/node-esm/types/index.mjs.map +7 -0
  25. package/dist/types/src/SpacePlugin.d.ts.map +1 -1
  26. package/dist/types/src/components/MenuFooter.d.ts.map +1 -1
  27. package/dist/types/src/components/SaveStatus.d.ts +3 -0
  28. package/dist/types/src/components/SaveStatus.d.ts.map +1 -0
  29. package/dist/types/src/components/ShareSpaceButton.stories.d.ts +2 -0
  30. package/dist/types/src/components/ShareSpaceButton.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/SpaceMain/SpaceMain.d.ts.map +1 -1
  32. package/dist/types/src/components/SpacePresence.stories.d.ts +2 -0
  33. package/dist/types/src/components/SpacePresence.stories.d.ts.map +1 -1
  34. package/dist/types/src/components/SpaceSettings.d.ts.map +1 -1
  35. package/dist/types/src/components/SyncStatus/SyncStatus.d.ts +13 -0
  36. package/dist/types/src/components/SyncStatus/SyncStatus.d.ts.map +1 -0
  37. package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts +115 -0
  38. package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts.map +1 -0
  39. package/dist/types/src/components/SyncStatus/index.d.ts +2 -0
  40. package/dist/types/src/components/SyncStatus/index.d.ts.map +1 -0
  41. package/dist/types/src/components/SyncStatus/types.d.ts +14 -0
  42. package/dist/types/src/components/SyncStatus/types.d.ts.map +1 -0
  43. package/dist/types/src/components/index.d.ts +2 -0
  44. package/dist/types/src/components/index.d.ts.map +1 -1
  45. package/dist/types/src/translations.d.ts +2 -0
  46. package/dist/types/src/translations.d.ts.map +1 -1
  47. package/dist/types/src/types/thread.d.ts +13 -0
  48. package/dist/types/src/types/thread.d.ts.map +1 -1
  49. package/dist/types/src/types/types.d.ts +18 -1
  50. package/dist/types/src/types/types.d.ts.map +1 -1
  51. package/dist/types/src/util.d.ts +1 -4
  52. package/dist/types/src/util.d.ts.map +1 -1
  53. package/package.json +41 -34
  54. package/src/SpacePlugin.tsx +44 -24
  55. package/src/components/MenuFooter.tsx +1 -0
  56. package/src/components/SaveStatus.tsx +95 -0
  57. package/src/components/SpaceMain/SpaceMain.tsx +1 -22
  58. package/src/components/SpacePresence.stories.tsx +49 -54
  59. package/src/components/SpaceSettings.tsx +32 -3
  60. package/src/components/SyncStatus/SyncStatus.stories.tsx +62 -0
  61. package/src/components/SyncStatus/SyncStatus.tsx +188 -0
  62. package/src/components/SyncStatus/index.ts +5 -0
  63. package/src/components/SyncStatus/types.ts +77 -0
  64. package/src/components/index.ts +2 -0
  65. package/src/translations.ts +2 -0
  66. package/src/types/thread.ts +9 -0
  67. package/src/types/types.ts +25 -1
  68. package/src/util.tsx +15 -50
  69. package/dist/lib/browser/chunk-DTVUOG2C.mjs.map +0 -7
  70. package/dist/lib/node/chunk-CVZPI2P3.cjs.map +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-space",
3
- "version": "0.6.11-staging.e6894a4",
3
+ "version": "0.6.12-main.15a606f",
4
4
  "description": "DXOS Surface plugin for DXOS ECHO Spaces",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -10,21 +10,24 @@
10
10
  ".": {
11
11
  "browser": "./dist/lib/browser/index.mjs",
12
12
  "node": {
13
- "default": "./dist/lib/node/index.cjs"
13
+ "require": "./dist/lib/node/index.cjs",
14
+ "default": "./dist/lib/node-esm/index.mjs"
14
15
  },
15
16
  "types": "./dist/types/src/index.d.ts"
16
17
  },
17
18
  "./meta": {
18
19
  "browser": "./dist/lib/browser/meta.mjs",
19
20
  "node": {
20
- "default": "./dist/lib/node/meta.cjs"
21
+ "require": "./dist/lib/node/meta.cjs",
22
+ "default": "./dist/lib/node-esm/meta.mjs"
21
23
  },
22
24
  "types": "./dist/types/src/meta.d.ts"
23
25
  },
24
26
  "./types": {
25
27
  "browser": "./dist/lib/browser/types/index.mjs",
26
28
  "node": {
27
- "default": "./dist/lib/node/types/index.cjs"
29
+ "require": "./dist/lib/node/types/index.cjs",
30
+ "default": "./dist/lib/node-esm/types/index.mjs"
28
31
  },
29
32
  "types": "./dist/types/src/types/index.d.ts"
30
33
  }
@@ -51,28 +54,32 @@
51
54
  "lodash.get": "^4.4.2",
52
55
  "react-drag-drop-files": "^2.3.8",
53
56
  "react-is": "~18.2.0",
54
- "@dxos/app-framework": "0.6.11-staging.e6894a4",
55
- "@dxos/async": "0.6.11-staging.e6894a4",
56
- "@dxos/client": "0.6.11-staging.e6894a4",
57
- "@dxos/automerge": "0.6.11-staging.e6894a4",
58
- "@dxos/display-name": "0.6.11-staging.e6894a4",
59
- "@dxos/echo-schema": "0.6.11-staging.e6894a4",
60
- "@dxos/invariant": "0.6.11-staging.e6894a4",
61
- "@dxos/keys": "0.6.11-staging.e6894a4",
62
- "@dxos/local-storage": "0.6.11-staging.e6894a4",
63
- "@dxos/log": "0.6.11-staging.e6894a4",
64
- "@dxos/migrations": "0.6.11-staging.e6894a4",
65
- "@dxos/plugin-attention": "0.6.11-staging.e6894a4",
66
- "@dxos/plugin-client": "0.6.11-staging.e6894a4",
67
- "@dxos/plugin-graph": "0.6.11-staging.e6894a4",
68
- "@dxos/plugin-metadata": "0.6.11-staging.e6894a4",
69
- "@dxos/plugin-observability": "0.6.11-staging.e6894a4",
70
- "@dxos/react-client": "0.6.11-staging.e6894a4",
71
- "@dxos/react-ui-attention": "0.6.11-staging.e6894a4",
72
- "@dxos/react-ui-editor": "0.6.11-staging.e6894a4",
73
- "@dxos/shell": "0.6.11-staging.e6894a4",
74
- "@dxos/util": "0.6.11-staging.e6894a4",
75
- "@dxos/plugin-settings": "0.6.11-staging.e6894a4"
57
+ "@dxos/app-framework": "0.6.12-main.15a606f",
58
+ "@dxos/async": "0.6.12-main.15a606f",
59
+ "@dxos/automerge": "0.6.12-main.15a606f",
60
+ "@dxos/context": "0.6.12-main.15a606f",
61
+ "@dxos/client": "0.6.12-main.15a606f",
62
+ "@dxos/display-name": "0.6.12-main.15a606f",
63
+ "@dxos/keys": "0.6.12-main.15a606f",
64
+ "@dxos/echo-schema": "0.6.12-main.15a606f",
65
+ "@dxos/local-storage": "0.6.12-main.15a606f",
66
+ "@dxos/invariant": "0.6.12-main.15a606f",
67
+ "@dxos/log": "0.6.12-main.15a606f",
68
+ "@dxos/migrations": "0.6.12-main.15a606f",
69
+ "@dxos/plugin-attention": "0.6.12-main.15a606f",
70
+ "@dxos/plugin-client": "0.6.12-main.15a606f",
71
+ "@dxos/plugin-observability": "0.6.12-main.15a606f",
72
+ "@dxos/plugin-graph": "0.6.12-main.15a606f",
73
+ "@dxos/plugin-settings": "0.6.12-main.15a606f",
74
+ "@dxos/plugin-metadata": "0.6.12-main.15a606f",
75
+ "@dxos/plugin-status-bar": "0.6.12-main.15a606f",
76
+ "@dxos/react-client": "0.6.12-main.15a606f",
77
+ "@dxos/react-ui-attention": "0.6.12-main.15a606f",
78
+ "@dxos/protocols": "0.6.12-main.15a606f",
79
+ "@dxos/react-ui-syntax-highlighter": "0.6.12-main.15a606f",
80
+ "@dxos/react-ui-editor": "0.6.12-main.15a606f",
81
+ "@dxos/shell": "0.6.12-main.15a606f",
82
+ "@dxos/util": "0.6.12-main.15a606f"
76
83
  },
77
84
  "devDependencies": {
78
85
  "@babel/core": "^7.18.13",
@@ -82,18 +89,18 @@
82
89
  "@types/react-dom": "~18.2.0",
83
90
  "react": "~18.2.0",
84
91
  "react-dom": "~18.2.0",
85
- "vite": "^5.3.4",
86
- "@dxos/react-ui": "0.6.11-staging.e6894a4",
87
- "@dxos/react-ui-theme": "0.6.11-staging.e6894a4",
88
- "@dxos/storybook-utils": "0.6.11-staging.e6894a4"
92
+ "vite": "5.4.7",
93
+ "@dxos/react-ui": "0.6.12-main.15a606f",
94
+ "@dxos/react-ui-theme": "0.6.12-main.15a606f",
95
+ "@dxos/storybook-utils": "0.6.12-main.15a606f"
89
96
  },
90
97
  "optionalDependencies": {
91
98
  "@babel/core": "^7.18.13",
92
99
  "@phosphor-icons/react": "^2.1.5",
93
- "react": "^18.0.0",
94
- "react-dom": "^18.0.0",
95
- "@dxos/react-ui": "0.6.11-staging.e6894a4",
96
- "@dxos/react-ui-theme": "0.6.11-staging.e6894a4"
100
+ "react": "~18.2.0",
101
+ "react-dom": "~18.2.0",
102
+ "@dxos/react-ui-theme": "0.6.12-main.15a606f",
103
+ "@dxos/react-ui": "0.6.12-main.15a606f"
97
104
  },
98
105
  "publishConfig": {
99
106
  "access": "public"
@@ -2,7 +2,6 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { type IconProps, Plus, SignIn, CardsThree, Warning } from '@phosphor-icons/react';
6
5
  import { effect, signal } from '@preact/signals-core';
7
6
  import React from 'react';
8
7
 
@@ -10,45 +9,45 @@ import {
10
9
  type IntentDispatcher,
11
10
  type IntentPluginProvides,
12
11
  LayoutAction,
13
- Surface,
14
12
  type LocationProvides,
15
13
  NavigationAction,
16
14
  type Plugin,
17
15
  type PluginDefinition,
18
- openIds,
16
+ Surface,
19
17
  firstIdInPart,
18
+ openIds,
19
+ parseGraphPlugin,
20
20
  parseIntentPlugin,
21
- parseNavigationPlugin,
22
21
  parseMetadataResolverPlugin,
22
+ parseNavigationPlugin,
23
23
  resolvePlugin,
24
- parseGraphPlugin,
25
24
  } from '@dxos/app-framework';
26
25
  import { EventSubscriptions, type Trigger, type UnsubscribeCallback } from '@dxos/async';
27
- import { type Identifiable, isReactiveObject, type EchoReactiveObject } from '@dxos/echo-schema';
26
+ import { type EchoReactiveObject, type Identifiable, isReactiveObject } from '@dxos/echo-schema';
28
27
  import { LocalStorageStore } from '@dxos/local-storage';
29
28
  import { log } from '@dxos/log';
30
29
  import { Migrations } from '@dxos/migrations';
31
30
  import { type AttentionPluginProvides, parseAttentionPlugin } from '@dxos/plugin-attention';
32
31
  import { type ClientPluginProvides, parseClientPlugin } from '@dxos/plugin-client';
33
- import { createExtension, isGraphNode, memoize, type Node, toSignal } from '@dxos/plugin-graph';
32
+ import { type Node, createExtension, isGraphNode, memoize, toSignal } from '@dxos/plugin-graph';
34
33
  import { ObservabilityAction } from '@dxos/plugin-observability/meta';
35
34
  import { type Client, PublicKey } from '@dxos/react-client';
36
35
  import {
36
+ Expando,
37
+ Filter,
37
38
  type PropertiesTypeProps,
38
39
  type Space,
40
+ SpaceState,
39
41
  create,
40
- Expando,
41
- Filter,
42
42
  fullyQualifiedId,
43
43
  getSpace,
44
44
  getTypename,
45
45
  isEchoObject,
46
46
  isSpace,
47
47
  loadObjectReferences,
48
- SpaceState,
49
48
  } from '@dxos/react-client/echo';
50
49
  import { Dialog } from '@dxos/react-ui';
51
- import { InvitationManager, type InvitationManagerProps, osTranslations, ClipboardProvider } from '@dxos/shell/react';
50
+ import { ClipboardProvider, InvitationManager, type InvitationManagerProps, osTranslations } from '@dxos/shell/react';
52
51
  import { ComplexMap, nonNullable, reduceGroupBy } from '@dxos/util';
53
52
 
54
53
  import {
@@ -61,15 +60,17 @@ import {
61
60
  MissingObject,
62
61
  PopoverRenameObject,
63
62
  PopoverRenameSpace,
63
+ SaveStatus,
64
64
  ShareSpaceButton,
65
65
  SmallPresence,
66
66
  SmallPresenceLive,
67
67
  SpacePresence,
68
68
  SpaceSettings,
69
+ SyncStatus,
69
70
  } from './components';
70
71
  import meta, { SPACE_PLUGIN, SpaceAction } from './meta';
71
72
  import translations from './translations';
72
- import { CollectionType, type SpacePluginProvides, type SpaceSettingsProps, type PluginState } from './types';
73
+ import { CollectionType, type PluginState, type SpacePluginProvides, type SpaceSettingsProps } from './types';
73
74
  import {
74
75
  COMPOSER_SPACE_LOCK,
75
76
  SHARED,
@@ -118,7 +119,9 @@ export const SpacePlugin = ({
118
119
  firstRun,
119
120
  onFirstRun,
120
121
  }: SpacePluginOptions = {}): PluginDefinition<SpacePluginProvides> => {
121
- const settings = new LocalStorageStore<SpaceSettingsProps>(SPACE_PLUGIN);
122
+ const settings = new LocalStorageStore<SpaceSettingsProps>(SPACE_PLUGIN, {
123
+ onSpaceCreate: 'dxos.org/plugin/markdown/action/create',
124
+ });
122
125
  const state = new LocalStorageStore<PluginState>(SPACE_PLUGIN, {
123
126
  awaiting: undefined,
124
127
  spaceNames: {},
@@ -340,8 +343,7 @@ export const SpacePlugin = ({
340
343
  records: {
341
344
  [CollectionType.typename]: {
342
345
  placeholder: ['unnamed collection label', { ns: SPACE_PLUGIN }],
343
- icon: (props: IconProps) => <CardsThree {...props} />,
344
- iconSymbol: 'ph--cards-three--regular',
346
+ icon: 'ph--cards-three--regular',
345
347
  // TODO(wittjosiah): Move out of metadata.
346
348
  loadReferences: (collection: CollectionType) =>
347
349
  loadObjectReferences(collection, (collection) => [
@@ -441,6 +443,14 @@ export const SpacePlugin = ({
441
443
  } else {
442
444
  return <MenuFooter object={data.object} />;
443
445
  }
446
+ case 'status': {
447
+ return (
448
+ <>
449
+ <SyncStatus />
450
+ <SaveStatus />
451
+ </>
452
+ );
453
+ }
444
454
  default:
445
455
  return null;
446
456
  }
@@ -540,8 +550,7 @@ export const SpacePlugin = ({
540
550
  },
541
551
  properties: {
542
552
  label: ['create space label', { ns: SPACE_PLUGIN }],
543
- icon: (props: IconProps) => <Plus {...props} />,
544
- iconSymbol: 'ph--plus--regular',
553
+ icon: 'ph--plus--regular',
545
554
  disposition: 'toolbar',
546
555
  testId: 'spacePlugin.createSpace',
547
556
  },
@@ -561,8 +570,7 @@ export const SpacePlugin = ({
561
570
  },
562
571
  properties: {
563
572
  label: ['join space label', { ns: SPACE_PLUGIN }],
564
- icon: (props: IconProps) => <SignIn {...props} />,
565
- iconSymbol: 'ph--sign-in--regular',
573
+ icon: 'ph--sign-in--regular',
566
574
  testId: 'spacePlugin.joinSpace',
567
575
  },
568
576
  },
@@ -573,7 +581,12 @@ export const SpacePlugin = ({
573
581
  () => client.spaces.get(),
574
582
  );
575
583
 
576
- if (!spaces) {
584
+ const isReady = toSignal(
585
+ (onChange) => client.spaces.isReady.subscribe(() => onChange()).unsubscribe,
586
+ () => client.spaces.isReady.get(),
587
+ );
588
+
589
+ if (!spaces || !isReady) {
577
590
  return;
578
591
  }
579
592
 
@@ -800,6 +813,15 @@ export const SpacePlugin = ({
800
813
  data: { space, id: space.id, activeParts: { main: [space.id] } },
801
814
 
802
815
  intents: [
816
+ ...(settings.values.onSpaceCreate
817
+ ? [
818
+ [
819
+ { action: settings.values.onSpaceCreate, data: { space } },
820
+ { action: SpaceAction.ADD_OBJECT, data: { target: space } },
821
+ { action: NavigationAction.EXPOSE },
822
+ ],
823
+ ]
824
+ : []),
803
825
  [
804
826
  {
805
827
  action: ObservabilityAction.SEND_EVENT,
@@ -1015,8 +1037,7 @@ export const SpacePlugin = ({
1015
1037
  title: translations[0]['en-US'][SPACE_PLUGIN]['space limit label'],
1016
1038
  description: translations[0]['en-US'][SPACE_PLUGIN]['space limit description'],
1017
1039
  duration: 5_000,
1018
- icon: (props: IconProps) => <Warning {...props} />,
1019
- iconSymbol: 'ph--warning--regular',
1040
+ icon: 'ph--warning--regular',
1020
1041
  actionLabel: translations[0]['en-US'][SPACE_PLUGIN]['remove deleted objects label'],
1021
1042
  actionAlt: translations[0]['en-US'][SPACE_PLUGIN]['remove deleted objects alt'],
1022
1043
  // TODO(wittjosiah): Use OS namespace.
@@ -1055,7 +1076,7 @@ export const SpacePlugin = ({
1055
1076
  }
1056
1077
 
1057
1078
  return {
1058
- data: { id: object.id, object, activeParts: { main: [fullyQualifiedId(object)] } },
1079
+ data: { id: fullyQualifiedId(object), object, activeParts: { main: [fullyQualifiedId(object)] } },
1059
1080
  intents: [
1060
1081
  [
1061
1082
  {
@@ -1110,7 +1131,6 @@ export const SpacePlugin = ({
1110
1131
  activeParts: {
1111
1132
  main: deletionData.wasActive,
1112
1133
  sidebar: deletionData.wasActive,
1113
- complementary: deletionData.wasActive,
1114
1134
  },
1115
1135
  },
1116
1136
  });
@@ -1,6 +1,7 @@
1
1
  //
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
+
4
5
  import { Planet } from '@phosphor-icons/react';
5
6
  import React from 'react';
6
7
 
@@ -0,0 +1,95 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { useEffect, useState } from 'react';
6
+
7
+ import { type UnsubscribeCallback } from '@dxos/async';
8
+ import { type Client } from '@dxos/client';
9
+ import { type Space, type SpaceId } from '@dxos/client/echo';
10
+ import { Context } from '@dxos/context';
11
+ import { StatusBar } from '@dxos/plugin-status-bar';
12
+ import { useClient } from '@dxos/react-client';
13
+ import { Icon, useTranslation } from '@dxos/react-ui';
14
+
15
+ import { SPACE_PLUGIN } from '../meta';
16
+
17
+ export const SaveStatus = () => {
18
+ const { t } = useTranslation(SPACE_PLUGIN);
19
+ const client = useClient();
20
+ const [state, setState] = useState<'saved' | 'saving'>('saved');
21
+ useEffect(() => {
22
+ return createClientSaveTracker(client, (state) => {
23
+ setState(state);
24
+ });
25
+ }, []);
26
+
27
+ return (
28
+ <StatusBar.Item title={state === 'saving' ? t('saving label') : t('saved label')}>
29
+ <Icon icon={state === 'saving' ? 'ph--arrows-clockwise--regular' : 'ph--check-circle--regular'} size={4} />
30
+ </StatusBar.Item>
31
+ );
32
+ };
33
+
34
+ const createClientSaveTracker = (client: Client, cb: (state: 'saved' | 'saving') => void) => {
35
+ const unsubscribeCallbacks: Record<SpaceId, UnsubscribeCallback> = {};
36
+ const state: Record<SpaceId, 'saved' | 'saving'> = {};
37
+
38
+ const install = (spaces: Space[]) => {
39
+ for (const space of spaces) {
40
+ if (state[space.id]) {
41
+ continue;
42
+ }
43
+
44
+ state[space.id] = 'saved';
45
+ unsubscribeCallbacks[space.id] = createSpaceSaveTracker(space, (s) => {
46
+ state[space.id] = s;
47
+ cb(Object.values(state).some((s) => s === 'saving') ? 'saving' : 'saved');
48
+ });
49
+ }
50
+ };
51
+ client.spaces.subscribe((spaces) => {
52
+ install(spaces);
53
+ });
54
+ install(client.spaces.get());
55
+
56
+ return () => {
57
+ for (const unsubscribe of Object.values(unsubscribeCallbacks)) {
58
+ unsubscribe();
59
+ }
60
+ };
61
+ };
62
+
63
+ const createSpaceSaveTracker = (space: Space, cb: (state: 'saved' | 'saving') => void): UnsubscribeCallback => {
64
+ const ctx = new Context();
65
+
66
+ void space.waitUntilReady().then(() => {
67
+ if (ctx.disposed) {
68
+ return;
69
+ }
70
+
71
+ let hasUnsavedChanges = false;
72
+ let lastFlushPromise: Promise<void> | undefined;
73
+ space.crud.saveStateChanged.on(ctx, ({ unsavedDocuments }) => {
74
+ hasUnsavedChanges = unsavedDocuments.length > 0;
75
+ });
76
+ space.crud.saveStateChanged.debounce(500).on(ctx, () => {
77
+ if (hasUnsavedChanges) {
78
+ lastFlushPromise = undefined;
79
+ cb('saving');
80
+ } else {
81
+ const flushPromise = space.crud.flush();
82
+ lastFlushPromise = flushPromise;
83
+ void flushPromise.then(() => {
84
+ if (lastFlushPromise === flushPromise) {
85
+ cb('saved');
86
+ }
87
+ });
88
+ }
89
+ });
90
+ });
91
+
92
+ return () => {
93
+ void ctx.dispose();
94
+ };
95
+ };
@@ -6,35 +6,14 @@ import { Command } from '@phosphor-icons/react';
6
6
  import React from 'react';
7
7
 
8
8
  import { Surface } from '@dxos/app-framework';
9
- import { type Action } from '@dxos/plugin-graph';
10
9
  import { SpaceState, type Space } from '@dxos/react-client/echo';
11
- import { Button, Main, useTranslation, toLocalizedString } from '@dxos/react-ui';
10
+ import { Main, useTranslation } from '@dxos/react-ui';
12
11
  import { getSize, mx, topbarBlockPaddingStart } from '@dxos/react-ui-theme';
13
12
  import { ClipboardProvider } from '@dxos/shell/react';
14
13
 
15
14
  import { SpaceMembersSection } from './SpaceMembersSection';
16
15
  import { SPACE_PLUGIN } from '../../meta';
17
16
 
18
- const _InFlowSpaceActions = ({ actionsMap }: { actionsMap: Record<string, Action> }) => {
19
- const { t } = useTranslation(SPACE_PLUGIN);
20
- return (
21
- <section className='mbe-4 col-start-2 col-end-4 md:col-end-7 grid gap-2 auto-rows-min grid-cols-[repeat(auto-fill,minmax(8rem,1fr))]'>
22
- {Object.entries(actionsMap)
23
- .filter(([_, { properties }]) => properties?.mainAreaDisposition === 'in-flow')
24
- .map(([actionId, { data: invoke, properties }]) => {
25
- const Icon = properties?.icon;
26
- const label = properties?.label;
27
- return (
28
- <Button key={actionId} classNames='block text-center plb-2 font-normal'>
29
- {Icon && <Icon size={5} className='mli-auto' />}
30
- <p>{toLocalizedString(label, t)}</p>
31
- </Button>
32
- );
33
- })}
34
- </section>
35
- );
36
- };
37
-
38
17
  const KeyShortcuts = () => {
39
18
  const { t } = useTranslation(SPACE_PLUGIN);
40
19
  return (
@@ -8,15 +8,14 @@ import '@dxos-theme';
8
8
 
9
9
  import { PublicKey } from '@dxos/keys';
10
10
  import { HaloSpaceMember, SpaceMember } from '@dxos/react-client/echo';
11
- import { Tooltip } from '@dxos/react-ui';
12
- import { withTheme } from '@dxos/storybook-utils';
11
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
13
12
 
14
13
  import { FullPresence, type MemberPresenceProps, SmallPresence, type Member } from './SpacePresence';
15
14
  import translations from '../translations';
16
15
 
17
16
  export default {
18
17
  title: 'plugin-space/SpacePresence',
19
- decorators: [withTheme],
18
+ decorators: [withTheme, withLayout({ tooltips: true })],
20
19
  parameters: { translations },
21
20
  actions: { argTypesRegex: '^on.*' },
22
21
  };
@@ -36,37 +35,35 @@ export const Full = (props: MemberPresenceProps) => {
36
35
  };
37
36
 
38
37
  return (
39
- <Tooltip.Provider>
40
- <div className='p-4'>
41
- <div className='p-3'>
42
- <FullPresence members={nViewers(1)} {...p} />
43
- </div>
44
- <div className='p-3'>
45
- <FullPresence members={nViewers(2)} {...p} />
46
- </div>
47
- <div className='p-3'>
48
- <FullPresence members={nViewers(3)} {...p} />
49
- </div>
50
- <div className='p-3'>
51
- <FullPresence members={nViewers(3, false)} {...p} />
52
- </div>
53
- <div className='p-3'>
54
- <FullPresence members={nViewers(4)} {...p} />
55
- </div>
56
- <div className='p-3'>
57
- <FullPresence members={nViewers(5)} {...p} />
58
- </div>
59
- <div className='p-3'>
60
- <FullPresence members={nViewers(5, false)} {...p} />
61
- </div>
62
- <div className='p-3'>
63
- <FullPresence members={nViewers(10)} {...p} />
64
- </div>
65
- <div className='p-3'>
66
- <FullPresence members={nViewers(100)} {...p} />
67
- </div>
38
+ <div className='p-4'>
39
+ <div className='p-3'>
40
+ <FullPresence members={nViewers(1)} {...p} />
68
41
  </div>
69
- </Tooltip.Provider>
42
+ <div className='p-3'>
43
+ <FullPresence members={nViewers(2)} {...p} />
44
+ </div>
45
+ <div className='p-3'>
46
+ <FullPresence members={nViewers(3)} {...p} />
47
+ </div>
48
+ <div className='p-3'>
49
+ <FullPresence members={nViewers(3, false)} {...p} />
50
+ </div>
51
+ <div className='p-3'>
52
+ <FullPresence members={nViewers(4)} {...p} />
53
+ </div>
54
+ <div className='p-3'>
55
+ <FullPresence members={nViewers(5)} {...p} />
56
+ </div>
57
+ <div className='p-3'>
58
+ <FullPresence members={nViewers(5, false)} {...p} />
59
+ </div>
60
+ <div className='p-3'>
61
+ <FullPresence members={nViewers(10)} {...p} />
62
+ </div>
63
+ <div className='p-3'>
64
+ <FullPresence members={nViewers(100)} {...p} />
65
+ </div>
66
+ </div>
70
67
  );
71
68
  };
72
69
 
@@ -76,27 +73,25 @@ export const Small = (props: MemberPresenceProps) => {
76
73
  };
77
74
 
78
75
  return (
79
- <Tooltip.Provider>
80
- <div className='p-4'>
81
- <div className='p-3'>
82
- <SmallPresence count={0} {...p} />
83
- </div>
84
- <div className='p-3'>
85
- <SmallPresence count={1} {...p} />
86
- </div>
87
- <div className='p-3'>
88
- <SmallPresence count={2} {...p} />
89
- </div>
90
- <div className='p-3'>
91
- <SmallPresence count={3} {...p} />
92
- </div>
93
- <div className='p-3'>
94
- <SmallPresence count={4} {...p} />
95
- </div>
96
- <div className='p-3'>
97
- <SmallPresence count={5} {...p} />
98
- </div>
76
+ <div className='p-4'>
77
+ <div className='p-3'>
78
+ <SmallPresence count={0} {...p} />
79
+ </div>
80
+ <div className='p-3'>
81
+ <SmallPresence count={1} {...p} />
82
+ </div>
83
+ <div className='p-3'>
84
+ <SmallPresence count={2} {...p} />
85
+ </div>
86
+ <div className='p-3'>
87
+ <SmallPresence count={3} {...p} />
88
+ </div>
89
+ <div className='p-3'>
90
+ <SmallPresence count={4} {...p} />
91
+ </div>
92
+ <div className='p-3'>
93
+ <SmallPresence count={5} {...p} />
99
94
  </div>
100
- </Tooltip.Provider>
95
+ </div>
101
96
  );
102
97
  };
@@ -4,16 +4,17 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { useIntentDispatcher } from '@dxos/app-framework';
7
+ import { useIntentDispatcher, useResolvePlugins } from '@dxos/app-framework';
8
8
  import { SettingsValue } from '@dxos/plugin-settings';
9
- import { Input, useTranslation } from '@dxos/react-ui';
9
+ import { Input, Select, toLocalizedString, useTranslation } from '@dxos/react-ui';
10
10
 
11
11
  import { SpaceAction, SPACE_PLUGIN } from '../meta';
12
- import { type SpaceSettingsProps } from '../types';
12
+ import { parseSpaceInitPlugin, type SpaceSettingsProps } from '../types';
13
13
 
14
14
  export const SpaceSettings = ({ settings }: { settings: SpaceSettingsProps }) => {
15
15
  const { t } = useTranslation(SPACE_PLUGIN);
16
16
  const dispatch = useIntentDispatcher();
17
+ const plugins = useResolvePlugins(parseSpaceInitPlugin);
17
18
 
18
19
  return (
19
20
  <>
@@ -29,6 +30,34 @@ export const SpaceSettings = ({ settings }: { settings: SpaceSettingsProps }) =>
29
30
  }
30
31
  />
31
32
  </SettingsValue>
33
+
34
+ <SettingsValue label={t('default on space create label')}>
35
+ <Select.Root
36
+ value={settings.onSpaceCreate}
37
+ onValueChange={(value) => {
38
+ settings.onSpaceCreate = value;
39
+ }}
40
+ >
41
+ <Select.TriggerButton />
42
+ <Select.Portal>
43
+ <Select.Content>
44
+ <Select.Viewport>
45
+ {plugins.map(
46
+ ({
47
+ provides: {
48
+ space: { onSpaceCreate },
49
+ },
50
+ }) => (
51
+ <Select.Option key={onSpaceCreate.action} value={onSpaceCreate.action}>
52
+ {toLocalizedString(onSpaceCreate.label, t)}
53
+ </Select.Option>
54
+ ),
55
+ )}
56
+ </Select.Viewport>
57
+ </Select.Content>
58
+ </Select.Portal>
59
+ </Select.Root>
60
+ </SettingsValue>
32
61
  </>
33
62
  );
34
63
  };