@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.
- package/dist/lib/browser/chunk-5VRACIDE.mjs +10 -0
- package/dist/lib/browser/chunk-5VRACIDE.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +225 -174
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +43 -0
- package/dist/lib/browser/testing/index.mjs.map +7 -0
- package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationListItem.d.ts.map +1 -1
- package/dist/types/src/composites/JoinDialog/JoinDialog.stories.d.ts.map +1 -1
- package/dist/types/src/composites/Shell/ShellContext.d.ts.map +1 -1
- package/dist/types/src/panels/DevicesPanel/DevicesPanel.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/joinMachine.d.ts +5 -5
- package/dist/types/src/panels/JoinPanel/joinMachine.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts +2 -2
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts +2 -2
- package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts +2 -2
- package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts.map +1 -1
- package/dist/types/src/panels/SpacePanel/SpacePanel.d.ts.map +1 -1
- package/dist/types/src/playwright/invitations-manager.d.ts +8 -17
- package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/shell-manager.d.ts +16 -0
- package/dist/types/src/testing/shell-manager.d.ts.map +1 -0
- package/dist/types/src/util/invitationStatusValue.d.ts.map +1 -1
- package/package.json +25 -14
- package/src/components/InvitationList/InvitationList.tsx +2 -2
- package/src/components/InvitationList/InvitationListContainer.tsx +3 -2
- package/src/components/InvitationList/InvitationListItem.tsx +4 -8
- package/src/composites/JoinDialog/JoinDialog.stories.tsx +3 -12
- package/src/composites/Shell/Shell.tsx +1 -1
- package/src/composites/Shell/ShellContext.tsx +11 -8
- package/src/panels/DevicesPanel/DevicesPanel.tsx +3 -1
- package/src/panels/JoinPanel/JoinPanel.tsx +8 -8
- package/src/panels/JoinPanel/joinMachine.ts +108 -98
- package/src/panels/JoinPanel/view-states/InvitationAccepted.tsx +6 -6
- package/src/panels/JoinPanel/view-states/InvitationAuthenticator.tsx +14 -14
- package/src/panels/JoinPanel/view-states/InvitationInput.tsx +9 -9
- package/src/panels/JoinPanel/view-states/InvitationRescuer.tsx +10 -10
- package/src/panels/SpacePanel/SpacePanel.tsx +19 -4
- package/src/playwright/invitations-manager.ts +23 -78
- package/src/playwright/invitations.spec.ts +79 -117
- package/src/testing/index.ts +5 -0
- package/src/testing/shell-manager.ts +59 -0
- 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
|
|
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:
|
|
30
|
-
space:
|
|
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
|
-
| '
|
|
46
|
-
| '
|
|
47
|
-
| '
|
|
48
|
-
| '
|
|
49
|
-
| '
|
|
50
|
-
| '
|
|
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
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
109
|
-
log.error('[invitation errored]', {
|
|
110
|
-
next({ type: `fail${
|
|
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 = (
|
|
133
|
+
const acceptingInvitationTemplate = (Kind: 'Space' | 'Halo', successTarget: string) => {
|
|
120
134
|
const config: StateNodeConfig<JoinMachineContext, any, InvitationEvent> = {
|
|
121
|
-
initial: `unknown${
|
|
135
|
+
initial: `unknown${Kind}`,
|
|
122
136
|
states: {
|
|
123
|
-
[`unknown${
|
|
137
|
+
[`unknown${Kind}`]: {
|
|
124
138
|
always: [
|
|
125
139
|
{
|
|
126
|
-
cond: ({ mode }) => mode === 'halo-only' &&
|
|
140
|
+
cond: ({ mode }) => mode === 'halo-only' && Kind === 'Space',
|
|
127
141
|
target: '#join.finishingJoiningHalo'
|
|
128
142
|
},
|
|
129
143
|
{
|
|
130
|
-
// cond: `no${
|
|
131
|
-
target: `inputting${
|
|
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${
|
|
137
|
-
// actions: [`redeem${
|
|
150
|
+
// target: `acceptingRedeemed${Kind}Invitation`,
|
|
151
|
+
// actions: [`redeem${Kind}InvitationCode`, 'log']
|
|
138
152
|
// }
|
|
139
153
|
]
|
|
140
154
|
},
|
|
141
|
-
[`inputting${
|
|
142
|
-
[`acceptingRedeemed${
|
|
155
|
+
[`inputting${Kind}InvitationCode`]: {},
|
|
156
|
+
[`acceptingRedeemed${Kind}Invitation`]: {
|
|
143
157
|
invoke: {
|
|
144
|
-
src: (context) => context[
|
|
158
|
+
src: (context) => context[Kind.toLowerCase() as 'space' | 'halo'].invitationSubscribable!
|
|
145
159
|
},
|
|
146
|
-
initial: `unknown${
|
|
160
|
+
initial: `unknown${Kind}Invitation`,
|
|
147
161
|
states: {
|
|
148
|
-
[`unknown${
|
|
162
|
+
[`unknown${Kind}Invitation`]: {
|
|
149
163
|
always: [
|
|
150
164
|
{
|
|
151
165
|
cond: (context) => {
|
|
152
|
-
const invitation = context[
|
|
166
|
+
const invitation = context[Kind.toLowerCase() as 'space' | 'halo'].invitation;
|
|
153
167
|
return !invitation || invitation?.state === Invitation.State.CONNECTING;
|
|
154
168
|
},
|
|
155
|
-
target: `connecting${
|
|
169
|
+
target: `connecting${Kind}Invitation`,
|
|
156
170
|
actions: 'log'
|
|
157
171
|
},
|
|
158
172
|
{
|
|
159
|
-
target: `inputting${
|
|
173
|
+
target: `inputting${Kind}VerificationCode`,
|
|
160
174
|
actions: 'log'
|
|
161
175
|
}
|
|
162
176
|
]
|
|
163
177
|
},
|
|
164
|
-
[`connecting${
|
|
165
|
-
[`inputting${
|
|
178
|
+
[`connecting${Kind}Invitation`]: {},
|
|
179
|
+
[`inputting${Kind}VerificationCode`]: {},
|
|
180
|
+
[`authenticating${Kind}VerificationCode`]: {
|
|
166
181
|
on: {
|
|
167
|
-
[`
|
|
168
|
-
target: `
|
|
169
|
-
actions: 'log'
|
|
182
|
+
[`readyForAuthentication${Kind}Invitation`]: {
|
|
183
|
+
target: `authenticationFailing${Kind}VerificationCode`,
|
|
184
|
+
actions: ['setInvitation', 'log']
|
|
170
185
|
}
|
|
171
186
|
}
|
|
172
187
|
},
|
|
173
|
-
[`
|
|
174
|
-
|
|
175
|
-
|
|
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${
|
|
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
|
-
[`
|
|
193
|
-
target: `.connecting${
|
|
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
|
-
[`
|
|
197
|
-
target: `.
|
|
209
|
+
[`authenticating${Kind}Invitation`]: {
|
|
210
|
+
target: `.authenticating${Kind}VerificationCode`,
|
|
198
211
|
actions: ['setInvitation', 'log']
|
|
199
212
|
},
|
|
200
|
-
[`
|
|
201
|
-
[`fail${
|
|
202
|
-
target: `.failing${
|
|
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
|
-
[
|
|
218
|
+
[Kind.toLowerCase() as 'space' | 'halo']: (
|
|
206
219
|
context: JoinMachineContext,
|
|
207
220
|
event: FailInvitationEvent
|
|
208
221
|
) => ({
|
|
209
|
-
...context[
|
|
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${
|
|
221
|
-
target: `.acceptingRedeemed${
|
|
233
|
+
[`set${Kind}InvitationCode`]: {
|
|
234
|
+
target: `.acceptingRedeemed${Kind}Invitation`,
|
|
222
235
|
actions: [
|
|
223
236
|
assign({
|
|
224
|
-
[
|
|
225
|
-
context
|
|
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${
|
|
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
|
-
|
|
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
|
-
|
|
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${
|
|
36
|
-
data-testid={`${
|
|
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 {
|
|
61
|
+
const { Kind, doneActionParent: _doneActionParent, onDone: _onDone, ...viewStateProps } = props;
|
|
62
62
|
const activeInvitation =
|
|
63
|
-
viewStateProps.joinState?.context[
|
|
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
|
-
|
|
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
|
-
|
|
27
|
+
Kind,
|
|
28
28
|
onChange,
|
|
29
29
|
onAuthenticate
|
|
30
30
|
}: {
|
|
31
31
|
disabled?: boolean;
|
|
32
32
|
joinSend: JoinSend;
|
|
33
33
|
joinState?: JoinState;
|
|
34
|
-
|
|
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 =
|
|
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${
|
|
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
|
-
|
|
100
|
+
Kind,
|
|
101
101
|
failed
|
|
102
102
|
}: {
|
|
103
103
|
joinSend: JoinSend;
|
|
104
104
|
joinState?: JoinState;
|
|
105
105
|
disabled?: boolean;
|
|
106
106
|
invitation: AuthenticatingInvitationObservable;
|
|
107
|
-
|
|
107
|
+
Kind: InvitationAuthenticatorProps['Kind'];
|
|
108
108
|
failed: InvitationAuthenticatorProps['failed'];
|
|
109
109
|
}) => {
|
|
110
|
-
const invitationType =
|
|
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${
|
|
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,
|
|
128
|
+
{...{ disabled, failed, joinSend, joinState, Kind, onChange, onAuthenticate }}
|
|
129
129
|
/>
|
|
130
130
|
);
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
-
export const InvitationAuthenticator = ({ failed,
|
|
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[
|
|
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,
|
|
143
|
+
{...{ disabled, failed, joinSend, joinState, Kind, onChange: () => {}, onAuthenticate: () => {} }}
|
|
144
144
|
/>
|
|
145
145
|
) : (
|
|
146
146
|
<InvitationAuthenticatorContent
|
|
147
|
-
{...{ disabled, failed, invitation: activeInvitation, joinSend, joinState,
|
|
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
|
-
|
|
13
|
+
Kind: 'Space' | 'Halo';
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const InvitationInput = ({
|
|
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[
|
|
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${
|
|
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${
|
|
46
|
-
'data-testid': `${
|
|
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={`${
|
|
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={
|
|
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={`${
|
|
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
|
-
|
|
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
|
-
|
|
23
|
+
Kind
|
|
24
24
|
}: {
|
|
25
25
|
invitationState?: Invitation.State;
|
|
26
26
|
disabled?: boolean;
|
|
27
27
|
joinSend: JoinSend;
|
|
28
28
|
joinState?: JoinState;
|
|
29
|
-
|
|
29
|
+
Kind: InvitationConnectorProps['Kind'];
|
|
30
30
|
}) => {
|
|
31
31
|
const { t } = useTranslation('os');
|
|
32
|
-
const invitationType =
|
|
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${
|
|
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 = ({
|
|
88
|
+
export const InvitationRescuer = ({ Kind, ...viewStateProps }: InvitationConnectorProps) => {
|
|
89
89
|
const disabled = !viewStateProps.active;
|
|
90
90
|
const { joinSend, joinState } = viewStateProps;
|
|
91
|
-
const invitationState = joinState?.context[
|
|
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${
|
|
101
|
+
data-autofocus={`inputting${Kind}InvitationCode`}
|
|
102
102
|
data-testid='invitation-rescuer-blank-reset'
|
|
103
|
-
onClick={() => joinSend({ type: `reset${
|
|
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,
|
|
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={(
|
|
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={() =>
|
|
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>
|