tangled
alpha
login
or
join now
futur.blue
/
pegasus
57
fork
atom
objective categorical abstract machine language personal data server
57
fork
atom
overview
issues
2
pulls
pipelines
Don't remove form from DOM while it's submitting
futur.blue
2 months ago
38c6d716
a871067c
verified
This commit was signed with the committer's
known signature
.
futur.blue
SSH Key Fingerprint:
SHA256:QHGqHWNpqYyw9bt8KmPuJIyeZX9SZewBZ0PR1COtKQ0=
+99
-126
1 changed file
expand all
collapse all
unified
split
frontend
src
templates
MigratePage.mlx
+99
-126
frontend/src/templates/MigratePage.mlx
···
47
47
"error"
48
48
49
49
let step_to_number = function
50
50
-
| EnterCredentials | ResumeAvailable | Enter2FA ->
51
51
-
0
52
52
-
| ImportingData ->
50
50
+
| EnterCredentials | ResumeAvailable | Enter2FA | ImportingData ->
53
51
1
54
52
| EnterPlcToken ->
55
53
2
···
104
102
</div>
105
103
end
106
104
107
107
-
module LoadingOverlay = struct
108
108
-
type loading_step =
109
109
-
{ label: string
110
110
-
; message: string
111
111
-
; duration: int (* ms before moving to next step *) }
112
112
-
113
113
-
let steps =
114
114
-
[| { label= "authenticating"
115
115
-
; message= "Logging into your current PDS..."
116
116
-
; duration= 2000 (* fake step *) }
117
117
-
; { label= "creating account"
118
118
-
; message= "Creating your account on this PDS..."
119
119
-
; duration= 2000 (* fake step *) }
120
120
-
; { label= "importing repository"
121
121
-
; message= "Importing your repository data..."
122
122
-
; duration= 0 (* stays here until page loads *) } |]
105
105
+
module LoadingSpinner = struct
106
106
+
let messages =
107
107
+
[| "Logging into your current PDS..."
108
108
+
; "Creating your account on this PDS..."
109
109
+
; "Importing your repository data..." |]
123
110
124
111
let[@react.component] make () =
125
125
-
let step_index, set_step_index = React.useState (fun () -> 0) in
126
126
-
(* advance through steps on a timer *)
112
112
+
let msg_index, set_msg_index = React.useState (fun () -> 0) in
113
113
+
(* cycle through messages every 2 seconds *)
127
114
React.useEffect1
128
115
(fun () ->
129
129
-
let current = steps.(step_index) in
130
130
-
if current.duration > 0 && step_index < Array.length steps - 1 then
116
116
+
if msg_index < Array.length messages - 1 then
131
117
let timer_id =
132
118
Js.Global.setTimeout
133
133
-
~f:(fun () -> set_step_index (fun i -> i + 1))
134
134
-
current.duration
119
119
+
~f:(fun () -> set_msg_index (fun i -> i + 1))
120
120
+
2000
135
121
in
136
122
Some (fun () -> Js.Global.clearTimeout timer_id)
137
123
else None )
138
138
-
[|step_index|] ;
139
139
-
let current = steps.(step_index) in
140
140
-
let step_number = step_index + 1 in
141
141
-
<div>
142
142
-
<div className="mb-6">
143
143
-
<div className="flex items-center gap-1 text-sm text-mist-100 mb-2">
144
144
-
<span>
145
145
-
(string
146
146
-
( "step " ^ string_of_int step_number ^ " of "
147
147
-
^ string_of_int total_steps ^ ": " ) )
148
148
-
</span>
149
149
-
<span className="font-medium text-mana-100">
150
150
-
(string current.label)
151
151
-
</span>
152
152
-
</div>
153
153
-
<div
154
154
-
className="w-full bg-mist-60 rounded-full h-3"
155
155
-
style=(ReactDOM.Style.make
156
156
-
~boxShadow:"0 4px 8px 0 rgba(115, 117, 121, 0.30) inset" () )>
157
157
-
<div
158
158
-
className="bg-mana-100 shadow-elixir h-3 rounded-full \
159
159
-
transition-all duration-500"
160
160
-
style=(ReactDOM.Style.make
161
161
-
~width:
162
162
-
(string_of_int (step_number * 100 / total_steps) ^ "%")
163
163
-
() )
164
164
-
/>
165
165
-
</div>
166
166
-
</div>
167
167
-
<div className="flex flex-col items-center py-8">
168
168
-
<div
169
169
-
className="animate-spin w-8 h-8 border-2 border-mana-100 \
170
170
-
border-t-transparent rounded-full mb-4"
171
171
-
/>
172
172
-
<p className="text-mist-100 text-center">(string current.message)</p>
173
173
-
</div>
124
124
+
[|msg_index|] ;
125
125
+
<div className="flex flex-col items-center py-8">
126
126
+
<div
127
127
+
className="animate-spin w-8 h-8 border-2 border-mana-100 \
128
128
+
border-t-transparent rounded-full mb-4"
129
129
+
/>
130
130
+
<p className="text-mist-100 text-center">(string messages.(msg_index))</p>
174
131
</div>
175
132
end
176
133
···
186
143
let[@react.component] make ~csrf_token ~invite_required () =
187
144
let is_submitting, set_is_submitting = React.useState (fun () -> false) in
188
145
let handle_submit _ = set_is_submitting (fun _ -> true) in
189
189
-
if is_submitting then <LoadingOverlay />
190
190
-
else
191
191
-
array
192
192
-
[| <p key="desc" className="w-full text-balance text-mist-100 mb-4">
193
193
-
(string
194
194
-
"Migrate your existing atproto account to this PDS. You'll \
195
195
-
need your account credentials from your current PDS." )
196
196
-
</p>
197
197
-
; <form
198
198
-
key="form"
199
199
-
className="w-full flex flex-col gap-y-3"
200
200
-
onSubmit=handle_submit>
201
201
-
<input type_="hidden" name="dream.csrf" value=csrf_token />
202
202
-
<input type_="hidden" name="action" value="start_migration" />
203
203
-
( if invite_required then
204
204
-
<Input
205
205
-
name="invite_code"
206
206
-
type_="text"
207
207
-
label="Invite code"
208
208
-
placeholder="a1b2c3d4"
209
209
-
required=true
210
210
-
showIndicator=false />
211
211
-
else null )
212
212
-
<Input
213
213
-
name="identifier"
214
214
-
type_="text"
215
215
-
label="Existing handle or DID"
216
216
-
placeholder="you.bsky.social or did:plc:..."
217
217
-
required=true
218
218
-
showIndicator=false
219
219
-
/>
220
220
-
<Input
221
221
-
name="password"
222
222
-
type_="password"
223
223
-
label="Existing password"
224
224
-
required=true
225
225
-
showIndicator=false
226
226
-
/>
227
227
-
<p className="text-xs text-mist-80 -mt-1">
228
228
-
(string
229
229
-
"Use your actual account password, not an app password. Your \
230
230
-
password is only used to log into your current PDS and is \
231
231
-
never stored." )
232
232
-
</p>
233
233
-
<Button type_="submit" formMethod="post" className="mt-2">
234
234
-
(string "start migration")
235
235
-
</Button>
236
236
-
</form>
237
237
-
; <div key="footer" className="mt-4">
238
238
-
<span className="text-sm text-mist-100">
239
239
-
(string "Don't have an account? ")
240
240
-
<a
241
241
-
href="/account/signup"
242
242
-
className="text-mana-100 underline hover:text-mana-200">
243
243
-
(string "sign up")
244
244
-
</a>
245
245
-
(string " instead.")
246
246
-
</span>
247
247
-
</div> |]
146
146
+
<div>
147
147
+
( if is_submitting then
148
148
+
<div>
149
149
+
<ProgressIndicator step_number=1 label="importing data" />
150
150
+
<LoadingSpinner />
151
151
+
</div>
152
152
+
else null )
153
153
+
<div className=(if is_submitting then "hidden" else "")>
154
154
+
<p className="w-full text-balance text-mist-100 mb-4">
155
155
+
(string
156
156
+
"Migrate your existing atproto account to this PDS. You'll need \
157
157
+
your account credentials from your current PDS." )
158
158
+
</p>
159
159
+
<form className="w-full flex flex-col gap-y-3" onSubmit=handle_submit>
160
160
+
<input type_="hidden" name="dream.csrf" value=csrf_token />
161
161
+
<input type_="hidden" name="action" value="start_migration" />
162
162
+
( if invite_required then
163
163
+
<Input
164
164
+
name="invite_code"
165
165
+
type_="text"
166
166
+
label="Invite code"
167
167
+
placeholder="a1b2c3d4"
168
168
+
required=true
169
169
+
showIndicator=false />
170
170
+
else null )
171
171
+
<Input
172
172
+
name="identifier"
173
173
+
type_="text"
174
174
+
label="Existing handle or DID"
175
175
+
placeholder="you.bsky.social or did:plc:..."
176
176
+
required=true
177
177
+
showIndicator=false
178
178
+
/>
179
179
+
<Input
180
180
+
name="password"
181
181
+
type_="password"
182
182
+
label="Existing password"
183
183
+
required=true
184
184
+
showIndicator=false
185
185
+
/>
186
186
+
<p className="text-xs text-mist-80 -mt-1">
187
187
+
(string
188
188
+
"Use your actual account password, not an app password. Your \
189
189
+
password is only used to log into your current PDS and is \
190
190
+
never stored." )
191
191
+
</p>
192
192
+
<Button type_="submit" formMethod="post" className="mt-2">
193
193
+
(string "start migration")
194
194
+
</Button>
195
195
+
</form>
196
196
+
<div className="mt-4">
197
197
+
<span className="text-sm text-mist-100">
198
198
+
(string "Don't have an account? ")
199
199
+
<a
200
200
+
href="/account/signup"
201
201
+
className="text-mana-100 underline hover:text-mana-200">
202
202
+
(string "sign up")
203
203
+
</a>
204
204
+
(string " instead.")
205
205
+
</span>
206
206
+
</div>
207
207
+
</div>
208
208
+
</div>
248
209
end
249
210
250
211
module ResumeForm = struct
251
212
let[@react.component] make ~csrf_token ~did () =
252
213
let is_submitting, set_is_submitting = React.useState (fun () -> false) in
253
214
let handle_submit _ = set_is_submitting (fun _ -> true) in
254
254
-
if is_submitting then <LoadingOverlay />
255
255
-
else
256
256
-
<div>
215
215
+
<div>
216
216
+
( if is_submitting then
217
217
+
<div>
218
218
+
<ProgressIndicator step_number=1 label="importing data" />
219
219
+
<LoadingSpinner />
220
220
+
</div>
221
221
+
else null )
222
222
+
<div className=(if is_submitting then "hidden" else "")>
257
223
<div
258
224
className="bg-mana-100/10 border border-mana-100/30 rounded-lg p-4 \
259
225
mb-4">
···
309
275
</a>
310
276
</div>
311
277
</div>
278
278
+
</div>
312
279
end
313
280
314
281
module TwoFactorForm = struct
315
282
let[@react.component] make ~csrf_token ~identifier ~old_pds ~invite_code () =
316
283
let is_submitting, set_is_submitting = React.useState (fun () -> false) in
317
284
let handle_submit _ = set_is_submitting (fun _ -> true) in
318
318
-
if is_submitting then <LoadingOverlay />
319
319
-
else
320
320
-
<div>
285
285
+
<div>
286
286
+
( if is_submitting then
287
287
+
<div>
288
288
+
<ProgressIndicator step_number=1 label="importing data" />
289
289
+
<LoadingSpinner />
290
290
+
</div>
291
291
+
else null )
292
292
+
<div className=(if is_submitting then "hidden" else "")>
321
293
<p className="text-mist-100 mb-4">
322
294
(string
323
295
"Your account requires two-factor authentication. Check your \
···
363
335
</a>
364
336
</div>
365
337
</div>
338
338
+
</div>
366
339
end
367
340
368
341
module BlobProgress = struct