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