source: Klonkt/src/views/pages/admin-migrate.ejs@ 47f1183

main
Last change on this file since 47f1183 was 47f1183, checked in by Robin <roboburr@…>, 4 weeks ago

Een stappenplan op de migrate-pagina, en de volgorde klopte niet

Robin: misschien moeten we bij migrate een stappenplan beschrijven, waaronder
dus ook dit (de Delete-ronde voor je een domein opzegt).

Bij het uitschrijven bleek de pagina zelf een verkeerde volgorde te suggereren.
Ik noemde het aankondigen "de laatste stap", maar ingestFromSource weigert met
not_moved_here zolang movedTo niet naar ons wijst. De ophaalknop werkt dus PAS
nadat de Move gedaan is. Aankondigen is stap 2, niet de afsluiter.

Met een zip mag het juist andersom: een bestand vraagt niemand toestemming. Die
twee volgordes naast elkaar zijn precies het soort ding waar je halverwege op
vastloopt zonder te snappen waarom, dus staan ze er nu uitgeschreven.

DE PAGINA DRAAIT OP BEIDE INSTANTIES. Stap 1, 3 en 4 horen op de nieuwe kant,
stap 2 en 5 op de oude. Een vast "hier" is dus op de helft van de schermen
onzin. Het plan draait mee met waar je kijkt, en op de vertrekkende kant staat
er een regel boven dat je naar de instantie kijkt die weggaat.

Die omkering had ik bij het bouwen precies verkeerd om: beide labels werden
"hier". Zag ik pas door hem te renderen, niet door hem te lezen.

STAP 5 heeft geen knop, en dat staat erbij. Verwijder je oude berichten voor je
het domein opzegt, zodat boosts van anderen netjes verdwijnen in plaats van te
blijven staan als kapotte kaart; haal daarna de alias weg, want die wijst naar
een adres dat je niet meer beheert. Een stappenplan dat een knop belooft die er
niet is, is erger dan geen stappenplan.

Changed files:
src/routes/admin-migrate.js

  • stappen(): afleiden wat af is uit aliassen, moved_to, de moves-collectie en de vertaaltabel; meegegeven aan alle drie de renders

src/views/pages/admin-migrate.ejs

  • het stappenplan bovenaan, met vinkjes en een waar-label per stap
  • de labels draaien om vanaf de vertrekkende kant

src/services/i18n.js

  • mig.plan_* in nl/en/de
  • mig.move_title is "Stap 2" en niet meer "Laatste stap"
  • de waarschuwing zegt nu dat dit EERST moet bij de ophaalknop

test/migrate-page.test.js

  • het plan staat boven de knoppen die het beschrijft
  • de perspectiefwissel, met de eis dat de twee labels nooit gelijk zijn
  • geen "laatste stap" meer in een van de drie talen
  • stap 5 noemt de Delete-ronde, de alias en dat er geen knop is

remarks: gerenderd vanaf beide kanten om het te controleren. Suite 1013 groen,
tegenproef op de perspectiefwissel.

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

  • Property mode set to 100644
File size: 18.6 KB
Line 
1<div class="container mig-wrap">
2 <h1><%= t('mig.title') %></h1>
3 <p class="mig-lead"><%= t('mig.lead') %></p>
4
5 <% if (typeof success !== 'undefined' && success) { %><div class="alert alert-success"><%= success %></div><% } %>
6 <% if (typeof error !== 'undefined' && error) { %><div class="alert alert-error"><%= error %></div><% } %>
7
8 <%# ── Het stappenplan ────────────────────────────────────────── %>
9 <%# Bestaat omdat de VOLGORDE niet vanzelfsprekend is en een fout erin je
10 halverwege vastzet. Twee dingen die niemand raadt:
11 - de ophaalknop werkt PAS nadat de verhuizing is aangekondigd; de bron
12 geeft niets af aan een instantie die niet in zijn movedTo staat;
13 - met een zip kan het juist andersom, want een zip vraagt niemand iets.
14 En stap 5 staat erbij omdat hij bestaat, niet omdat er een knop voor is. %>
15 <section class="mig-card mig-plan">
16 <h2><%= t('mig.plan_title') %></h2>
17 <p class="form-hint"><%= t('mig.plan_hint') %></p>
18 <%# "hier" hangt af van WELKE kant je bekijkt. Deze pagina draait op allebei
19 de instanties, en een vaste tekst is dus op de helft van de schermen
20 onzin. Heeft deze site een moved_to, dan is dit de vertrekkende kant. %>
21 <%# Stap 1, 3 en 4 horen op de NIEUWE kant; stap 2 en 5 op de oude. Vanaf
22 welke instantie je kijkt bepaalt dus welk van de twee "hier" is. %>
23 <% var _hier = stap.isOud ? t('mig.plan_new') : t('mig.plan_here');
24 var _daar = stap.isOud ? t('mig.plan_here') : t('mig.plan_old'); %>
25 <% if (stap.isOud) { %>
26 <p class="form-hint mig-warn"><%= t('mig.plan_from_old') %></p>
27 <% } %>
28 <ol class="mig-steps">
29 <li class="<%= stap.geclaimd ? 'is-done' : '' %>">
30 <strong><%= t('mig.plan_1') %></strong>
31 <span class="mig-waar"><%= _hier %></span>
32 <em><%= t('mig.plan_1_why') %></em>
33 </li>
34 <li class="<%= stap.aangekondigd ? 'is-done' : '' %>">
35 <strong><%= t('mig.plan_2') %></strong>
36 <span class="mig-waar"><%= _daar %></span>
37 <em><%= t('mig.plan_2_why') %></em>
38 </li>
39 <li class="<%= stap.opgehaald ? 'is-done' : '' %>">
40 <strong><%= t('mig.plan_3') %></strong>
41 <span class="mig-waar"><%= _hier %></span>
42 <em><%= t('mig.plan_3_why') %></em>
43 </li>
44 <li>
45 <strong><%= t('mig.plan_4') %></strong>
46 <span class="mig-waar"><%= _hier %></span>
47 </li>
48 <li class="mig-step-later">
49 <strong><%= t('mig.plan_5') %></strong>
50 <span class="mig-waar"><%= _daar %></span>
51 <em><%= t('mig.plan_5_why') %></em>
52 </li>
53 </ol>
54 </section>
55
56 <%# ── Je oude account claimen (FEP-7628 alsoKnownAs) ─────────── %>
57 <%# Bewust als EERSTE: zonder deze claim weigert de oude instantie de Move
58 met no_backreference, en kan de ophaalknop hieronder ook niets. Dit stond
59 op de site-bewerkpagina tussen de kleuren; daar zoekt niemand het als hij
60 aan het verhuizen is. %>
61 <section class="mig-card">
62 <h2><%= t('mig.alias_title') %></h2>
63 <p class="form-hint"><%= t('mig.alias_hint') %></p>
64 <form method="post" action="/admin/migrate/aliases">
65 <label for="mig-alias"><%= t('mig.alias_label') %></label>
66 <textarea id="mig-alias" name="ap_aliases" rows="3" class="mig-input"
67 placeholder="@oud@mastodon.social&#10;https://oude-klonkt.nl/ap/users/jij"><%= aliassen || '' %></textarea>
68 <p class="form-hint"><%= t('mig.alias_note') %></p>
69 <button type="submit" class="btn"><%= t('mig.alias_btn') %></button>
70 </form>
71 </section>
72
73 <%# ── Exporteren ─────────────────────────────────────────────── %>
74 <section class="mig-card">
75 <h2><%= t('mig.export_title') %></h2>
76 <p class="form-hint"><%= t('mig.export_hint') %></p>
77
78 <% if (telling) { %>
79 <ul class="mig-counts">
80 <li><strong><%= telling.posts %></strong> <%= t('mig.c_posts') %></li>
81 <li><strong><%= telling.replies %></strong> <%= t('mig.c_replies') %></li>
82 <li><strong><%= telling.media %></strong> <%= t('mig.c_media') %></li>
83 <%# Muziek APART tellen, niet onder "media". Dit ontbrak, en juist daardoor
84 kon een export van 140 nummers er als 4,5 MB uitzien zonder dat iemand
85 het merkte: de teller zei "39 mediabestanden" en zweeg over de rest. %>
86 <% if (telling.tracks) { %>
87 <%# Wat er ECHT meegaat, niet hoeveel rijen er in de database staan.
88 "8 nummers" met daaronder "van 3 ontbreekt het bestand" telt niet
89 op; 5 plus die waarschuwing wel. %>
90 <li><strong><%= telling.tracks - (telling.audioMissing || 0) %></strong> <%= t('mig.c_tracks') %></li>
91 <% } %>
92 <% if (telling.playlists) { %>
93 <li><strong><%= telling.playlists %></strong> <%= t('mig.c_playlists') %></li>
94 <% } %>
95 <% if (typeof telling.following === 'number') { %>
96 <li><strong><%= telling.following %></strong> <%= t('mig.c_following') %></li>
97 <% } %>
98 <li><strong><%= mb(telling.bytes) %></strong> <%= t('mig.c_size') %></li>
99 </ul>
100
101 <% if (telling.ontbrekend) { %>
102 <%# Niets stils: media die op schijf ontbreekt wordt geteld en gemeld, want
103 een archief dat stilzwijgend minder bevat is erger dan een waarschuwing. %>
104 <p class="alert alert-error"><%= t('mig.missing', { n: telling.ontbrekend }) %></p>
105 <% } %>
106
107 <% if (telling.audioMissing) { %>
108 <%# Een eigen zin voor muziek. "N mediaverwijzingen" zei niets over de
109 vraag die er toe doet: gaat mijn bibliotheek mee. %>
110 <p class="alert alert-error"><%= t('mig.audio_missing', { n: telling.audioMissing }) %></p>
111 <% } %>
112
113
114 <% if (telling.groot) { %>
115 <p class="alert alert-error"><%= t('mig.too_big') %></p>
116 <% } else { %>
117 <p><a class="btn btn-primary" href="/admin/migrate/export"><%= t('mig.export_btn') %></a></p>
118 <% } %>
119 <% } else { %>
120 <p class="form-hint"><%= t('mig.export_none') %></p>
121 <% } %>
122 </section>
123
124 <%# ── Rechtstreeks ophalen (FEP-1580) ────────────────────────── %>
125 <section class="mig-card">
126 <h2><%= t('mig.pull_title') %></h2>
127 <p class="form-hint"><%= t('mig.pull_hint') %></p>
128
129 <% if (haalVerslag) { %>
130 <div class="mig-report<%= haalVerslag.error ? '' : ' is-done' %>">
131 <% if (haalVerslag.error) { %>
132 <h3><%= t('mig.pull_failed') %></h3>
133 <%# Elke weigering krijgt een eigen zin. "Er ging iets mis" laat je
134 raden welke van de twee kanten van de afspraak ontbreekt, en dat
135 is precies wat je moet weten om het op te lossen. %>
136 <p><%= t('mig.e_' + haalVerslag.error) !== 'mig.e_' + haalVerslag.error
137 ? t('mig.e_' + haalVerslag.error) : (haalVerslag.melding || haalVerslag.error) %></p>
138 <% if (haalVerslag.error === 'not_moved_here' && haalVerslag.movedTo) { %>
139 <p class="form-hint"><%= t('mig.e_points_at') %> <code><%= haalVerslag.movedTo %></code></p>
140 <% } %>
141 <% } else { %>
142 <h3><%= t('mig.pull_done') %></h3>
143 <ul class="mig-counts">
144 <li><strong><%= haalVerslag.posts %></strong> <%= t('mig.r_imported') %></li>
145 <% if (haalVerslag.overgeslagen) { %><li><strong><%= haalVerslag.overgeslagen %></strong> <%= t('mig.r_skipped') %></li><% } %>
146 <% if (haalVerslag.media) { %><li><strong><%= haalVerslag.media %></strong> <%= t('mig.r_media') %></li><% } %>
147 <% if (haalVerslag.blocks) { %><li><strong><%= haalVerslag.blocks %></strong> <%= t('mig.r_blocks') %></li><% } %>
148 <% if (haalVerslag.tracksBinnen) { %><li><strong><%= haalVerslag.tracksBinnen %></strong> <%= t('mig.c_tracks') %></li><% } %>
149 <%# Aangevuld telt apart van nieuw. Een tweede ronde die "0 erbij"
150 meldt terwijl hij drie nummers compleet maakte, leest als niets
151 gedaan. %>
152 <% if (haalVerslag.tracksBijgewerkt) { %><li><strong><%= haalVerslag.tracksBijgewerkt %></strong> <%= t('mig.r_tracks_updated') %></li><% } %>
153 <% if (haalVerslag.postsBijgewerkt) { %><li><strong><%= haalVerslag.postsBijgewerkt %></strong> <%= t('mig.r_posts_updated') %></li><% } %>
154 <% if (haalVerslag.linksBijgetrokken) { %><li><strong><%= haalVerslag.linksBijgetrokken %></strong> <%= t('mig.r_links_fixed') %></li><% } %>
155 <% if (haalVerslag.playlistsBinnen) { %><li><strong><%= haalVerslag.playlistsBinnen %></strong> <%= t('mig.c_playlists') %></li><% } %>
156 </ul>
157 <% if (haalVerslag.tracksMislukt) { %>
158 <p class="alert alert-error"><%= t('mig.r_tracks_missing', { n: haalVerslag.tracksMislukt }) %></p>
159 <% } %>
160 <% } %>
161 <% if (haalVerslag.waarschuwingen && haalVerslag.waarschuwingen.length) { %>
162 <ul class="mig-warnlist">
163 <% haalVerslag.waarschuwingen.slice(0, 6).forEach(function (w) { %><li><%= w %></li><% }); %>
164 </ul>
165 <% } %>
166 </div>
167 <% } %>
168
169 <form method="post" action="/admin/migrate/pull">
170 <label for="mig-bron"><%= t('mig.pull_source') %></label>
171 <input type="url" id="mig-bron" name="bron" value="<%= bron || '' %>"
172 placeholder="https://oude-klonkt.nl/ap/users/jij" class="mig-input">
173 <p class="form-hint"><%= t('mig.pull_source_hint') %></p>
174 <button type="submit" class="btn"><%= t('mig.pull_btn') %></button>
175 </form>
176
177 <% if (mig && (mig.total || mig.moves)) { %>
178 <p class="form-hint mig-state">
179 <%= t('mig.state', { n: mig.total }) %>
180 <%= mig.complete ? t('mig.state_done') : t('mig.state_busy') %>
181 </p>
182 <% } %>
183 </section>
184
185 <%# ── Importeren ─────────────────────────────────────────────── %>
186 <section class="mig-card">
187 <h2><%= t('mig.import_title') %></h2>
188 <p class="form-hint"><%= t('mig.import_hint') %></p>
189
190 <% if (verslag) { %>
191 <div class="mig-report<%= verslag.echt ? ' is-done' : '' %>">
192 <h3><%= verslag.echt ? t('mig.r_done') : t('mig.r_dry') %></h3>
193 <p class="form-hint"><%= verslag.bestand %> &middot; <%= mb(verslag.bytes) %></p>
194 <ul class="mig-counts">
195 <li><strong><%= verslag.posts %></strong> <%= verslag.echt ? t('mig.r_imported') : t('mig.r_would') %></li>
196 <li><strong><%= verslag.overgeslagen %></strong> <%= t('mig.r_skipped') %></li>
197 <% if (verslag.overschreven) { %><li><strong><%= verslag.overschreven %></strong> <%= t('mig.r_overwritten') %></li><% } %>
198 <% if (verslag.mediaMissing) { %><li><strong><%= verslag.mediaMissing %></strong> <%= t('mig.r_media_missing') %></li><% } %>
199 <% if (verslag.media) { %><li><strong><%= verslag.media %></strong> <%= t('mig.r_media') %></li><% } %>
200 <%# Ook hier: muziek apart. Zonder deze twee regels zie je aan de
201 ontvangende kant net zo min of je bibliotheek is aangekomen. %>
202 <% if (verslag.tracks) { %><li><strong><%= verslag.tracks %></strong> <%= t('mig.c_tracks') %></li><% } %>
203 <% if (verslag.playlists) { %><li><strong><%= verslag.playlists %></strong> <%= t('mig.c_playlists') %></li><% } %>
204 <% if (verslag.linksBijgetrokken) { %><li><strong><%= verslag.linksBijgetrokken %></strong> <%= t('mig.r_links_fixed') %></li><% } %>
205 </ul>
206 <% if (verslag.tracksMissing) { %>
207 <p class="alert alert-error"><%= t('mig.r_tracks_missing', { n: verslag.tracksMissing }) %></p>
208 <% } %>
209 <% if (verslag.waarschuwingen && verslag.waarschuwingen.length) { %>
210 <ul class="mig-warnlist">
211 <% verslag.waarschuwingen.slice(0, 6).forEach(function (w) { %><li><%= w %></li><% }); %>
212 </ul>
213 <% } %>
214 <% if (verslag.idsBehouden === false) { %>
215 <%# Dit is de belangrijkste regel van het hele verslag: komt het archief
216 van een ANDER adres, dan krijgen de posts nieuwe id's en zijn het
217 nieuwe objecten voor de fediverse. %>
218 <p class="alert alert-error"><%= t('mig.r_new_ids') %></p>
219 <% } %>
220
221 <% if (!verslag.echt && verslag.posts > 0) { %>
222 <form method="post" action="/admin/migrate/import" enctype="multipart/form-data" class="mig-confirm">
223 <p class="form-hint"><%= t('mig.r_confirm_hint') %></p>
224 <label for="mig-file2"><%= t('mig.file_label') %></label>
225 <input type="file" id="mig-file2" name="archief" accept=".zip,application/zip" required>
226 <input type="hidden" name="echt" value="1">
227 <% if (verslag.overschrijf) { %><input type="hidden" name="overschrijf" value="1"><% } %>
228 <button type="submit" class="btn btn-primary"><%= t('mig.r_confirm_btn') %></button>
229 </form>
230 <% } %>
231 </div>
232 <% } %>
233
234 <form method="post" action="/admin/migrate/import" enctype="multipart/form-data">
235 <label for="mig-file"><%= t('mig.file_label') %></label>
236 <input type="file" id="mig-file" name="archief" accept=".zip,application/zip" required>
237
238 <label class="mig-check">
239 <input type="checkbox" name="overschrijf" value="1">
240 <%= t('mig.overwrite_label') %>
241 </label>
242 <p class="form-hint mig-warn"><%= t('mig.overwrite_hint') %></p>
243
244 <button type="submit" class="btn"><%= t('mig.check_btn') %></button>
245 <p class="form-hint"><%= t('mig.check_hint') %></p>
246 </form>
247 </section>
248
249 <%# ── De verhuizing aankondigen (FEP-7628 Move) ──────────────── %>
250 <%# ONDERAAN, en met een rode knop. Dit is de enige knop op deze pagina die
251 de fediverse in gaat en niet terug te draaien is: je volgers verhuizen
252 mee en dit account gaat op slot. Alles hierboven kun je overdoen. %>
253 <section class="mig-card mig-card-danger">
254 <h2><%= t('mig.move_title') %></h2>
255 <p class="form-hint"><%= t('mig.move_hint') %></p>
256 <% if (movedTo) { %>
257 <p class="alert alert-error"><%= t('mig.move_done') %> <code><%= movedTo %></code></p>
258 <% } else { %>
259 <form method="post" action="/admin/sites/<%= site.slug %>/move"
260 onsubmit="return confirm('<%= t('mig.move_confirm') %>');">
261 <input type="hidden" name="next" value="/admin/migrate">
262 <label for="mig-move"><%= t('mig.move_label') %></label>
263 <input type="text" id="mig-move" name="move_target" class="mig-input"
264 placeholder="@nieuw@andere-server.nl" required>
265 <p class="form-hint mig-warn"><%= t('mig.move_warn') %></p>
266 <button type="submit" class="btn btn-danger"><%= t('mig.move_btn') %></button>
267 </form>
268 <% } %>
269 </section>
270
271 <%# ── Wie je volgt ────────────────────────────────────────────── %>
272 <%# Stond op Connect, in een <details> zonder een greintje opmaak: labels als
273 losse tekst naast hun invoerveld, een textarea van vijf regels breed. Hier
274 krijgt hij de kaartopmaak van deze pagina, en hij hoort hier ook: je
275 volglijst meenemen is een migratie-optie. %>
276 <section class="mig-card">
277 <h2><%= t('mig.follows_title') %></h2>
278 <p class="form-hint"><%= t('tl.move_hint') %></p>
279 <p><a class="btn" href="/news/following.csv" download>&#11015; <%= t('tl.move_export') %></a></p>
280
281 <form method="post" action="/news/following/import" enctype="multipart/form-data">
282 <input type="hidden" name="next" value="/admin/migrate">
283 <label for="mig-volg-bestand"><%= t('tl.move_import_file') %></label>
284 <input type="file" id="mig-volg-bestand" name="csvfile" accept=".csv,text/csv,text/plain">
285
286 <label for="mig-volg-csv"><%= t('tl.move_import_lbl') %></label>
287 <textarea id="mig-volg-csv" name="csv" rows="5" spellcheck="false" class="mig-input"
288 placeholder="Account address,Show boosts,Notify on new posts,Languages,Featured"></textarea>
289 <p class="form-hint"><%= t('mig.follows_note') %></p>
290
291 <button type="submit" class="btn btn-primary"><%= t('tl.move_import') %></button>
292 </form>
293 </section>
294</div>
295
296<style>
297 .mig-wrap { max-width: 46rem; }
298 .mig-lead { color: var(--sub); margin-bottom: 1.5rem; }
299 .mig-card { border: 1px solid var(--rule); border-radius: 12px; padding: 1.25rem 1.4rem; margin-bottom: 1.25rem; }
300 .mig-card h2 { margin: 0 0 .35rem; font-size: 1.1rem; }
301 .mig-counts { list-style: none; padding: 0; margin: .9rem 0; display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; }
302 .mig-counts li { color: var(--sub); font-size: .94rem; }
303 .mig-counts strong { color: var(--ink); font-size: 1.05rem; }
304 .mig-card label { display: block; margin: .9rem 0 .35rem; font-weight: 600; font-size: .92rem; }
305 .mig-card input[type="file"] { display: block; margin-bottom: .6rem; }
306 .mig-check { display: flex; align-items: center; gap: .5rem; font-weight: 400 !important; }
307 .mig-input { width: 100%; max-width: 34rem; padding: .5rem .6rem; border: 1px solid var(--rule);
308 border-radius: 8px; background: transparent; color: var(--ink); font-size: .95rem; }
309 .mig-state { margin-top: .9rem; }
310 .mig-report code { word-break: break-all; font-size: .88rem; }
311 .mig-warn { color: var(--accent); }
312 .mig-plan { background: color-mix(in srgb, var(--ink, #000) 3%, transparent); }
313 .mig-steps { margin: 1rem 0 0; padding-left: 1.4rem; display: flex; flex-direction: column; gap: .7rem; }
314 .mig-steps li { color: var(--ink); }
315 .mig-steps li em { display: block; color: var(--sub); font-style: normal; font-size: .9rem; margin-top: .15rem; }
316 .mig-steps li.is-done > strong { text-decoration: line-through; opacity: .6; }
317 .mig-steps li.is-done::marker { content: '✓ '; }
318 .mig-steps li.mig-step-later { opacity: .8; }
319 .mig-waar { font-size: .8rem; padding: .05rem .4rem; border: 1px solid var(--rule); border-radius: 999px;
320 color: var(--sub); margin-left: .4rem; white-space: nowrap; }
321 .mig-card-danger { border-color: color-mix(in srgb, var(--accent, #c33) 45%, var(--rule)); }
322 textarea.mig-input { font-family: inherit; resize: vertical; }
323 .mig-report { border-left: 3px solid var(--accent); padding: .8rem 1rem; margin-bottom: 1.2rem;
324 background: color-mix(in srgb, var(--ink, #000) 4%, transparent); border-radius: 0 8px 8px 0; }
325 .mig-report.is-done { border-left-color: #3fa843; }
326 .mig-report h3 { margin: 0 0 .3rem; font-size: 1rem; }
327 .mig-warnlist { margin: .5rem 0; padding-left: 1.2rem; color: var(--accent); font-size: .9rem; }
328 .mig-confirm { margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--rule); }
329</style>
Note: See TracBrowser for help on using the repository browser.