@dxos/react-ui 0.1.35 → 0.1.36-next.ef27157

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 (50) hide show
  1. package/dist/lib/browser/chunk-5VRACIDE.mjs +10 -0
  2. package/dist/lib/browser/chunk-5VRACIDE.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +225 -174
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +43 -0
  7. package/dist/lib/browser/testing/index.mjs.map +7 -0
  8. package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts.map +1 -1
  9. package/dist/types/src/components/InvitationList/InvitationListItem.d.ts.map +1 -1
  10. package/dist/types/src/composites/JoinDialog/JoinDialog.stories.d.ts.map +1 -1
  11. package/dist/types/src/composites/Shell/ShellContext.d.ts.map +1 -1
  12. package/dist/types/src/panels/DevicesPanel/DevicesPanel.d.ts.map +1 -1
  13. package/dist/types/src/panels/JoinPanel/joinMachine.d.ts +5 -5
  14. package/dist/types/src/panels/JoinPanel/joinMachine.d.ts.map +1 -1
  15. package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts +1 -1
  16. package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts.map +1 -1
  17. package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts +2 -2
  18. package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts.map +1 -1
  19. package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts +2 -2
  20. package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts.map +1 -1
  21. package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts +2 -2
  22. package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts.map +1 -1
  23. package/dist/types/src/panels/SpacePanel/SpacePanel.d.ts.map +1 -1
  24. package/dist/types/src/playwright/invitations-manager.d.ts +8 -17
  25. package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
  26. package/dist/types/src/testing/index.d.ts +2 -0
  27. package/dist/types/src/testing/index.d.ts.map +1 -0
  28. package/dist/types/src/testing/shell-manager.d.ts +16 -0
  29. package/dist/types/src/testing/shell-manager.d.ts.map +1 -0
  30. package/dist/types/src/util/invitationStatusValue.d.ts.map +1 -1
  31. package/package.json +25 -14
  32. package/src/components/InvitationList/InvitationList.tsx +2 -2
  33. package/src/components/InvitationList/InvitationListContainer.tsx +3 -2
  34. package/src/components/InvitationList/InvitationListItem.tsx +4 -8
  35. package/src/composites/JoinDialog/JoinDialog.stories.tsx +3 -12
  36. package/src/composites/Shell/Shell.tsx +1 -1
  37. package/src/composites/Shell/ShellContext.tsx +11 -8
  38. package/src/panels/DevicesPanel/DevicesPanel.tsx +3 -1
  39. package/src/panels/JoinPanel/JoinPanel.tsx +8 -8
  40. package/src/panels/JoinPanel/joinMachine.ts +108 -98
  41. package/src/panels/JoinPanel/view-states/InvitationAccepted.tsx +6 -6
  42. package/src/panels/JoinPanel/view-states/InvitationAuthenticator.tsx +14 -14
  43. package/src/panels/JoinPanel/view-states/InvitationInput.tsx +9 -9
  44. package/src/panels/JoinPanel/view-states/InvitationRescuer.tsx +10 -10
  45. package/src/panels/SpacePanel/SpacePanel.tsx +19 -4
  46. package/src/playwright/invitations-manager.ts +23 -78
  47. package/src/playwright/invitations.spec.ts +79 -117
  48. package/src/testing/index.ts +5 -0
  49. package/src/testing/shell-manager.ts +59 -0
  50. package/src/util/invitationStatusValue.ts +3 -2
@@ -15,7 +15,7 @@ import { JoinPanelMode } from './JoinPanelProps';
15
15
 
16
16
  type FailReason = 'error' | 'timeout' | 'cancelled' | 'badVerificationCode';
17
17
 
18
- type InvitationDomainContext = Partial<{
18
+ type InvitationKindContext = Partial<{
19
19
  failReason: FailReason | null;
20
20
  unredeemedCode: string;
21
21
  invitationObservable: AuthenticatingInvitationObservable;
@@ -26,8 +26,8 @@ type InvitationDomainContext = Partial<{
26
26
  type JoinMachineContext = {
27
27
  mode: JoinPanelMode;
28
28
  identity: Identity | null;
29
- halo: InvitationDomainContext;
30
- space: InvitationDomainContext;
29
+ halo: InvitationKindContext;
30
+ space: InvitationKindContext;
31
31
  };
32
32
 
33
33
  type SelectIdentityEvent = {
@@ -42,12 +42,16 @@ type SetInvitationCodeEvent = {
42
42
 
43
43
  type SetInvitationEvent = {
44
44
  type:
45
- | 'authenticateHaloInvitation'
46
- | 'authenticateSpaceInvitation'
47
- | 'connectHaloInvitation'
48
- | 'connectSpaceInvitation'
49
- | 'connectionSuccessHaloInvitation'
50
- | 'connectionSuccessSpaceInvitation';
45
+ | 'authenticatingHaloInvitation'
46
+ | 'authenticatingSpaceInvitation'
47
+ | 'readyForAuthenticationHaloInvitation'
48
+ | 'readyForAuthenticationSpaceInvitation'
49
+ | 'connectingHaloInvitation'
50
+ | 'connectingSpaceInvitation'
51
+ | 'connectedHaloInvitation'
52
+ | 'connectedSpaceInvitation'
53
+ | 'successHaloInvitation'
54
+ | 'successSpaceInvitation';
51
55
  invitation: Invitation;
52
56
  };
53
57
 
@@ -61,15 +65,13 @@ type EmptyInvitationEvent = {
61
65
  | 'authenticateHaloVerificationCode'
62
66
  | 'authenticateSpaceVerificationCode'
63
67
  | 'resetHaloInvitation'
64
- | 'resetSpaceInvitation'
65
- | 'succeedHaloInvitation'
66
- | 'succeedSpaceInvitation';
68
+ | 'resetSpaceInvitation';
67
69
  };
68
70
 
69
71
  type InvitationEvent = FailInvitationEvent | SetInvitationCodeEvent | SetInvitationEvent | EmptyInvitationEvent;
70
72
 
71
73
  const getInvitationSubscribable = (
72
- Domain: 'Space' | 'Halo',
74
+ Kind: 'Space' | 'Halo',
73
75
  invitation: AuthenticatingInvitationObservable
74
76
  ): Subscribable<InvitationEvent> => {
75
77
  log('[subscribing to invitation]', invitation);
@@ -78,135 +80,146 @@ const getInvitationSubscribable = (
78
80
  next: (value: InvitationEvent) => void,
79
81
  onError?: (error: any) => void,
80
82
  complete?: () => void
81
- ): Subscription => {
82
- const unsubscribe = invitation.subscribe({
83
- onAuthenticating: (invitation: Invitation) => {
84
- log('[invitation authenticating]', { Domain, invitation });
85
- return next({ type: `authenticate${Domain}Invitation`, invitation });
86
- },
87
- onCancelled: () => {
88
- log.warn('[invitation cancelled]', { Domain });
89
- return next({ type: `fail${Domain}Invitation`, reason: 'cancelled' } as FailInvitationEvent);
90
- },
91
- onTimeout: () => {
92
- log.error('[invitation timeout]', { Domain });
93
- return next({ type: `fail${Domain}Invitation`, reason: 'timeout' } as FailInvitationEvent);
94
- },
95
- onConnecting: (invitation: Invitation) => {
96
- log('[invitation connecting]', { Domain, invitation });
97
- return next({ type: `connect${Domain}Invitation`, invitation });
98
- },
99
- onConnected: (invitation: Invitation) => {
100
- log('[invitation connected]', { Domain, invitation });
101
- return next({ type: `connectionSuccess${Domain}Invitation`, invitation });
102
- },
103
- onSuccess: () => {
104
- log('[invitation success]', { Domain });
105
- next({ type: `succeed${Domain}Invitation` });
106
- return complete?.();
83
+ ): Subscription =>
84
+ invitation.subscribe(
85
+ (invitation: Invitation) => {
86
+ switch (invitation.state) {
87
+ case Invitation.State.CONNECTING: {
88
+ log('[invitation connecting]', { Kind, invitation });
89
+ return next({ type: `connecting${Kind}Invitation`, invitation });
90
+ }
91
+
92
+ case Invitation.State.CONNECTED: {
93
+ log('[invitation connected]', { Kind, invitation });
94
+ return next({ type: `connected${Kind}Invitation`, invitation });
95
+ }
96
+
97
+ case Invitation.State.READY_FOR_AUTHENTICATION: {
98
+ log('[invitation ready for authentication]', { Kind, invitation });
99
+ return next({ type: `readyForAuthentication${Kind}Invitation`, invitation });
100
+ }
101
+
102
+ case Invitation.State.AUTHENTICATING: {
103
+ log('[invitation authenticating]', { Kind, invitation });
104
+ return next({ type: `authenticating${Kind}Invitation`, invitation });
105
+ }
106
+
107
+ case Invitation.State.SUCCESS: {
108
+ log('[invitation success]', { Kind, invitation });
109
+ next({ type: `success${Kind}Invitation`, invitation });
110
+ return complete?.();
111
+ }
112
+
113
+ case Invitation.State.CANCELLED: {
114
+ log.warn('[invitation cancelled]', { Kind });
115
+ return next({ type: `fail${Kind}Invitation`, reason: 'cancelled' } as FailInvitationEvent);
116
+ }
117
+
118
+ case Invitation.State.TIMEOUT: {
119
+ log.error('[invitation timeout]', { Kind });
120
+ return next({ type: `fail${Kind}Invitation`, reason: 'timeout' } as FailInvitationEvent);
121
+ }
122
+ }
107
123
  },
108
- onError: (error: any) => {
109
- log.error('[invitation errored]', { Domain, error });
110
- next({ type: `fail${Domain}Invitation`, reason: 'error' });
124
+ (error: any) => {
125
+ log.error('[invitation errored]', { Kind, error });
126
+ next({ type: `fail${Kind}Invitation`, reason: 'error' });
111
127
  return onError?.(error);
112
128
  }
113
- });
114
- return { unsubscribe };
115
- }
129
+ )
116
130
  } as Subscribable<InvitationEvent>;
117
131
  };
118
132
 
119
- const acceptingInvitationTemplate = (Domain: 'Space' | 'Halo', successTarget: string) => {
133
+ const acceptingInvitationTemplate = (Kind: 'Space' | 'Halo', successTarget: string) => {
120
134
  const config: StateNodeConfig<JoinMachineContext, any, InvitationEvent> = {
121
- initial: `unknown${Domain}`,
135
+ initial: `unknown${Kind}`,
122
136
  states: {
123
- [`unknown${Domain}`]: {
137
+ [`unknown${Kind}`]: {
124
138
  always: [
125
139
  {
126
- cond: ({ mode }) => mode === 'halo-only' && Domain === 'Space',
140
+ cond: ({ mode }) => mode === 'halo-only' && Kind === 'Space',
127
141
  target: '#join.finishingJoiningHalo'
128
142
  },
129
143
  {
130
- // cond: `no${Domain}Invitation`,
131
- target: `inputting${Domain}InvitationCode`,
144
+ // cond: `no${Kind}Invitation`,
145
+ target: `inputting${Kind}InvitationCode`,
132
146
  actions: 'log'
133
147
  }
134
148
  // todo(thure): Restore this transition that redeems the invitation code on init.
135
149
  // {
136
- // target: `acceptingRedeemed${Domain}Invitation`,
137
- // actions: [`redeem${Domain}InvitationCode`, 'log']
150
+ // target: `acceptingRedeemed${Kind}Invitation`,
151
+ // actions: [`redeem${Kind}InvitationCode`, 'log']
138
152
  // }
139
153
  ]
140
154
  },
141
- [`inputting${Domain}InvitationCode`]: {},
142
- [`acceptingRedeemed${Domain}Invitation`]: {
155
+ [`inputting${Kind}InvitationCode`]: {},
156
+ [`acceptingRedeemed${Kind}Invitation`]: {
143
157
  invoke: {
144
- src: (context) => context[Domain.toLowerCase() as 'space' | 'halo'].invitationSubscribable!
158
+ src: (context) => context[Kind.toLowerCase() as 'space' | 'halo'].invitationSubscribable!
145
159
  },
146
- initial: `unknown${Domain}Invitation`,
160
+ initial: `unknown${Kind}Invitation`,
147
161
  states: {
148
- [`unknown${Domain}Invitation`]: {
162
+ [`unknown${Kind}Invitation`]: {
149
163
  always: [
150
164
  {
151
165
  cond: (context) => {
152
- const invitation = context[Domain.toLowerCase() as 'space' | 'halo'].invitation;
166
+ const invitation = context[Kind.toLowerCase() as 'space' | 'halo'].invitation;
153
167
  return !invitation || invitation?.state === Invitation.State.CONNECTING;
154
168
  },
155
- target: `connecting${Domain}Invitation`,
169
+ target: `connecting${Kind}Invitation`,
156
170
  actions: 'log'
157
171
  },
158
172
  {
159
- target: `inputting${Domain}VerificationCode`,
173
+ target: `inputting${Kind}VerificationCode`,
160
174
  actions: 'log'
161
175
  }
162
176
  ]
163
177
  },
164
- [`connecting${Domain}Invitation`]: {},
165
- [`inputting${Domain}VerificationCode`]: {
178
+ [`connecting${Kind}Invitation`]: {},
179
+ [`inputting${Kind}VerificationCode`]: {},
180
+ [`authenticating${Kind}VerificationCode`]: {
166
181
  on: {
167
- [`authenticate${Domain}VerificationCode`]: {
168
- target: `authenticating${Domain}VerificationCode`,
169
- actions: 'log'
182
+ [`readyForAuthentication${Kind}Invitation`]: {
183
+ target: `authenticationFailing${Kind}VerificationCode`,
184
+ actions: ['setInvitation', 'log']
170
185
  }
171
186
  }
172
187
  },
173
- [`authenticating${Domain}VerificationCode`]: {
174
- on: {
175
- [`authenticate${Domain}Invitation`]: {
176
- target: `authenticationFailing${Domain}VerificationCode`,
177
- actions: 'log'
178
- }
179
- }
180
- },
181
- [`authenticationFailing${Domain}VerificationCode`]: {},
182
- [`failing${Domain}Invitation`]: {},
183
- [`success${Domain}Invitation`]: {}
188
+ [`authenticationFailing${Kind}VerificationCode`]: {},
189
+ [`failing${Kind}Invitation`]: {},
190
+ [`success${Kind}Invitation`]: {}
184
191
  },
185
192
  on: {
186
- [`reset${Domain}Invitation`]: {
187
- target: `#join${
188
- Domain === 'Halo' ? '.choosingIdentity' : ''
189
- }.accepting${Domain}Invitation.unknown${Domain}`,
193
+ [`reset${Kind}Invitation`]: {
194
+ target: `#join${Kind === 'Halo' ? '.choosingIdentity' : ''}.accepting${Kind}Invitation.unknown${Kind}`,
190
195
  actions: ['resetInvitation', 'log']
191
196
  },
192
- [`connect${Domain}Invitation`]: {
193
- target: `.connecting${Domain}Invitation`,
197
+ [`connecting${Kind}Invitation`]: {
198
+ target: `.connecting${Kind}Invitation`,
199
+ actions: ['setInvitation', 'log']
200
+ },
201
+ [`connected${Kind}Invitation`]: {
202
+ target: `.connecting${Kind}Invitation`,
203
+ actions: ['setInvitation', 'log']
204
+ },
205
+ [`readyForAuthentication${Kind}Invitation`]: {
206
+ target: `.inputting${Kind}VerificationCode`,
194
207
  actions: ['setInvitation', 'log']
195
208
  },
196
- [`connectionSuccess${Domain}Invitation`]: {
197
- target: `.inputting${Domain}VerificationCode`,
209
+ [`authenticating${Kind}Invitation`]: {
210
+ target: `.authenticating${Kind}VerificationCode`,
198
211
  actions: ['setInvitation', 'log']
199
212
  },
200
- [`succeed${Domain}Invitation`]: { target: successTarget, actions: 'log' },
201
- [`fail${Domain}Invitation`]: {
202
- target: `.failing${Domain}Invitation`,
213
+ [`success${Kind}Invitation`]: { target: successTarget, actions: ['setInvitation', 'log'] },
214
+ [`fail${Kind}Invitation`]: {
215
+ target: `.failing${Kind}Invitation`,
203
216
  actions: [
204
217
  assign({
205
- [Domain.toLowerCase() as 'space' | 'halo']: (
218
+ [Kind.toLowerCase() as 'space' | 'halo']: (
206
219
  context: JoinMachineContext,
207
220
  event: FailInvitationEvent
208
221
  ) => ({
209
- ...context[Domain.toLowerCase() as 'space' | 'halo'],
222
+ ...context[Kind.toLowerCase() as 'space' | 'halo'],
210
223
  failReason: event.reason
211
224
  })
212
225
  }),
@@ -217,19 +230,16 @@ const acceptingInvitationTemplate = (Domain: 'Space' | 'Halo', successTarget: st
217
230
  }
218
231
  },
219
232
  on: {
220
- [`set${Domain}InvitationCode`]: {
221
- target: `.acceptingRedeemed${Domain}Invitation`,
233
+ [`set${Kind}InvitationCode`]: {
234
+ target: `.acceptingRedeemed${Kind}Invitation`,
222
235
  actions: [
223
236
  assign({
224
- [Domain.toLowerCase() as 'space' | 'halo']: (
225
- context: JoinMachineContext,
226
- event: SetInvitationCodeEvent
227
- ) => ({
228
- ...context[Domain.toLowerCase() as 'space' | 'halo'],
237
+ [Kind.toLowerCase() as 'space' | 'halo']: (context: JoinMachineContext, event: SetInvitationCodeEvent) => ({
238
+ ...context[Kind.toLowerCase() as 'space' | 'halo'],
229
239
  unredeemedCode: event.code
230
240
  })
231
241
  }),
232
- `redeem${Domain}InvitationCode`,
242
+ `redeem${Kind}InvitationCode`,
233
243
  'log'
234
244
  ]
235
245
  }
@@ -12,7 +12,7 @@ import { Button, getSize, mx, useTranslation } from '@dxos/react-components';
12
12
  import { ViewState, ViewStateProps } from './ViewState';
13
13
 
14
14
  export interface InvitationAcceptedProps extends ViewStateProps {
15
- Domain: 'Space' | 'Halo';
15
+ Kind: 'Space' | 'Halo';
16
16
  doneActionParent?: Parameters<typeof cloneElement>[0];
17
17
  onDone?: (result: InvitationResult | null) => void;
18
18
  }
@@ -20,7 +20,7 @@ export interface InvitationAcceptedProps extends ViewStateProps {
20
20
  const PureInvitationAcceptedContent = ({
21
21
  onDone,
22
22
  result,
23
- Domain,
23
+ Kind,
24
24
  doneActionParent,
25
25
  active
26
26
  }: InvitationAcceptedProps & { result: InvitationResult | null }) => {
@@ -32,8 +32,8 @@ const PureInvitationAcceptedContent = ({
32
32
  {...(onDone && { onClick: () => onDone(result) })}
33
33
  disabled={disabled}
34
34
  className='flex items-center gap-2 pli-2'
35
- data-autofocus={`success${Domain}Invitation finishingJoining${Domain}`}
36
- data-testid={`${Domain.toLowerCase()}-invitation-accepted-done`}
35
+ data-autofocus={`success${Kind}Invitation finishingJoining${Kind}`}
36
+ data-testid={`${Kind.toLowerCase()}-invitation-accepted-done`}
37
37
  >
38
38
  <CaretLeft weight='bold' className={mx(getSize(2), 'invisible')} />
39
39
  <span className='grow'>{t('done label')}</span>
@@ -58,9 +58,9 @@ const InvitationAcceptedContent = (
58
58
  };
59
59
 
60
60
  export const InvitationAccepted = (props: InvitationAcceptedProps) => {
61
- const { Domain, doneActionParent: _doneActionParent, onDone: _onDone, ...viewStateProps } = props;
61
+ const { Kind, doneActionParent: _doneActionParent, onDone: _onDone, ...viewStateProps } = props;
62
62
  const activeInvitation =
63
- viewStateProps.joinState?.context[Domain.toLowerCase() as 'halo' | 'space'].invitationObservable;
63
+ viewStateProps.joinState?.context[Kind.toLowerCase() as 'halo' | 'space'].invitationObservable;
64
64
 
65
65
  return (
66
66
  <ViewState {...viewStateProps}>
@@ -15,7 +15,7 @@ import { ViewState, ViewStateHeading, ViewStateProps } from './ViewState';
15
15
  const pinLength = 6;
16
16
 
17
17
  export interface InvitationAuthenticatorProps extends ViewStateProps {
18
- Domain: 'Space' | 'Halo';
18
+ Kind: 'Space' | 'Halo';
19
19
  failed?: boolean;
20
20
  }
21
21
 
@@ -24,20 +24,20 @@ const PureInvitationAuthenticatorContent = ({
24
24
  failed,
25
25
  joinSend,
26
26
  joinState,
27
- Domain,
27
+ Kind,
28
28
  onChange,
29
29
  onAuthenticate
30
30
  }: {
31
31
  disabled?: boolean;
32
32
  joinSend: JoinSend;
33
33
  joinState?: JoinState;
34
- Domain: InvitationAuthenticatorProps['Domain'];
34
+ Kind: InvitationAuthenticatorProps['Kind'];
35
35
  failed: InvitationAuthenticatorProps['failed'];
36
36
  onChange: ComponentProps<typeof Input>['onChange'];
37
37
  onAuthenticate: ComponentProps<typeof Button>['onClick'];
38
38
  }) => {
39
39
  const { t } = useTranslation('os');
40
- const invitationType = Domain.toLowerCase() as 'space' | 'halo';
40
+ const invitationType = Kind.toLowerCase() as 'space' | 'halo';
41
41
  return (
42
42
  <>
43
43
  <Input
@@ -54,7 +54,7 @@ const PureInvitationAuthenticatorContent = ({
54
54
  inputMode: 'numeric',
55
55
  autoComplete: 'off',
56
56
  pattern: '\\d*',
57
- 'data-autofocus': `connecting${Domain}Invitation inputting${Domain}VerificationCode authenticationFailing${Domain}VerificationCode authenticating${Domain}VerificationCode`,
57
+ 'data-autofocus': `connecting${Kind}Invitation inputting${Kind}VerificationCode authenticationFailing${Kind}VerificationCode authenticating${Kind}VerificationCode`,
58
58
  'data-prevent-ios-autofocus': true,
59
59
  'data-testid': `${invitationType}-auth-code-input`,
60
60
  'data-1p-ignore': true
@@ -97,21 +97,21 @@ const InvitationAuthenticatorContent = ({
97
97
  joinState,
98
98
  disabled,
99
99
  invitation,
100
- Domain,
100
+ Kind,
101
101
  failed
102
102
  }: {
103
103
  joinSend: JoinSend;
104
104
  joinState?: JoinState;
105
105
  disabled?: boolean;
106
106
  invitation: AuthenticatingInvitationObservable;
107
- Domain: InvitationAuthenticatorProps['Domain'];
107
+ Kind: InvitationAuthenticatorProps['Kind'];
108
108
  failed: InvitationAuthenticatorProps['failed'];
109
109
  }) => {
110
- const invitationType = Domain.toLowerCase();
110
+ const invitationType = Kind.toLowerCase();
111
111
  const [pinValue, setPinValue] = useState('');
112
112
  const { authenticate } = useInvitationStatus(invitation);
113
113
  const onAuthenticate = useCallback(() => {
114
- joinSend({ type: `authenticate${Domain}VerificationCode` });
114
+ joinSend({ type: `authenticate${Kind}VerificationCode` });
115
115
  void authenticate(pinValue);
116
116
  }, [joinSend, authenticate, pinValue]);
117
117
  const onChange = useCallback(
@@ -125,26 +125,26 @@ const InvitationAuthenticatorContent = ({
125
125
  );
126
126
  return (
127
127
  <PureInvitationAuthenticatorContent
128
- {...{ disabled, failed, joinSend, joinState, Domain, onChange, onAuthenticate }}
128
+ {...{ disabled, failed, joinSend, joinState, Kind, onChange, onAuthenticate }}
129
129
  />
130
130
  );
131
131
  };
132
132
 
133
- export const InvitationAuthenticator = ({ failed, Domain, ...viewStateProps }: InvitationAuthenticatorProps) => {
133
+ export const InvitationAuthenticator = ({ failed, Kind, ...viewStateProps }: InvitationAuthenticatorProps) => {
134
134
  const { joinSend, joinState } = viewStateProps;
135
135
  const disabled =
136
136
  !viewStateProps.active ||
137
137
  ['connecting', 'authenticating'].some((str) => joinState?.configuration[0].id.includes(str));
138
- const activeInvitation = joinState?.context[Domain.toLowerCase() as 'space' | 'halo'].invitationObservable;
138
+ const activeInvitation = joinState?.context[Kind.toLowerCase() as 'space' | 'halo'].invitationObservable;
139
139
  return (
140
140
  <ViewState {...viewStateProps}>
141
141
  {!activeInvitation ? (
142
142
  <PureInvitationAuthenticatorContent
143
- {...{ disabled, failed, joinSend, joinState, Domain, onChange: () => {}, onAuthenticate: () => {} }}
143
+ {...{ disabled, failed, joinSend, joinState, Kind, onChange: () => {}, onAuthenticate: () => {} }}
144
144
  />
145
145
  ) : (
146
146
  <InvitationAuthenticatorContent
147
- {...{ disabled, failed, invitation: activeInvitation, joinSend, joinState, Domain }}
147
+ {...{ disabled, failed, invitation: activeInvitation, joinSend, joinState, Kind }}
148
148
  />
149
149
  )}
150
150
  </ViewState>
@@ -10,15 +10,15 @@ import { Button, getSize, Input, mx, useTranslation } from '@dxos/react-componen
10
10
  import { ViewState, ViewStateHeading, ViewStateProps } from './ViewState';
11
11
 
12
12
  export interface InvitationInputProps extends ViewStateProps {
13
- Domain: 'Space' | 'Halo';
13
+ Kind: 'Space' | 'Halo';
14
14
  }
15
15
 
16
- export const InvitationInput = ({ Domain, ...viewStateProps }: InvitationInputProps) => {
16
+ export const InvitationInput = ({ Kind, ...viewStateProps }: InvitationInputProps) => {
17
17
  const disabled = !viewStateProps.active;
18
18
  const { joinSend, joinState } = viewStateProps;
19
19
  const { t } = useTranslation('os');
20
20
 
21
- const contextUnredeemedCode = joinState?.context[Domain.toLowerCase() as 'space' | 'halo'].unredeemedCode;
21
+ const contextUnredeemedCode = joinState?.context[Kind.toLowerCase() as 'space' | 'halo'].unredeemedCode;
22
22
 
23
23
  const [inputValue, setInputValue] = useState(contextUnredeemedCode ?? '');
24
24
 
@@ -28,7 +28,7 @@ export const InvitationInput = ({ Domain, ...viewStateProps }: InvitationInputPr
28
28
 
29
29
  const handleNext = () =>
30
30
  joinSend({
31
- type: `set${Domain}InvitationCode`,
31
+ type: `set${Kind}InvitationCode`,
32
32
  code: inputValue
33
33
  });
34
34
 
@@ -42,8 +42,8 @@ export const InvitationInput = ({ Domain, ...viewStateProps }: InvitationInputPr
42
42
  slots={{
43
43
  root: { className: 'm-0' },
44
44
  input: {
45
- 'data-autofocus': `inputting${Domain}InvitationCode`,
46
- 'data-testid': `${Domain.toLowerCase()}-invitation-input`,
45
+ 'data-autofocus': `inputting${Kind}InvitationCode`,
46
+ 'data-testid': `${Kind.toLowerCase()}-invitation-input`,
47
47
  onKeyUp: ({ key }) => key === 'Enter' && handleNext()
48
48
  } as ComponentPropsWithoutRef<'input'>
49
49
  }}
@@ -54,17 +54,17 @@ export const InvitationInput = ({ Domain, ...viewStateProps }: InvitationInputPr
54
54
  disabled={disabled}
55
55
  className='grow flex items-center gap-2 pli-2 order-2'
56
56
  onClick={handleNext}
57
- data-testid={`${Domain.toLowerCase()}-invitation-input-continue`}
57
+ data-testid={`${Kind.toLowerCase()}-invitation-input-continue`}
58
58
  >
59
59
  <CaretLeft weight='bold' className={mx(getSize(2), 'invisible')} />
60
60
  <span className='grow'>{t('continue label')}</span>
61
61
  <CaretRight weight='bold' className={getSize(4)} />
62
62
  </Button>
63
63
  <Button
64
- disabled={Domain === 'Space'}
64
+ disabled={disabled || Kind === 'Space'}
65
65
  onClick={() => joinSend({ type: 'deselectAuthMethod' })}
66
66
  className='flex items-center gap-2 pis-2 pie-4'
67
- data-testid={`${Domain.toLowerCase()}-invitation-input-back`}
67
+ data-testid={`${Kind.toLowerCase()}-invitation-input-back`}
68
68
  >
69
69
  <CaretLeft weight='bold' className={getSize(4)} />
70
70
  <span>{t('back label')}</span>
@@ -12,7 +12,7 @@ import { JoinSend, JoinState } from '../joinMachine';
12
12
  import { ViewState, ViewStateHeading, ViewStateProps } from './ViewState';
13
13
 
14
14
  export interface InvitationConnectorProps extends ViewStateProps {
15
- Domain: 'Space' | 'Halo';
15
+ Kind: 'Space' | 'Halo';
16
16
  }
17
17
 
18
18
  const InvitationActions = ({
@@ -20,16 +20,16 @@ const InvitationActions = ({
20
20
  disabled,
21
21
  joinSend,
22
22
  joinState,
23
- Domain
23
+ Kind
24
24
  }: {
25
25
  invitationState?: Invitation.State;
26
26
  disabled?: boolean;
27
27
  joinSend: JoinSend;
28
28
  joinState?: JoinState;
29
- Domain: InvitationConnectorProps['Domain'];
29
+ Kind: InvitationConnectorProps['Kind'];
30
30
  }) => {
31
31
  const { t } = useTranslation('os');
32
- const invitationType = Domain.toLowerCase() as 'space' | 'halo';
32
+ const invitationType = Kind.toLowerCase() as 'space' | 'halo';
33
33
  switch (invitationState) {
34
34
  case Invitation.State.CONNECTING:
35
35
  return (
@@ -73,7 +73,7 @@ const InvitationActions = ({
73
73
  <Button
74
74
  disabled={disabled}
75
75
  className='flex items-center gap-2 pli-2'
76
- onClick={() => joinSend({ type: `reset${Domain}Invitation` })}
76
+ onClick={() => joinSend({ type: `reset${Kind}Invitation` })}
77
77
  data-testid='invitation-rescuer-reset'
78
78
  >
79
79
  <CaretLeft weight='bold' className={mx(getSize(5), 'invisible')} />
@@ -85,10 +85,10 @@ const InvitationActions = ({
85
85
  }
86
86
  };
87
87
 
88
- export const InvitationRescuer = ({ Domain, ...viewStateProps }: InvitationConnectorProps) => {
88
+ export const InvitationRescuer = ({ Kind, ...viewStateProps }: InvitationConnectorProps) => {
89
89
  const disabled = !viewStateProps.active;
90
90
  const { joinSend, joinState } = viewStateProps;
91
- const invitationState = joinState?.context[Domain.toLowerCase() as 'space' | 'halo'].invitation?.state;
91
+ const invitationState = joinState?.context[Kind.toLowerCase() as 'space' | 'halo'].invitation?.state;
92
92
  const { t } = useTranslation('os');
93
93
  return (
94
94
  <ViewState {...viewStateProps}>
@@ -98,9 +98,9 @@ export const InvitationRescuer = ({ Domain, ...viewStateProps }: InvitationConne
98
98
  <Button
99
99
  disabled={disabled}
100
100
  className='flex items-center gap-2 pli-2'
101
- data-autofocus={`inputting${Domain}InvitationCode`}
101
+ data-autofocus={`inputting${Kind}InvitationCode`}
102
102
  data-testid='invitation-rescuer-blank-reset'
103
- onClick={() => joinSend({ type: `reset${Domain}Invitation` })}
103
+ onClick={() => joinSend({ type: `reset${Kind}Invitation` })}
104
104
  >
105
105
  <CaretLeft weight='bold' className={mx(getSize(5), 'invisible')} />
106
106
  <span className='grow'>{t('reset label')}</span>
@@ -108,7 +108,7 @@ export const InvitationRescuer = ({ Domain, ...viewStateProps }: InvitationConne
108
108
  </Button>
109
109
  </>
110
110
  ) : (
111
- <InvitationActions {...{ invitationState, disabled, joinSend, joinState, Domain }} />
111
+ <InvitationActions {...{ invitationState, disabled, joinSend, joinState, Kind }} />
112
112
  )}
113
113
  </ViewState>
114
114
  );
@@ -3,9 +3,9 @@
3
3
  //
4
4
 
5
5
  import { UserPlus } from '@phosphor-icons/react';
6
- import React, { cloneElement, useReducer } from 'react';
6
+ import React, { cloneElement, useCallback, useReducer } from 'react';
7
7
 
8
- import { Space } from '@dxos/client';
8
+ import { Invitation, InvitationEncoder, Space } from '@dxos/client';
9
9
  import { useSpaceInvitations, observer } from '@dxos/react-client';
10
10
  import { Button, DensityProvider, getSize, mx, useTranslation } from '@dxos/react-components';
11
11
 
@@ -27,10 +27,20 @@ const CurrentSpaceView = observer(({ space, createInvitationUrl, titleId }: Spac
27
27
  const invitations = useSpaceInvitations(space?.key);
28
28
  const name = space?.properties.name;
29
29
 
30
+ console.log('[space panel]', process.env.NODE_ENV);
31
+
30
32
  if (!space) {
31
33
  return null;
32
34
  }
33
35
 
36
+ const onInvitationEvent = useCallback((invitation: Invitation) => {
37
+ const invitationCode = InvitationEncoder.encode(invitation);
38
+ console.log(JSON.stringify({ invitationCode }));
39
+ if (invitation.authCode) {
40
+ console.log(JSON.stringify({ authCode: invitation.authCode }));
41
+ }
42
+ }, []);
43
+
34
44
  return (
35
45
  <div role='none' className='flex flex-col'>
36
46
  <div role='none' className={mx(subduedSurface, 'rounded-bs-md flex items-center p-2 gap-2')}>
@@ -42,12 +52,17 @@ const CurrentSpaceView = observer(({ space, createInvitationUrl, titleId }: Spac
42
52
  <div role='region' className={mx(defaultSurface, 'rounded-be-md p-2')}>
43
53
  <InvitationList
44
54
  invitations={invitations}
45
- onClickRemove={({ invitation }) => invitation && space?.removeInvitation(invitation.invitationId!)}
55
+ onClickRemove={(invitation) => invitation.get() && space?.removeInvitation(invitation.get().invitationId)}
46
56
  createInvitationUrl={createInvitationUrl}
47
57
  />
48
58
  <Button
49
59
  className='is-full flex gap-2 mbs-2'
50
- onClick={() => space?.createInvitation()}
60
+ onClick={() => {
61
+ const invitation = space?.createInvitation();
62
+ if (process.env.NODE_ENV !== 'production') {
63
+ invitation.subscribe(onInvitationEvent);
64
+ }
65
+ }}
51
66
  data-testid='spaces-panel.create-invitation'
52
67
  >
53
68
  <span>{t('create space invitation label')}</span>