+238
-4
web-ui/src/routes/missing-blobs/+page.svelte
+238
-4
web-ui/src/routes/missing-blobs/+page.svelte
···
3
3
import missingPicture from '$lib/assets/missing.webp'
4
4
import {MissingBlobs} from '@pds-moover/moover';
5
5
6
-
let {data} = $props();
6
+
let missingBlobs = $state(new MissingBlobs());
7
+
// Form state
8
+
let showCurrentLogin = $state(true);
9
+
let showOldLogin = $state(false);
10
+
let showAdvance = $state(false);
11
+
let disableLoginButton = $state(false);
12
+
let showBlobMoveProgress = $state(false);
13
+
let oldPdsUrl = $state<string | null>(null);
14
+
let showTryAgain = $state(false);
15
+
let errorMessage: string | null = $state(null);
16
+
let showStatusMessage = $state(false);
17
+
let statusMessage = $state('');
18
+
19
+
let currentLogin = $state({
20
+
handle: '',
21
+
password: '',
22
+
twoFactorCode: '',
23
+
showTwoFactorCodeInput: false,
24
+
});
25
+
26
+
let oldLogin = $state({
27
+
password: '',
28
+
twoFactorCode: '',
29
+
showTwoFactorCodeInput: false,
30
+
});
31
+
32
+
function resetStatusAndErrors() {
33
+
showStatusMessage = false;
34
+
statusMessage = '';
35
+
errorMessage = '';
36
+
disableLoginButton = true;
37
+
}
38
+
39
+
async function handleCurrentLogin(event: SubmitEvent) {
40
+
event.preventDefault();
41
+
resetStatusAndErrors();
42
+
try {
43
+
const {
44
+
accountStatus,
45
+
missingBlobsCount
46
+
} = await missingBlobs.currentAgentLogin(currentLogin.handle, currentLogin.password, currentLogin.twoFactorCode);
47
+
console.log(missingBlobsCount);
48
+
const noMissingBlobs = missingBlobsCount === 0;
49
+
if (noMissingBlobs) {
50
+
statusMessage = `You are good to go! You are not missing any blobs. Your account has ${accountStatus.importedBlobs} imported blobs and expects to have at least ${accountStatus.expectedBlobs} blobs. No action is required.`
51
+
} else {
52
+
showCurrentLogin = false;
53
+
statusMessage = 'You are currently missing some blobs. Login with your old password to import the missing blobs. We will automatically find your old handle.';
54
+
showOldLogin = true;
55
+
}
56
+
showStatusMessage = true;
57
+
58
+
} catch (err) {
59
+
//@ts-expect-error: Should always have an error message
60
+
if (err.error === 'AuthFactorTokenRequired') {
61
+
currentLogin.showTwoFactorCodeInput = true;
62
+
}
63
+
//@ts-expect-error: Should always have an error message
64
+
error = err.message;
65
+
}
66
+
disableLoginButton = false;
67
+
}
68
+
69
+
async function handleOldLogin(event: SubmitEvent) {
70
+
event.preventDefault();
71
+
resetStatusAndErrors();
72
+
try {
73
+
await missingBlobs.oldAgentLogin(oldLogin.password, oldLogin.twoFactorCode, oldPdsUrl);
74
+
showOldLogin = false;
75
+
showBlobMoveProgress = true;
76
+
showStatusMessage = true;
77
+
statusMessage = '';
78
+
await migrateMissingBlobs();
79
+
} catch (err) {
80
+
//@ts-expect-error: Should always have an error message
81
+
if (err.error === 'AuthFactorTokenRequired') {
82
+
oldLogin.showTwoFactorCodeInput = true;
83
+
}
84
+
//@ts-expect-error: Should always have an error message
85
+
error = err.message;
86
+
}
87
+
disableLoginButton = false;
88
+
}
89
+
90
+
function updateStatusHandler(status: string) {
91
+
console.log('Status update:', status);
92
+
const statusElement = document.getElementById('missing-status-message');
93
+
if (statusElement) {
94
+
statusElement.innerText = status;
95
+
}
96
+
}
97
+
98
+
async function migrateMissingBlobs() {
99
+
try {
100
+
resetStatusAndErrors();
101
+
showStatusMessage = true;
102
+
showTryAgain = false;
103
+
const {
104
+
accountStatus,
105
+
missingBlobsCount
106
+
} = await missingBlobs.migrateMissingBlobs(updateStatusHandler);
107
+
const noMissingBlobs = missingBlobsCount === 0;
108
+
if (noMissingBlobs) {
109
+
statusMessage = `You are good to go! You have all ${accountStatus.importedBlobs} of the expected ${accountStatus.expectedBlobs} blobs. You're done!!`
110
+
} else {
111
+
statusMessage = `Expected blobs: ${accountStatus.expectedBlobs} Imported blobs: ${accountStatus.importedBlobs}`;
112
+
showTryAgain = true;
113
+
}
114
+
} catch (err) {
115
+
//@ts-expect-error: Should always have an error message
116
+
error = err.message;
117
+
showTryAgain = true;
118
+
}
119
+
disableLoginButton = false;
120
+
}
121
+
122
+
function toggleAdvanceMenu() {
123
+
showAdvance = !showAdvance;
124
+
}
7
125
</script>
8
126
9
127
<svelte:head>
10
-
<title>PDS MOOver - Missing</title>
128
+
<title>PDS MOOver - Missing Blobs</title>
11
129
<meta property="og:description" content="Import missing blobs from your old PDS to your new PDS"/>
12
130
<meta property="og:image" content="{missingPicture}">
13
131
</svelte:head>
14
-
15
132
16
133
{#snippet custom_img()}
17
134
<img src='{missingPicture}' alt='Cartoon milk cow on a missing poster'
···
20
137
21
138
<div class="container">
22
139
<MooHeader title="Missing Blobs Importer" customImg={custom_img}/>
23
-
</div>
140
+
141
+
<a href="https://blacksky.community/profile/did:plc:g7j6qok5us4hjqlwjxwrrkjm/post/3lyylumcpok2c">How to video
142
+
guide</a>
143
+
144
+
<!-- First section: Current Login credentials -->
145
+
{#if showCurrentLogin}
146
+
<form id="moover-form" onsubmit={handleCurrentLogin}>
147
+
<div class="section">
148
+
<h2>Login for your current PDS</h2>
149
+
<div class="form-group">
150
+
<label for="current_handle">Current Handle:</label>
151
+
<input type="text" id="current_handle" name="handle" placeholder="alice.bsky.social"
152
+
bind:value={currentLogin.handle}
153
+
required>
154
+
</div>
155
+
156
+
<div class="form-group">
157
+
<label for="current_password">Current Password:</label>
158
+
<input type="password" id="current_password" name="password" bind:value={currentLogin.password}
159
+
required>
160
+
</div>
161
+
162
+
{#if currentLogin.showTwoFactorCodeInput}
163
+
<div class="form-group">
164
+
<label for="current_two-factor-code">2FA from the email sent</label>
165
+
<input type="text" id="current_two-factor-code" name="two-factor-code"
166
+
bind:value={currentLogin.twoFactorCode}>
167
+
<div class="error-message">Enter your 2fa code here</div>
168
+
</div>
169
+
{/if}
170
+
{#if errorMessage}
171
+
<div class="error-message">{errorMessage}</div>
172
+
{/if}
173
+
{#if showStatusMessage}
174
+
<div class="status-message">{statusMessage}</div>
175
+
{/if}
176
+
177
+
<div>
178
+
<button disabled={disableLoginButton} type="submit">Login</button>
179
+
</div>
180
+
</div>
181
+
</form>
182
+
{/if}
183
+
184
+
<!-- Second section: Old Login credentials -->
185
+
{#if showOldLogin}
186
+
<form onsubmit={handleOldLogin}>
187
+
<div class="section">
188
+
<h2>Password for your OLD PDS</h2>
189
+
<p>We only need your password for your old account. We can find your old handle from your current
190
+
login.</p>
191
+
<div class="form-group">
192
+
<label for="password">OLD Password:</label>
193
+
<input type="password" id="password" name="password" bind:value={oldLogin.password} required>
194
+
</div>
195
+
196
+
{#if oldLogin.showTwoFactorCodeInput}
197
+
<div class="form-group">
198
+
<label for="two-factor-code">2FA from the email sent</label>
199
+
<input type="text" id="two-factor-code" name="two-factor-code"
200
+
bind:value={oldLogin.twoFactorCode}>
201
+
<div class="error-message">Enter your 2fa code here</div>
202
+
</div>
203
+
{/if}
204
+
205
+
{#if showAdvance}
206
+
<div class="form-group show-advance">
207
+
<label for="old_pds">This is optional. If you do not know your old PDS url please leave it
208
+
blank. We
209
+
will find it for you. </label>
210
+
<input type="url" id="old_pds" name="two-factor-code"
211
+
placeholder="(Optional) Your old PDS URL" bind:value={oldPdsUrl}>
212
+
</div>
213
+
{/if}
214
+
<div class="form-group">
215
+
<button type="button" onclick={toggleAdvanceMenu} id="advance" name="advance">Advance Options
216
+
</button>
217
+
</div>
218
+
219
+
{#if errorMessage}
220
+
<div class="error-message">{errorMessage}</div>
221
+
{/if}
222
+
{#if showStatusMessage}
223
+
<div class="status-message">{statusMessage}</div>
224
+
{/if}
225
+
226
+
<div>
227
+
<button disabled={disableLoginButton} type="submit">Login and start the import of missing blobs
228
+
</button>
229
+
</div>
230
+
</div>
231
+
</form>
232
+
{/if}
233
+
234
+
<!-- Third section: Progress while uploading blobs-->
235
+
{#if showBlobMoveProgress}
236
+
<div>
237
+
{#if showStatusMessage}
238
+
<div id="warning">*This will take a while. Please do not close this tab. And watch
239
+
the status message below for updates
240
+
</div>
241
+
{/if}
242
+
{#if showStatusMessage}
243
+
<div id="missing-status-message" class="status-message">{statusMessage}</div>
244
+
{/if}
245
+
{#if errorMessage}
246
+
<div class="error-message">{errorMessage}</div>
247
+
{/if}
248
+
{#if showTryAgain}
249
+
<p style="color: yellow">We were unable to import all of your previous blobs, please try again. If it is
250
+
still not completing give it a few hours and come back and try again. It may be rate limited. Re
251
+
running this tool does not harm your account.</p>
252
+
<br>
253
+
<button onclick={migrateMissingBlobs}>Try again</button>
254
+
{/if}
255
+
</div>
256
+
{/if}
257
+
</div>