estela 0.2.2 → 0.2.4
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/README.md +33 -0
- package/dist/cli.js +121 -2
- package/dist/cloud/client.d.ts +2 -0
- package/dist/cloud/client.js +21 -27
- package/dist/db/store.d.ts +2 -0
- package/dist/db/store.js +5 -0
- package/dist/export/panel.d.ts +69 -0
- package/dist/export/panel.js +47 -10
- package/dist/i18n/en.js +29 -0
- package/dist/offline.d.ts +10 -0
- package/dist/offline.js +16 -0
- package/dist/publish.d.ts +38 -0
- package/dist/publish.js +101 -20
- package/dist/rate-history.d.ts +63 -0
- package/dist/rate-history.js +193 -0
- package/dist/server.js +18 -7
- package/dist/statusline-cache.d.ts +10 -0
- package/dist/statusline-run.js +8 -0
- package/dist/updateCheck.d.ts +6 -1
- package/dist/updateCheck.js +25 -4
- package/package.json +1 -1
- package/web/app.js +77 -38
- package/web/i18n.js +16 -0
package/web/app.js
CHANGED
|
@@ -1213,6 +1213,8 @@ function wireProjects() {
|
|
|
1213
1213
|
});
|
|
1214
1214
|
});
|
|
1215
1215
|
|
|
1216
|
+
// Publicar va en dos pasos, como en la terminal: primero lo que va a quedar
|
|
1217
|
+
// público (autores, ramas, ficheros, correos), y solo al confirmar se sube.
|
|
1216
1218
|
document.querySelectorAll(".share-btn").forEach((btn) => {
|
|
1217
1219
|
btn.addEventListener("click", async () => {
|
|
1218
1220
|
const card = btn.closest(".pcard");
|
|
@@ -1220,54 +1222,91 @@ function wireProjects() {
|
|
|
1220
1222
|
const out = card.querySelector(".share-out");
|
|
1221
1223
|
btn.disabled = true;
|
|
1222
1224
|
try {
|
|
1223
|
-
// El token ya vive en la base de datos local (una fila por proyecto,
|
|
1224
|
-
// se lee de state.projects.publications): guardarlo también en
|
|
1225
|
-
// localStorage sería una segunda copia que puede desincronizarse de
|
|
1226
|
-
// la real, y lo hizo — un token de una prueba vieja en el navegador
|
|
1227
|
-
// pisó el que de verdad estaba publicado.
|
|
1228
1225
|
const known = state.projects?.publications?.find((p) => p.projectId === projectId);
|
|
1229
|
-
const
|
|
1226
|
+
const { summary: s } = await api("/api/publish", {
|
|
1230
1227
|
method: "POST",
|
|
1231
|
-
body: JSON.stringify({ projectId, token: known?.token || "" }),
|
|
1228
|
+
body: JSON.stringify({ projectId, token: known?.token || "", preview: true }),
|
|
1232
1229
|
});
|
|
1233
|
-
|
|
1230
|
+
const list = (items) => items.length ? items.map(esc).join(", ") : "—";
|
|
1231
|
+
const row = (label, value) => '<p class="share-line">' + label + ' ' + value + '</p>';
|
|
1234
1232
|
out.hidden = false;
|
|
1235
1233
|
out.innerHTML =
|
|
1236
|
-
'<p class="share-line"><b>' +
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
const out3 = card2?.querySelector(".share-out");
|
|
1251
|
-
if (out3) { out3.hidden = false; out3.innerHTML = recien; }
|
|
1234
|
+
'<p class="share-line"><b>' + tr("publish.preview.title") + '</b></p>' +
|
|
1235
|
+
row(tr("publish.preview.project"), esc(s.project) + " · " + esc(s.client)) +
|
|
1236
|
+
row(tr("publish.preview.authors"), list(s.authors)) +
|
|
1237
|
+
row(tr("publish.preview.branches"), list(s.branches)) +
|
|
1238
|
+
row(tr("publish.preview.files"), list(s.files)) +
|
|
1239
|
+
row(tr("publish.preview.clients"), list(s.clients)) +
|
|
1240
|
+
'<p class="share-warn">' + tr("publish.noPassword") + '</p>' +
|
|
1241
|
+
'<p><button type="button" class="chip share-confirm">' + tr("publish.preview.confirm") + '</button> ' +
|
|
1242
|
+
'<button type="button" class="chip share-cancel">' + tr("publish.preview.cancel") + '</button></p>';
|
|
1243
|
+
out.querySelector(".share-cancel").addEventListener("click", () => { out.hidden = true; out.innerHTML = ""; });
|
|
1244
|
+
out.querySelector(".share-confirm").addEventListener("click", (e) => {
|
|
1245
|
+
e.currentTarget.disabled = true;
|
|
1246
|
+
publishNow(card, btn);
|
|
1247
|
+
});
|
|
1252
1248
|
} catch (error) {
|
|
1253
|
-
|
|
1254
|
-
// "Sin cuenta" no es un error cualquiera: se enseña con el comando
|
|
1255
|
-
// exacto para resolverlo, no como un aviso genérico que hay que
|
|
1256
|
-
// interpretar. `needsLogin` viaja en el cuerpo desde /api/publish.
|
|
1257
|
-
if (error.body?.needsLogin) {
|
|
1258
|
-
out2.hidden = false;
|
|
1259
|
-
out2.innerHTML =
|
|
1260
|
-
'<p class="share-line"><b>' + tr("publish.needsLogin.title") + '</b></p>' +
|
|
1261
|
-
'<p class="share-line">' + tr("publish.needsLogin.why") + '</p>' +
|
|
1262
|
-
'<code class="cmd">' + tr("publish.needsLogin.cmd") + '</code>' +
|
|
1263
|
-
'<p class="share-warn">' + tr("publish.needsLogin.once") + '</p>';
|
|
1264
|
-
} else {
|
|
1265
|
-
toast(error.message);
|
|
1266
|
-
}
|
|
1249
|
+
showPublishError(card, error);
|
|
1267
1250
|
} finally { btn.disabled = false; }
|
|
1268
1251
|
});
|
|
1269
1252
|
});
|
|
1270
1253
|
|
|
1254
|
+
async function publishNow(card, btn) {
|
|
1255
|
+
const projectId = card.dataset.project;
|
|
1256
|
+
const out = card.querySelector(".share-out");
|
|
1257
|
+
btn.disabled = true;
|
|
1258
|
+
try {
|
|
1259
|
+
// El token ya vive en la base de datos local (una fila por proyecto,
|
|
1260
|
+
// se lee de state.projects.publications): guardarlo también en
|
|
1261
|
+
// localStorage sería una segunda copia que puede desincronizarse de
|
|
1262
|
+
// la real, y lo hizo — un token de una prueba vieja en el navegador
|
|
1263
|
+
// pisó el que de verdad estaba publicado.
|
|
1264
|
+
const known = state.projects?.publications?.find((p) => p.projectId === projectId);
|
|
1265
|
+
const r = await api("/api/publish", {
|
|
1266
|
+
method: "POST",
|
|
1267
|
+
body: JSON.stringify({ projectId, token: known?.token || "" }),
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1270
|
+
out.hidden = false;
|
|
1271
|
+
out.innerHTML =
|
|
1272
|
+
'<p class="share-line"><b>' + (r.adopted ? tr("publish.linked") : tr("publish.published")) +
|
|
1273
|
+
'</b></p>' +
|
|
1274
|
+
'<p class="share-line">' + tr("publish.link") + ' <code>' + esc(r.url) + '</code></p>' +
|
|
1275
|
+
'<p class="share-warn">' + tr("publish.noPassword") + '</p>';
|
|
1276
|
+
toast(r.adopted ? tr("toast.linkedToAccount") : tr("publish.published"));
|
|
1277
|
+
|
|
1278
|
+
// Publicar pone a cero los "bloques nuevos desde que lo publicaste",
|
|
1279
|
+
// pero ese número vive en `state`, que se quedaba con el valor de
|
|
1280
|
+
// antes: el aviso seguía ahí después de resolverlo, y solo se iba
|
|
1281
|
+
// recargando la página a mano. Se vuelve a pedir el estado y se
|
|
1282
|
+
// repinta, conservando el mensaje del enlace recién generado.
|
|
1283
|
+
const recien = out.innerHTML;
|
|
1284
|
+
await loadProjects();
|
|
1285
|
+
const card2 = document.querySelector(`.pcard[data-project="${CSS.escape(projectId)}"]`);
|
|
1286
|
+
const out3 = card2?.querySelector(".share-out");
|
|
1287
|
+
if (out3) { out3.hidden = false; out3.innerHTML = recien; }
|
|
1288
|
+
} catch (error) {
|
|
1289
|
+
showPublishError(card, error);
|
|
1290
|
+
} finally { btn.disabled = false; }
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
function showPublishError(card, error) {
|
|
1294
|
+
const out2 = card.querySelector(".share-out");
|
|
1295
|
+
// "Sin cuenta" no es un error cualquiera: se enseña con el comando
|
|
1296
|
+
// exacto para resolverlo, no como un aviso genérico que hay que
|
|
1297
|
+
// interpretar. `needsLogin` viaja en el cuerpo desde /api/publish.
|
|
1298
|
+
if (error.body?.needsLogin) {
|
|
1299
|
+
out2.hidden = false;
|
|
1300
|
+
out2.innerHTML =
|
|
1301
|
+
'<p class="share-line"><b>' + tr("publish.needsLogin.title") + '</b></p>' +
|
|
1302
|
+
'<p class="share-line">' + tr("publish.needsLogin.why") + '</p>' +
|
|
1303
|
+
'<code class="cmd">' + tr("publish.needsLogin.cmd") + '</code>' +
|
|
1304
|
+
'<p class="share-warn">' + tr("publish.needsLogin.once") + '</p>';
|
|
1305
|
+
} else {
|
|
1306
|
+
toast(error.message);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1271
1310
|
document.querySelectorAll(".rateform").forEach((form) => {
|
|
1272
1311
|
form.addEventListener("submit", async (e) => {
|
|
1273
1312
|
e.preventDefault();
|
package/web/i18n.js
CHANGED
|
@@ -280,6 +280,14 @@
|
|
|
280
280
|
"publish.published": "Panel publicado",
|
|
281
281
|
"publish.link": "Enlace:",
|
|
282
282
|
"publish.noPassword": "Quien tenga el enlace, entra: no hay contraseña.",
|
|
283
|
+
"publish.preview.title": "Esto va a quedar público. Quien tenga el enlace lo ve todo:",
|
|
284
|
+
"publish.preview.project": "Proyecto:",
|
|
285
|
+
"publish.preview.authors": "Autores:",
|
|
286
|
+
"publish.preview.branches": "Ramas:",
|
|
287
|
+
"publish.preview.files": "Ficheros:",
|
|
288
|
+
"publish.preview.clients": "Clientes:",
|
|
289
|
+
"publish.preview.confirm": "Publicar",
|
|
290
|
+
"publish.preview.cancel": "Cancelar",
|
|
283
291
|
"publish.needsLogin.title": "Hace falta vincular una cuenta",
|
|
284
292
|
"publish.needsLogin.why": "Publicar aloja el panel en getestela.dev, y eso exige sesión:",
|
|
285
293
|
"publish.needsLogin.cmd": "estela login --email tu@correo.com",
|
|
@@ -577,6 +585,14 @@
|
|
|
577
585
|
"publish.published": "Panel published",
|
|
578
586
|
"publish.link": "Link:",
|
|
579
587
|
"publish.noPassword": "Anyone with the link can get in: there's no password.",
|
|
588
|
+
"publish.preview.title": "This will become public. Anyone with the link sees all of it:",
|
|
589
|
+
"publish.preview.project": "Project:",
|
|
590
|
+
"publish.preview.authors": "Authors:",
|
|
591
|
+
"publish.preview.branches": "Branches:",
|
|
592
|
+
"publish.preview.files": "Files:",
|
|
593
|
+
"publish.preview.clients": "Clients:",
|
|
594
|
+
"publish.preview.confirm": "Publish",
|
|
595
|
+
"publish.preview.cancel": "Cancel",
|
|
580
596
|
"publish.needsLogin.title": "You need to link an account",
|
|
581
597
|
"publish.needsLogin.why": "Publishing hosts the panel on getestela.dev, which requires signing in:",
|
|
582
598
|
"publish.needsLogin.cmd": "estela login --email you@example.com",
|