dsh-manage-session 0.3.3 → 0.5.1
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/CHANGELOG.ja.md +242 -188
- package/CHANGELOG.ko.md +242 -189
- package/CHANGELOG.md +341 -261
- package/INSTALL.ja.md +179 -164
- package/INSTALL.ko.md +179 -164
- package/INSTALL.md +179 -164
- package/INSTALL.zh.md +179 -164
- package/LICENSE +21 -21
- package/README.de.md +120 -0
- package/README.en.md +12 -0
- package/README.es.md +120 -0
- package/README.fr.md +120 -0
- package/README.it.md +120 -0
- package/README.ja.md +12 -0
- package/README.ko.md +12 -0
- package/README.md +14 -0
- package/README.ru.md +120 -0
- package/cordis.patch.yml +11 -11
- package/dsh.plugin.json +22 -22
- package/lib/client.js +623 -35
- package/lib/index.d.ts +123 -8
- package/lib/index.js +1147 -815
- package/package.json +125 -122
- package/src/client/card.tsx +9 -12
- package/src/client/health-panel.tsx +51 -0
- package/src/client/history-panel.tsx +319 -319
- package/src/client/host-api.ts +14 -1
- package/src/client/index.ts +150 -30
- package/src/client/locales.ts +491 -1
- package/src/config.ts +33 -33
- package/src/host/health/attribution.ts +118 -118
- package/src/host/health/gates.ts +4 -1
- package/src/host/health/lossless.ts +128 -128
- package/src/host/health/source-kind.ts +350 -0
- package/src/host/history/archive-source.ts +202 -202
- package/src/host/history/archive.ts +194 -191
- package/src/host/history/purge.ts +370 -323
- package/src/index.ts +56 -48
package/lib/client.js
CHANGED
|
@@ -31,6 +31,7 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
"card.health.desc": "体检 → 处方 → 出院。关闭后不注册体检接口、不渲染该页签。",
|
|
32
32
|
"card.readonly": "当前会话无法修改设置(只读挂载)。",
|
|
33
33
|
"card.unavailable": "设置服务不可用,无法读取配置。",
|
|
34
|
+
"family.title": "起子插件设置",
|
|
34
35
|
"panel.title": "会话管家",
|
|
35
36
|
"panel.tab.history": "养老院",
|
|
36
37
|
"panel.tab.health": "体检",
|
|
@@ -75,6 +76,7 @@ window.__ModuleLoader__.load({
|
|
|
75
76
|
"health.gate.projection-cache": "投影缓存",
|
|
76
77
|
"health.gate.lossless-json": "无损 JSON",
|
|
77
78
|
"health.gate.cold-read": "可接续性",
|
|
79
|
+
"health.gate.source-kind": "插件署名",
|
|
78
80
|
"health.attribution": "归属",
|
|
79
81
|
"health.field": "字段",
|
|
80
82
|
"health.unknownOwner": "归属未知",
|
|
@@ -83,6 +85,11 @@ window.__ModuleLoader__.load({
|
|
|
83
85
|
"health.phase.discharge": "③ 出院",
|
|
84
86
|
"health.repair": "执行可逆处置",
|
|
85
87
|
"health.repairing": "处置中…",
|
|
88
|
+
"health.sourceMigrate": "转换旧署名",
|
|
89
|
+
"health.sourceMigrating": "转换中…",
|
|
90
|
+
"health.sourceMigrated": "已转换 {n} 行旧署名(备份:{backup})",
|
|
91
|
+
"health.sourceMigrateNone": "没有需要转换的旧署名行",
|
|
92
|
+
"health.sourceMigrateFail": "转换失败:{error}",
|
|
86
93
|
"health.before": "处置前",
|
|
87
94
|
"health.after": "处置后",
|
|
88
95
|
"health.quarantined": "已隔离投影缓存记录(重启 DSH 后重折叠)",
|
|
@@ -111,6 +118,7 @@ window.__ModuleLoader__.load({
|
|
|
111
118
|
"card.health.desc": "Checkup → Prescription → Discharge. When off, health routes and the tab are gone.",
|
|
112
119
|
"card.readonly": "This session cannot edit settings (read-only mount).",
|
|
113
120
|
"card.unavailable": "Settings service unavailable; configuration cannot be read.",
|
|
121
|
+
"family.title": "Screwdriver plugin settings",
|
|
114
122
|
"panel.title": "Session Steward",
|
|
115
123
|
"panel.tab.history": "Retirement Home",
|
|
116
124
|
"panel.tab.health": "Checkup",
|
|
@@ -155,6 +163,7 @@ window.__ModuleLoader__.load({
|
|
|
155
163
|
"health.gate.projection-cache": "Projection cache",
|
|
156
164
|
"health.gate.lossless-json": "Lossless JSON",
|
|
157
165
|
"health.gate.cold-read": "Continuability",
|
|
166
|
+
"health.gate.source-kind": "Plugin signature",
|
|
158
167
|
"health.attribution": "Owner",
|
|
159
168
|
"health.field": "Field",
|
|
160
169
|
"health.unknownOwner": "owner unknown",
|
|
@@ -163,6 +172,11 @@ window.__ModuleLoader__.load({
|
|
|
163
172
|
"health.phase.discharge": "3) Discharge",
|
|
164
173
|
"health.repair": "Apply reversible repair",
|
|
165
174
|
"health.repairing": "Repairing…",
|
|
175
|
+
"health.sourceMigrate": "Migrate legacy signatures",
|
|
176
|
+
"health.sourceMigrating": "Migrating…",
|
|
177
|
+
"health.sourceMigrated": "Migrated {n} legacy signature rows (backup: {backup})",
|
|
178
|
+
"health.sourceMigrateNone": "No legacy signature rows to migrate",
|
|
179
|
+
"health.sourceMigrateFail": "Migration failed: {error}",
|
|
166
180
|
"health.before": "Before",
|
|
167
181
|
"health.after": "After",
|
|
168
182
|
"health.quarantined": "Projection cache quarantined (refolds after a DSH restart)",
|
|
@@ -179,6 +193,441 @@ window.__ModuleLoader__.load({
|
|
|
179
193
|
"health.ago.hours": "{n} h ago",
|
|
180
194
|
"health.ago.days": "{n} d ago"
|
|
181
195
|
};
|
|
196
|
+
/** Dictionnaire français (mêmes clés). */
|
|
197
|
+
const fr = {
|
|
198
|
+
"card.title": "Session Steward",
|
|
199
|
+
"card.desc": "Fichiers d’historique · Bilan de santé",
|
|
200
|
+
"card.enabled": "Activer Session Steward",
|
|
201
|
+
"card.enabled.desc": "Désactivé, aucun service n’est enregistré et l’entrée de la barre latérale disparaît.",
|
|
202
|
+
"card.history": "Fichiers d’historique des sessions",
|
|
203
|
+
"card.history.desc": "Consultation et nettoyage des archives (Maison de retraite). Désactivé, les routes d’historique et l’onglet disparaissent.",
|
|
204
|
+
"card.health": "Bilan de santé",
|
|
205
|
+
"card.health.desc": "Bilan → Ordonnance → Sortie. Désactivé, les routes de santé et l’onglet disparaissent.",
|
|
206
|
+
"card.readonly": "Cette session ne peut pas modifier les réglages (montage en lecture seule).",
|
|
207
|
+
"card.unavailable": "Service de réglages indisponible ; impossible de lire la configuration.",
|
|
208
|
+
"family.title": "Réglages des plugins Screwdriver",
|
|
209
|
+
"panel.title": "Session Steward",
|
|
210
|
+
"panel.tab.history": "Maison de retraite",
|
|
211
|
+
"panel.tab.health": "Bilan",
|
|
212
|
+
"panel.close": "Fermer",
|
|
213
|
+
"panel.untitled": "(sans titre)",
|
|
214
|
+
"history.loading": "Chargement des sessions archivées…",
|
|
215
|
+
"history.empty": "L’ensemble d’archives est vide.",
|
|
216
|
+
"history.edit": "Modifier",
|
|
217
|
+
"history.done": "Terminé",
|
|
218
|
+
"history.selectAll": "Tout sélectionner",
|
|
219
|
+
"history.unselectAll": "Tout désélectionner",
|
|
220
|
+
"history.unarchive": "Annuler l’archivage ({n})",
|
|
221
|
+
"history.unarchiving": "Annulation…",
|
|
222
|
+
"history.purge": "Purger les fichiers d’archive ({n}) · libère {size}",
|
|
223
|
+
"history.purging": "Purge…",
|
|
224
|
+
"history.editingHint": "Mode édition : cochez des sessions puis choisissez — « Annuler l’archivage » les retire seulement du tableau d’archives officiel (réversible ; elles reviennent dans la barre latérale après un redémarrage) ; « Purger les fichiers d’archive » supprime réellement la transcription et le cache de projection du disque (irréversible).",
|
|
225
|
+
"history.restartHint": "{removed} id retiré(s) du tableau d’archives ({remaining} restant(s)). **Redémarrez DSH maintenant** : tant que l’hôte n’est pas quitté, toute modification d’archive ou d’espace de travail réécrit tout l’instantané mémoire dans le fichier et annule cette opération.",
|
|
226
|
+
"history.pendingRestart": "{n} id archivé(s) sont encore vivants dans la mémoire de l’hôte : la liste suit le fichier de stockage (ils y ont déjà disparu), mais leurs sessions restent masquées dans la barre latérale jusqu’au redémarrage de DSH.",
|
|
227
|
+
"history.count": "{n} au total · {size} sur disque",
|
|
228
|
+
"history.size": "transcription {t} · cache {c}",
|
|
229
|
+
"history.sizeUnknown": "aucune entité sur disque",
|
|
230
|
+
"history.source.registry": "Source : registre d’archives de l’hôte",
|
|
231
|
+
"history.source.storage-file": "Source : fichier de stockage",
|
|
232
|
+
"history.source.none": "Archives illisibles depuis les deux sources",
|
|
233
|
+
"history.confirmUnarchive": "Annuler l’archivage de ces {n} session(s) ?\n\n{summary}\n\nSeul le tableau d’archives est modifié (sauvegarde automatique) ; rien sur le disque n’est touché. Après un redémarrage de DSH, ces sessions retrouvent leurs espaces de travail.",
|
|
234
|
+
"history.confirmPurge": "Purger les fichiers sur disque de ces {n} session(s) archivée(s) ?\n\n{summary}\n\nEnviron {size} seront libérés.\nCeci supprime : le répertoire des transcriptions (copies au vieux format comprises) et le cache de projection par session, et les retire du tableau d’archives et des tables d’appartenance aux espaces de travail.\n\n**Opération irréversible — les sessions seront définitivement perdues.**",
|
|
235
|
+
"history.purgeResult": "{purged} session(s) archivée(s) purgée(s), {size} libéré(s). Redémarrez DSH pour qu’elles disparaissent totalement.",
|
|
236
|
+
"history.purgePartial": "{purged} purgée(s), {size} libéré(s) ; {failed} échec(s) (détails ci-dessous).",
|
|
237
|
+
"history.purgeFailures": "Détail des échecs",
|
|
238
|
+
"health.scan": "Lancer le bilan",
|
|
239
|
+
"health.scanning": "Bilan en cours…",
|
|
240
|
+
"health.progress": "{done}/{total} · {sec}s écoulées",
|
|
241
|
+
"health.empty": "Aucune session problématique trouvée.",
|
|
242
|
+
"health.clean": "Tous les contrôles sont passés.",
|
|
243
|
+
"health.level.ok": "ok",
|
|
244
|
+
"health.level.warn": "alerte",
|
|
245
|
+
"health.level.skipped": "Non vérifié",
|
|
246
|
+
"health.level.fail": "échec",
|
|
247
|
+
"health.priority.high": "Prioritaire",
|
|
248
|
+
"health.gate.generation": "Artefact de génération",
|
|
249
|
+
"health.gate.log-integrity": "Intégrité des journaux",
|
|
250
|
+
"health.gate.projection-cache": "Cache de projection",
|
|
251
|
+
"health.gate.lossless-json": "JSON sans perte",
|
|
252
|
+
"health.gate.cold-read": "Reprise",
|
|
253
|
+
"health.gate.source-kind": "Signature du plugin",
|
|
254
|
+
"health.attribution": "Propriétaire",
|
|
255
|
+
"health.field": "Champ",
|
|
256
|
+
"health.unknownOwner": "propriétaire inconnu",
|
|
257
|
+
"health.phase.checkup": "1) Bilan",
|
|
258
|
+
"health.phase.prescribe": "2) Ordonnance",
|
|
259
|
+
"health.phase.discharge": "3) Sortie",
|
|
260
|
+
"health.repair": "Appliquer la réparation réversible",
|
|
261
|
+
"health.repairing": "Réparation…",
|
|
262
|
+
"health.sourceMigrate": "Migrer les anciennes signatures",
|
|
263
|
+
"health.sourceMigrating": "Migration…",
|
|
264
|
+
"health.sourceMigrated": "{n} lignes d’anciennes signatures migrées (sauvegarde : {backup})",
|
|
265
|
+
"health.sourceMigrateNone": "Aucune ancienne signature à migrer",
|
|
266
|
+
"health.sourceMigrateFail": "Échec de la migration : {error}",
|
|
267
|
+
"health.before": "Avant",
|
|
268
|
+
"health.after": "Après",
|
|
269
|
+
"health.quarantined": "Cache de projection mis en quarantaine (se referme après un redémarrage de DSH)",
|
|
270
|
+
"health.commands": "Commandes",
|
|
271
|
+
"health.copy": "Copier",
|
|
272
|
+
"health.copied": "Copié",
|
|
273
|
+
"health.detail": "Détails",
|
|
274
|
+
"health.back": "Retour",
|
|
275
|
+
"health.cache.hint": "Résultat en cache · {ago}",
|
|
276
|
+
"health.cache.refresh": "Actualiser",
|
|
277
|
+
"health.cache.corpusChanged": "Corpus modifié ({was} → {now}) ; actualisation conseillée",
|
|
278
|
+
"health.ago.justNow": "à l’instant",
|
|
279
|
+
"health.ago.minutes": "il y a {n} min",
|
|
280
|
+
"health.ago.hours": "il y a {n} h",
|
|
281
|
+
"health.ago.days": "il y a {n} j"
|
|
282
|
+
};
|
|
283
|
+
/** Deutsches Wörterbuch (gleiche Schlüssel). */
|
|
284
|
+
const de = {
|
|
285
|
+
"card.title": "Session Steward",
|
|
286
|
+
"card.desc": "Verlaufsdateien · Gesundheitscheck",
|
|
287
|
+
"card.enabled": "Session Steward aktivieren",
|
|
288
|
+
"card.enabled.desc": "Bei Deaktivierung wird kein Dienst registriert und der Seitenleisten-Eintrag verschwindet.",
|
|
289
|
+
"card.history": "Sitzungsverlaufsdateien",
|
|
290
|
+
"card.history.desc": "Archiv durchsehen und aufräumen (Altersheim). Bei Deaktivierung bleiben Verlaufsrouten und Tab weg.",
|
|
291
|
+
"card.health": "Gesundheitscheck",
|
|
292
|
+
"card.health.desc": "Untersuchung → Verordnung → Entlassung. Bei Deaktivierung bleiben Health-Routen und Tab weg.",
|
|
293
|
+
"card.readonly": "Diese Sitzung kann die Einstellungen nicht ändern (schreibgeschützt eingebunden).",
|
|
294
|
+
"card.unavailable": "Einstellungsdienst nicht verfügbar; Konfiguration nicht lesbar.",
|
|
295
|
+
"family.title": "Screwdriver-Plugin-Einstellungen",
|
|
296
|
+
"panel.title": "Session Steward",
|
|
297
|
+
"panel.tab.history": "Altersheim",
|
|
298
|
+
"panel.tab.health": "Check",
|
|
299
|
+
"panel.close": "Schließen",
|
|
300
|
+
"panel.untitled": "(unbenannt)",
|
|
301
|
+
"history.loading": "Archivierte Sitzungen werden geladen…",
|
|
302
|
+
"history.empty": "Der Archivbestand ist leer.",
|
|
303
|
+
"history.edit": "Bearbeiten",
|
|
304
|
+
"history.done": "Fertig",
|
|
305
|
+
"history.selectAll": "Alle auswählen",
|
|
306
|
+
"history.unselectAll": "Auswahl aufheben",
|
|
307
|
+
"history.unarchive": "Archivstatus aufheben ({n})",
|
|
308
|
+
"history.unarchiving": "Wird aufgehoben…",
|
|
309
|
+
"history.purge": "Archivdateien löschen ({n}) · gibt {size} frei",
|
|
310
|
+
"history.purging": "Wird gelöscht…",
|
|
311
|
+
"history.editingHint": "Bearbeitungsmodus: Sitzungen ankreuzen, dann eine von zwei Wahlen treffen – „Archivstatus aufheben“ entfernt sie nur aus dem offiziellen Archiv-Array (umkehrbar; sie kehren nach einem Neustart in die Seitenleiste zurück); „Archivdateien löschen“ löscht Transkript und Projektionscache wirklich von der Platte (unumkehrbar).",
|
|
312
|
+
"history.restartHint": "{removed} ID(s) aus dem Archiv-Array entfernt ({remaining} übrig). **Jetzt DSH neu starten**: Bis der Host beendet ist, schreibt jede Archiv- oder Workspace-Änderung den gesamten Speicherzustand zurück in die Datei und macht dies rückgängig.",
|
|
313
|
+
"history.pendingRestart": "{n} archivierte ID(s) leben noch im Host-Speicher: Die Liste folgt der Speicherdatei (dort sind sie schon weg), doch ihre Sitzungen bleiben bis zum DSH-Neustart in der Seitenleiste verborgen.",
|
|
314
|
+
"history.count": "{n} insgesamt · {size} auf der Platte",
|
|
315
|
+
"history.size": "Transkript {t} · Cache {c}",
|
|
316
|
+
"history.sizeUnknown": "nichts auf der Platte",
|
|
317
|
+
"history.source.registry": "Quelle: Archiv-Registry des Hosts",
|
|
318
|
+
"history.source.storage-file": "Quelle: Speicherdatei",
|
|
319
|
+
"history.source.none": "Archivbestand aus beiden Quellen nicht lesbar",
|
|
320
|
+
"history.confirmUnarchive": "Archivstatus dieser {n} Sitzung(en) aufheben?\n\n{summary}\n\nNur das Archiv-Array wird geändert (automatisches Backup); auf der Platte wird nichts angefasst. Nach einem DSH-Neustart kehren diese Sitzungen in ihre Workspaces zurück.",
|
|
321
|
+
"history.confirmPurge": "Die Dateien auf der Platte dieser {n} archivierten Sitzung(en) endgültig löschen?\n\n{summary}\n\nEtwa {size} werden freigegeben.\nGelöscht werden: das Transkriptverzeichnis (einschließlich Kopien im alten Format) und der sitzungsweise Projektionscache, außerdem werden sie aus dem Archiv-Array und den Workspace-Zugehörigkeitstabellen entfernt.\n\n**Dies ist unumkehrbar – die Sitzungen sind unwiederbringlich verloren.**",
|
|
322
|
+
"history.purgeResult": "{purged} archivierte Sitzung(en) gelöscht, {size} freigegeben. DSH neu starten, damit sie ganz verschwinden.",
|
|
323
|
+
"history.purgePartial": "{purged} gelöscht, {size} freigegeben; {failed} fehlgeschlagen (Details unten).",
|
|
324
|
+
"history.purgeFailures": "Fehlerdetails",
|
|
325
|
+
"health.scan": "Check starten",
|
|
326
|
+
"health.scanning": "Läuft…",
|
|
327
|
+
"health.progress": "{done}/{total} · {sec}s verstrichen",
|
|
328
|
+
"health.empty": "Keine problematische Sitzung gefunden.",
|
|
329
|
+
"health.clean": "Alle Prüfungen bestanden.",
|
|
330
|
+
"health.level.ok": "ok",
|
|
331
|
+
"health.level.warn": "Warnung",
|
|
332
|
+
"health.level.skipped": "Nicht geprüft",
|
|
333
|
+
"health.level.fail": "Fehler",
|
|
334
|
+
"health.priority.high": "Priorität",
|
|
335
|
+
"health.gate.generation": "Generierungsartefakt",
|
|
336
|
+
"health.gate.log-integrity": "Log-Integrität",
|
|
337
|
+
"health.gate.projection-cache": "Projektionscache",
|
|
338
|
+
"health.gate.lossless-json": "Verlustfreies JSON",
|
|
339
|
+
"health.gate.cold-read": "Fortsetzbarkeit",
|
|
340
|
+
"health.gate.source-kind": "Plugin-Signatur",
|
|
341
|
+
"health.attribution": "Eigentümer",
|
|
342
|
+
"health.field": "Feld",
|
|
343
|
+
"health.unknownOwner": "Eigentümer unbekannt",
|
|
344
|
+
"health.phase.checkup": "1) Untersuchung",
|
|
345
|
+
"health.phase.prescribe": "2) Verordnung",
|
|
346
|
+
"health.phase.discharge": "3) Entlassung",
|
|
347
|
+
"health.repair": "Umkehrbare Reparatur anwenden",
|
|
348
|
+
"health.repairing": "Wird repariert…",
|
|
349
|
+
"health.sourceMigrate": "Alte Signaturen migrieren",
|
|
350
|
+
"health.sourceMigrating": "Wird migriert…",
|
|
351
|
+
"health.sourceMigrated": "{n} alte Signaturzeilen migriert (Backup: {backup})",
|
|
352
|
+
"health.sourceMigrateNone": "Keine alten Signaturzeilen zu migrieren",
|
|
353
|
+
"health.sourceMigrateFail": "Migration fehlgeschlagen: {error}",
|
|
354
|
+
"health.before": "Vorher",
|
|
355
|
+
"health.after": "Nachher",
|
|
356
|
+
"health.quarantined": "Projektionscache in Quarantäne (klappt nach einem DSH-Neustart wieder zu)",
|
|
357
|
+
"health.commands": "Befehle",
|
|
358
|
+
"health.copy": "Kopieren",
|
|
359
|
+
"health.copied": "Kopiert",
|
|
360
|
+
"health.detail": "Details",
|
|
361
|
+
"health.back": "Zurück",
|
|
362
|
+
"health.cache.hint": "Zwischengespeichertes Ergebnis · {ago}",
|
|
363
|
+
"health.cache.refresh": "Aktualisieren",
|
|
364
|
+
"health.cache.corpusChanged": "Korpus geändert ({was} → {now}); Aktualisierung empfohlen",
|
|
365
|
+
"health.ago.justNow": "gerade eben",
|
|
366
|
+
"health.ago.minutes": "vor {n} Min.",
|
|
367
|
+
"health.ago.hours": "vor {n} Std.",
|
|
368
|
+
"health.ago.days": "vor {n} T."
|
|
369
|
+
};
|
|
370
|
+
/** Dizionario italiano (stesse chiavi). */
|
|
371
|
+
const it = {
|
|
372
|
+
"card.title": "Session Steward",
|
|
373
|
+
"card.desc": "File di cronologia · Controllo salute",
|
|
374
|
+
"card.enabled": "Abilita Session Steward",
|
|
375
|
+
"card.enabled.desc": "Quando disattivato, nessun servizio viene registrato e la voce della barra laterale scompare.",
|
|
376
|
+
"card.history": "File di cronologia delle sessioni",
|
|
377
|
+
"card.history.desc": "Consultazione e pulizia dell’archivio (Casa di riposo). Quando disattivato, rotte della cronologia e scheda spariscono.",
|
|
378
|
+
"card.health": "Controllo salute",
|
|
379
|
+
"card.health.desc": "Visita → Prescrizione → Dimissione. Quando disattivato, rotte della salute e scheda spariscono.",
|
|
380
|
+
"card.readonly": "Questa sessione non può modificare le impostazioni (montaggio in sola lettura).",
|
|
381
|
+
"card.unavailable": "Servizio impostazioni non disponibile; impossibile leggere la configurazione.",
|
|
382
|
+
"family.title": "Impostazioni dei plugin Screwdriver",
|
|
383
|
+
"panel.title": "Session Steward",
|
|
384
|
+
"panel.tab.history": "Casa di riposo",
|
|
385
|
+
"panel.tab.health": "Visita",
|
|
386
|
+
"panel.close": "Chiudi",
|
|
387
|
+
"panel.untitled": "(senza titolo)",
|
|
388
|
+
"history.loading": "Caricamento delle sessioni archiviate…",
|
|
389
|
+
"history.empty": "L’insieme di archivi è vuoto.",
|
|
390
|
+
"history.edit": "Modifica",
|
|
391
|
+
"history.done": "Fatto",
|
|
392
|
+
"history.selectAll": "Seleziona tutto",
|
|
393
|
+
"history.unselectAll": "Deseleziona tutto",
|
|
394
|
+
"history.unarchive": "Annulla archiviazione ({n})",
|
|
395
|
+
"history.unarchiving": "Annullamento…",
|
|
396
|
+
"history.purge": "Elimina i file d’archivio ({n}) · libera {size}",
|
|
397
|
+
"history.purging": "Eliminazione…",
|
|
398
|
+
"history.editingHint": "Modalità modifica: spunta le sessioni, poi scegli una delle due — «Annulla archiviazione» le rimuove solo dall’array di archivio ufficiale (reversibile; tornano nella barra laterale dopo un riavvio); «Elimina i file d’archivio» cancella davvero trascrizione e cache di proiezione dal disco (irreversibile).",
|
|
399
|
+
"history.restartHint": "Rimossi {removed} id dall’array di archivio ({remaining} rimasti). **Riavvia subito DSH**: finché l’host non esce, qualsiasi modifica ad archivio o workspace riscrive l’intero snapshot di memoria nel file e annulla questa operazione.",
|
|
400
|
+
"history.pendingRestart": "{n} id archiviati sono ancora vivi nella memoria dell’host: l’elenco segue il file di archiviazione (lì sono già spariti), ma le loro sessioni restano nascoste nella barra laterale finché DSH non si riavvia.",
|
|
401
|
+
"history.count": "{n} in totale · {size} su disco",
|
|
402
|
+
"history.size": "trascrizione {t} · cache {c}",
|
|
403
|
+
"history.sizeUnknown": "nessuna entità su disco",
|
|
404
|
+
"history.source.registry": "Origine: registro archivi dell’host",
|
|
405
|
+
"history.source.storage-file": "Origine: file di archiviazione",
|
|
406
|
+
"history.source.none": "Archivi illeggibili da entrambe le origini",
|
|
407
|
+
"history.confirmUnarchive": "Annullare l’archiviazione di queste {n} sessioni?\n\n{summary}\n\nViene modificato solo l’array di archivio (backup automatico); il disco non viene toccato. Dopo un riavvio di DSH queste sessioni tornano nei loro workspace.",
|
|
408
|
+
"history.confirmPurge": "Eliminare i file su disco di queste {n} sessioni archiviate?\n\n{summary}\n\nVerranno liberati circa {size}.\nVerranno eliminati: la directory delle trascrizioni (comprese le copie nel vecchio formato) e la cache di proiezione per sessione, e saranno rimosse dall’array di archivio e dalle tabelle di appartenenza ai workspace.\n\n**Operazione irreversibile: le sessioni non saranno recuperabili.**",
|
|
409
|
+
"history.purgeResult": "Eliminate {purged} sessioni archiviate, liberati {size}. Riavvia DSH per farle scomparire del tutto.",
|
|
410
|
+
"history.purgePartial": "Eliminate {purged}, liberati {size}; {failed} con errori (dettagli sotto).",
|
|
411
|
+
"history.purgeFailures": "Dettagli degli errori",
|
|
412
|
+
"health.scan": "Avvia la visita",
|
|
413
|
+
"health.scanning": "Visita in corso…",
|
|
414
|
+
"health.progress": "{done}/{total} · {sec}s trascorsi",
|
|
415
|
+
"health.empty": "Nessuna sessione problematica trovata.",
|
|
416
|
+
"health.clean": "Tutti i controlli superati.",
|
|
417
|
+
"health.level.ok": "ok",
|
|
418
|
+
"health.level.warn": "attenzione",
|
|
419
|
+
"health.level.skipped": "Non verificato",
|
|
420
|
+
"health.level.fail": "errore",
|
|
421
|
+
"health.priority.high": "Priorità",
|
|
422
|
+
"health.gate.generation": "Artefatto di generazione",
|
|
423
|
+
"health.gate.log-integrity": "Integrità dei log",
|
|
424
|
+
"health.gate.projection-cache": "Cache di proiezione",
|
|
425
|
+
"health.gate.lossless-json": "JSON senza perdite",
|
|
426
|
+
"health.gate.cold-read": "Riprendibilità",
|
|
427
|
+
"health.gate.source-kind": "Firma del plugin",
|
|
428
|
+
"health.attribution": "Proprietario",
|
|
429
|
+
"health.field": "Campo",
|
|
430
|
+
"health.unknownOwner": "proprietario sconosciuto",
|
|
431
|
+
"health.phase.checkup": "1) Visita",
|
|
432
|
+
"health.phase.prescribe": "2) Prescrizione",
|
|
433
|
+
"health.phase.discharge": "3) Dimissione",
|
|
434
|
+
"health.repair": "Applica riparazione reversibile",
|
|
435
|
+
"health.repairing": "Riparazione…",
|
|
436
|
+
"health.sourceMigrate": "Migra le firme precedenti",
|
|
437
|
+
"health.sourceMigrating": "Migrazione…",
|
|
438
|
+
"health.sourceMigrated": "{n} righe di firme precedenti migrate (backup: {backup})",
|
|
439
|
+
"health.sourceMigrateNone": "Nessuna firma precedente da migrare",
|
|
440
|
+
"health.sourceMigrateFail": "Migrazione non riuscita: {error}",
|
|
441
|
+
"health.before": "Prima",
|
|
442
|
+
"health.after": "Dopo",
|
|
443
|
+
"health.quarantined": "Cache di proiezione in quarantena (si richiude dopo un riavvio di DSH)",
|
|
444
|
+
"health.commands": "Comandi",
|
|
445
|
+
"health.copy": "Copia",
|
|
446
|
+
"health.copied": "Copiato",
|
|
447
|
+
"health.detail": "Dettagli",
|
|
448
|
+
"health.back": "Indietro",
|
|
449
|
+
"health.cache.hint": "Risultato in cache · {ago}",
|
|
450
|
+
"health.cache.refresh": "Aggiorna",
|
|
451
|
+
"health.cache.corpusChanged": "Corpus modificato ({was} → {now}); aggiornamento consigliato",
|
|
452
|
+
"health.ago.justNow": "proprio ora",
|
|
453
|
+
"health.ago.minutes": "{n} min fa",
|
|
454
|
+
"health.ago.hours": "{n} h fa",
|
|
455
|
+
"health.ago.days": "{n} g fa"
|
|
456
|
+
};
|
|
457
|
+
/** Русский словарь (те же ключи). */
|
|
458
|
+
const ru = {
|
|
459
|
+
"card.title": "Session Steward",
|
|
460
|
+
"card.desc": "Файлы истории · Проверка здоровья",
|
|
461
|
+
"card.enabled": "Включить Session Steward",
|
|
462
|
+
"card.enabled.desc": "Если выключено, сервисы не регистрируются, а запись в боковой панели исчезает.",
|
|
463
|
+
"card.history": "Файлы истории сессий",
|
|
464
|
+
"card.history.desc": "Просмотр и очистка архива (Пансионат). Если выключено, маршруты истории и вкладка исчезают.",
|
|
465
|
+
"card.health": "Проверка здоровья",
|
|
466
|
+
"card.health.desc": "Осмотр → Рецепт → Выписка. Если выключено, маршруты здоровья и вкладка исчезают.",
|
|
467
|
+
"card.readonly": "Эта сессия не может менять настройки (монтирование только для чтения).",
|
|
468
|
+
"card.unavailable": "Сервис настроек недоступен; конфигурацию прочитать нельзя.",
|
|
469
|
+
"family.title": "Настройки плагинов Screwdriver",
|
|
470
|
+
"panel.title": "Session Steward",
|
|
471
|
+
"panel.tab.history": "Пансионат",
|
|
472
|
+
"panel.tab.health": "Осмотр",
|
|
473
|
+
"panel.close": "Закрыть",
|
|
474
|
+
"panel.untitled": "(без названия)",
|
|
475
|
+
"history.loading": "Загрузка архивных сессий…",
|
|
476
|
+
"history.empty": "Набор архивов пуст.",
|
|
477
|
+
"history.edit": "Изменить",
|
|
478
|
+
"history.done": "Готово",
|
|
479
|
+
"history.selectAll": "Выбрать все",
|
|
480
|
+
"history.unselectAll": "Снять выделение",
|
|
481
|
+
"history.unarchive": "Снять архивацию ({n})",
|
|
482
|
+
"history.unarchiving": "Снятие архивации…",
|
|
483
|
+
"history.purge": "Удалить архивные файлы ({n}) · освободит {size}",
|
|
484
|
+
"history.purging": "Удаление…",
|
|
485
|
+
"history.editingHint": "Режим правки: отметьте сессии, затем выберите одно из двух — «Снять архивацию» лишь убирает их из официального массива архива (обратимо; после перезапуска они вернутся в боковую панель); «Удалить архивные файлы» действительно стирает транскрипт и кэш проекций с диска (необратимо).",
|
|
486
|
+
"history.restartHint": "Из массива архива удалено id: {removed} (осталось {remaining}). **Перезапустите DSH немедленно**: пока хост не завершится, любое изменение архива или рабочего пространства перезапишет весь снимок памяти в файл и отменит эту операцию.",
|
|
487
|
+
"history.pendingRestart": "{n} архивных id ещё живы в памяти хоста: список следует за файлом хранилища (там их уже нет), но их сессии остаются скрытыми в боковой панели до перезапуска DSH.",
|
|
488
|
+
"history.count": "Всего {n} · {size} на диске",
|
|
489
|
+
"history.size": "транскрипт {t} · кэш {c}",
|
|
490
|
+
"history.sizeUnknown": "нет файлов на диске",
|
|
491
|
+
"history.source.registry": "Источник: реестр архива хоста",
|
|
492
|
+
"history.source.storage-file": "Источник: файл хранилища",
|
|
493
|
+
"history.source.none": "Набор архивов не читается ни из одного источника",
|
|
494
|
+
"history.confirmUnarchive": "Снять архивацию этих {n} сессий?\n\n{summary}\n\nМеняется только массив архива (автоматическая резервная копия); файлы на диске не затрагиваются. После перезапуска DSH эти сессии вернутся в свои рабочие пространства.",
|
|
495
|
+
"history.confirmPurge": "Удалить файлы на диске этих {n} архивных сессий?\n\n{summary}\n\nБудет освобождено около {size}.\nБудут удалены: каталог транскриптов (включая копии старого формата) и кэш проекций каждой сессии, а сами сессии — из массива архива и таблиц членства в рабочих пространствах.\n\n**Операция необратима — сессии невозможно будет восстановить.**",
|
|
496
|
+
"history.purgeResult": "Удалено {purged} архивных сессий, освобождено {size}. Перезапустите DSH, чтобы они исчезли окончательно.",
|
|
497
|
+
"history.purgePartial": "Удалено {purged}, освобождено {size}; с ошибками: {failed} (подробности ниже).",
|
|
498
|
+
"history.purgeFailures": "Подробности ошибок",
|
|
499
|
+
"health.scan": "Запустить осмотр",
|
|
500
|
+
"health.scanning": "Осмотр…",
|
|
501
|
+
"health.progress": "{done}/{total} · прошло {sec} с",
|
|
502
|
+
"health.empty": "Проблемных сессий не найдено.",
|
|
503
|
+
"health.clean": "Все проверки пройдены.",
|
|
504
|
+
"health.level.ok": "норма",
|
|
505
|
+
"health.level.warn": "внимание",
|
|
506
|
+
"health.level.skipped": "Не проверено",
|
|
507
|
+
"health.level.fail": "сбой",
|
|
508
|
+
"health.priority.high": "Приоритет",
|
|
509
|
+
"health.gate.generation": "Артефакт поколения",
|
|
510
|
+
"health.gate.log-integrity": "Целостность журналов",
|
|
511
|
+
"health.gate.projection-cache": "Кэш проекций",
|
|
512
|
+
"health.gate.lossless-json": "JSON без потерь",
|
|
513
|
+
"health.gate.cold-read": "Возобновляемость",
|
|
514
|
+
"health.gate.source-kind": "Подпись плагина",
|
|
515
|
+
"health.attribution": "Владелец",
|
|
516
|
+
"health.field": "Поле",
|
|
517
|
+
"health.unknownOwner": "владелец неизвестен",
|
|
518
|
+
"health.phase.checkup": "1) Осмотр",
|
|
519
|
+
"health.phase.prescribe": "2) Рецепт",
|
|
520
|
+
"health.phase.discharge": "3) Выписка",
|
|
521
|
+
"health.repair": "Применить обратимое исправление",
|
|
522
|
+
"health.repairing": "Исправление…",
|
|
523
|
+
"health.sourceMigrate": "Мигрировать старые подписи",
|
|
524
|
+
"health.sourceMigrating": "Миграция…",
|
|
525
|
+
"health.sourceMigrated": "Мигрировано строк старых подписей: {n} (резервная копия: {backup})",
|
|
526
|
+
"health.sourceMigrateNone": "Старых подписей для миграции нет",
|
|
527
|
+
"health.sourceMigrateFail": "Ошибка миграции: {error}",
|
|
528
|
+
"health.before": "До",
|
|
529
|
+
"health.after": "После",
|
|
530
|
+
"health.quarantined": "Кэш проекций отправлен в карантин (свернётся после перезапуска DSH)",
|
|
531
|
+
"health.commands": "Команды",
|
|
532
|
+
"health.copy": "Копировать",
|
|
533
|
+
"health.copied": "Скопировано",
|
|
534
|
+
"health.detail": "Подробнее",
|
|
535
|
+
"health.back": "Назад",
|
|
536
|
+
"health.cache.hint": "Результат из кэша · {ago}",
|
|
537
|
+
"health.cache.refresh": "Обновить",
|
|
538
|
+
"health.cache.corpusChanged": "Корпус изменился ({was} → {now}); рекомендуется обновить",
|
|
539
|
+
"health.ago.justNow": "только что",
|
|
540
|
+
"health.ago.minutes": "{n} мин назад",
|
|
541
|
+
"health.ago.hours": "{n} ч назад",
|
|
542
|
+
"health.ago.days": "{n} дн назад"
|
|
543
|
+
};
|
|
544
|
+
/** Diccionario español (mismas claves). */
|
|
545
|
+
const es = {
|
|
546
|
+
"card.title": "Session Steward",
|
|
547
|
+
"card.desc": "Archivos de historial · Chequeo de salud",
|
|
548
|
+
"card.enabled": "Activar Session Steward",
|
|
549
|
+
"card.enabled.desc": "Al desactivarlo no se registra ningún servicio y la entrada de la barra lateral desaparece.",
|
|
550
|
+
"card.history": "Archivos de historial de sesiones",
|
|
551
|
+
"card.history.desc": "Consulta y limpieza del archivo (Residencia). Al desactivarlo, las rutas de historial y la pestaña desaparecen.",
|
|
552
|
+
"card.health": "Chequeo de salud",
|
|
553
|
+
"card.health.desc": "Chequeo → Receta → Alta. Al desactivarlo, las rutas de salud y la pestaña desaparecen.",
|
|
554
|
+
"card.readonly": "Esta sesión no puede editar los ajustes (montaje de solo lectura).",
|
|
555
|
+
"card.unavailable": "Servicio de ajustes no disponible; no se puede leer la configuración.",
|
|
556
|
+
"family.title": "Ajustes de los plugins Screwdriver",
|
|
557
|
+
"panel.title": "Session Steward",
|
|
558
|
+
"panel.tab.history": "Residencia",
|
|
559
|
+
"panel.tab.health": "Chequeo",
|
|
560
|
+
"panel.close": "Cerrar",
|
|
561
|
+
"panel.untitled": "(sin título)",
|
|
562
|
+
"history.loading": "Cargando sesiones archivadas…",
|
|
563
|
+
"history.empty": "El conjunto de archivos está vacío.",
|
|
564
|
+
"history.edit": "Editar",
|
|
565
|
+
"history.done": "Hecho",
|
|
566
|
+
"history.selectAll": "Seleccionar todo",
|
|
567
|
+
"history.unselectAll": "Quitar selección",
|
|
568
|
+
"history.unarchive": "Desarchivar ({n})",
|
|
569
|
+
"history.unarchiving": "Desarchivando…",
|
|
570
|
+
"history.purge": "Purgar archivos de archivo ({n}) · libera {size}",
|
|
571
|
+
"history.purging": "Purgando…",
|
|
572
|
+
"history.editingHint": "Modo de edición: marca sesiones y elige una de dos — «Desarchivar» solo las quita del arreglo de archivos oficial (reversible; vuelven a la barra lateral tras un reinicio); «Purgar archivos de archivo» borra de verdad la transcripción y la caché de proyección del disco (irreversible).",
|
|
573
|
+
"history.restartHint": "Se quitaron {removed} id del arreglo de archivos ({remaining} restantes). **Reinicia DSH ahora**: hasta que el host salga, cualquier cambio de archivo o espacio de trabajo reescribe toda la instantánea en memoria al fichero y deshace esta operación.",
|
|
574
|
+
"history.pendingRestart": "{n} id archivados siguen vivos en la memoria del host: la lista sigue el fichero de almacenamiento (allí ya no están), pero sus sesiones siguen ocultas en la barra lateral hasta que se reinicie DSH.",
|
|
575
|
+
"history.count": "{n} en total · {size} en disco",
|
|
576
|
+
"history.size": "transcripción {t} · caché {c}",
|
|
577
|
+
"history.sizeUnknown": "sin entidad en disco",
|
|
578
|
+
"history.source.registry": "Fuente: registro de archivos del host",
|
|
579
|
+
"history.source.storage-file": "Fuente: fichero de almacenamiento",
|
|
580
|
+
"history.source.none": "Archivos ilegibles desde ambas fuentes",
|
|
581
|
+
"history.confirmUnarchive": "¿Desarchivar estas {n} sesiones?\n\n{summary}\n\nSolo se edita el arreglo de archivos (copia de seguridad automática); no se toca nada en el disco. Tras reiniciar DSH estas sesiones vuelven a sus espacios de trabajo.",
|
|
582
|
+
"history.confirmPurge": "¿Purgar los ficheros en disco de estas {n} sesiones archivadas?\n\n{summary}\n\nSe liberarán unos {size}.\nSe eliminarán: el directorio de transcripciones (incluidas las copias del formato antiguo) y la caché de proyección por sesión, y se quitarán del arreglo de archivos y de las tablas de pertenencia a espacios de trabajo.\n\n**Esto no se puede deshacer: las sesiones no se podrán recuperar.**",
|
|
583
|
+
"history.purgeResult": "Purgadas {purged} sesiones archivadas, liberados {size}. Reinicia DSH para que desaparezcan por completo.",
|
|
584
|
+
"history.purgePartial": "Purgadas {purged}, liberados {size}; {failed} con error (detalles abajo).",
|
|
585
|
+
"history.purgeFailures": "Detalles de los errores",
|
|
586
|
+
"health.scan": "Iniciar chequeo",
|
|
587
|
+
"health.scanning": "Chequeando…",
|
|
588
|
+
"health.progress": "{done}/{total} · {sec}s transcurridos",
|
|
589
|
+
"health.empty": "No se encontró ninguna sesión problemática.",
|
|
590
|
+
"health.clean": "Todas las comprobaciones pasaron.",
|
|
591
|
+
"health.level.ok": "ok",
|
|
592
|
+
"health.level.warn": "aviso",
|
|
593
|
+
"health.level.skipped": "Sin comprobar",
|
|
594
|
+
"health.level.fail": "fallo",
|
|
595
|
+
"health.priority.high": "Prioridad",
|
|
596
|
+
"health.gate.generation": "Artefacto de generación",
|
|
597
|
+
"health.gate.log-integrity": "Integridad del registro",
|
|
598
|
+
"health.gate.projection-cache": "Caché de proyección",
|
|
599
|
+
"health.gate.lossless-json": "JSON sin pérdidas",
|
|
600
|
+
"health.gate.cold-read": "Reanudabilidad",
|
|
601
|
+
"health.gate.source-kind": "Firma del plugin",
|
|
602
|
+
"health.attribution": "Propietario",
|
|
603
|
+
"health.field": "Campo",
|
|
604
|
+
"health.unknownOwner": "propietario desconocido",
|
|
605
|
+
"health.phase.checkup": "1) Chequeo",
|
|
606
|
+
"health.phase.prescribe": "2) Receta",
|
|
607
|
+
"health.phase.discharge": "3) Alta",
|
|
608
|
+
"health.repair": "Aplicar reparación reversible",
|
|
609
|
+
"health.repairing": "Reparando…",
|
|
610
|
+
"health.sourceMigrate": "Migrar firmas antiguas",
|
|
611
|
+
"health.sourceMigrating": "Migrando…",
|
|
612
|
+
"health.sourceMigrated": "Se migraron {n} filas de firmas antiguas (copia: {backup})",
|
|
613
|
+
"health.sourceMigrateNone": "No hay firmas antiguas que migrar",
|
|
614
|
+
"health.sourceMigrateFail": "Error de migración: {error}",
|
|
615
|
+
"health.before": "Antes",
|
|
616
|
+
"health.after": "Después",
|
|
617
|
+
"health.quarantined": "Caché de proyección en cuarentena (se repliega tras reiniciar DSH)",
|
|
618
|
+
"health.commands": "Comandos",
|
|
619
|
+
"health.copy": "Copiar",
|
|
620
|
+
"health.copied": "Copiado",
|
|
621
|
+
"health.detail": "Detalles",
|
|
622
|
+
"health.back": "Volver",
|
|
623
|
+
"health.cache.hint": "Resultado en caché · {ago}",
|
|
624
|
+
"health.cache.refresh": "Actualizar",
|
|
625
|
+
"health.cache.corpusChanged": "El corpus cambió ({was} → {now}); se recomienda actualizar",
|
|
626
|
+
"health.ago.justNow": "justo ahora",
|
|
627
|
+
"health.ago.minutes": "hace {n} min",
|
|
628
|
+
"health.ago.hours": "hace {n} h",
|
|
629
|
+
"health.ago.days": "hace {n} d"
|
|
630
|
+
};
|
|
182
631
|
/** 字典查找(缺 key 时回退到内置 zh,再回退 key 本身)。 */
|
|
183
632
|
function translate(t, key, params) {
|
|
184
633
|
if (t !== void 0) try {
|
|
@@ -196,17 +645,14 @@ window.__ModuleLoader__.load({
|
|
|
196
645
|
/**
|
|
197
646
|
* 设置卡(插件配置行):一个可折叠抽屉 —— 会话历史文件 / 健康检查。
|
|
198
647
|
*
|
|
199
|
-
* **chrome
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
* renderSlot('settings.plugin.item', {}, { entryKey: ns })
|
|
203
|
-
*
|
|
204
|
-
* 它**不提供任何外壳**。所以卡片的标题、说明、展开/收起全归插件自己所有
|
|
205
|
-
* (同分区里 search-index 等卡片都是这个形态)。早期版本只渲染了裸行,
|
|
206
|
-
* 结果既与分区内其它插件的抽屉形态不一致,又让 `card.title` / `card.desc`
|
|
207
|
-
* 变成定义了却没人渲染的死文案。
|
|
648
|
+
* **chrome 必须自己渲染**:宿主不为贡献卡提供任何外壳,标题、说明、
|
|
649
|
+
* 展开/收起全归插件自己所有。早期版本只渲染裸行,与同分区其它插件
|
|
650
|
+
* 的抽屉形态不一致,还让 `card.title` / `card.desc` 成为死文案。
|
|
208
651
|
*
|
|
209
|
-
* 读写走
|
|
652
|
+
* 读写走 configForms(`configForms.get(STEWARD_ENTRY_ID)`,以本插件 entry 为键;
|
|
653
|
+
* 旧宿主回退 settingsScope 绑定)的显式 `set`。0.1.7 起本卡挂在插件族共用
|
|
654
|
+
* 设置节(`dsh-family.tab`,dsh-thinking-levels 顶级「起子插件设置」节声明)里,
|
|
655
|
+
* 与同节其它抽屉一样默认展开。
|
|
210
656
|
*/
|
|
211
657
|
/** 一行设置项。 */
|
|
212
658
|
function Row(props) {
|
|
@@ -269,10 +715,10 @@ window.__ModuleLoader__.load({
|
|
|
269
715
|
strokeLinejoin: "round"
|
|
270
716
|
}))]);
|
|
271
717
|
}
|
|
272
|
-
/**
|
|
718
|
+
/** 插件设置卡主体(抽屉)。默认展开,family 设置节内直接呈现完整面板。 */
|
|
273
719
|
function StewardSettingsCard({ t, scope }) {
|
|
274
720
|
const snapshot = (0, react.useSyncExternalStore)((listener) => scope.subscribe(listener), () => scope.getSnapshot());
|
|
275
|
-
const [open, setOpen] = (0, react.useState)(
|
|
721
|
+
const [open, setOpen] = (0, react.useState)(true);
|
|
276
722
|
const value = snapshot.value ?? {};
|
|
277
723
|
const writable = snapshot.writable;
|
|
278
724
|
const rows = [];
|
|
@@ -683,7 +1129,8 @@ window.__ModuleLoader__.load({
|
|
|
683
1129
|
"log-integrity": "health.gate.log-integrity",
|
|
684
1130
|
"projection-cache": "health.gate.projection-cache",
|
|
685
1131
|
"lossless-json": "health.gate.lossless-json",
|
|
686
|
-
"cold-read": "health.gate.cold-read"
|
|
1132
|
+
"cold-read": "health.gate.cold-read",
|
|
1133
|
+
"source-kind": "health.gate.source-kind"
|
|
687
1134
|
};
|
|
688
1135
|
const LEVEL_LABEL = {
|
|
689
1136
|
ok: "health.level.ok",
|
|
@@ -733,6 +1180,9 @@ window.__ModuleLoader__.load({
|
|
|
733
1180
|
const [error, setError] = (0, react.useState)(null);
|
|
734
1181
|
const [detail, setDetail] = (0, react.useState)(null);
|
|
735
1182
|
const [repairing, setRepairing] = (0, react.useState)(false);
|
|
1183
|
+
const [migrating, setMigrating] = (0, react.useState)(false);
|
|
1184
|
+
/** 署名转换结果提示(一次性;点击转换或返回列表时清除)。 */
|
|
1185
|
+
const [migrateNote, setMigrateNote] = (0, react.useState)(null);
|
|
736
1186
|
const [discharge, setDischarge] = (0, react.useState)(null);
|
|
737
1187
|
const [copied, setCopied] = (0, react.useState)(null);
|
|
738
1188
|
/** 分批扫描进度:done = 已访问会话数,total = 语料总数(0 表示尚未拿到分母)。 */
|
|
@@ -788,6 +1238,7 @@ window.__ModuleLoader__.load({
|
|
|
788
1238
|
setError(null);
|
|
789
1239
|
setDetail(null);
|
|
790
1240
|
setDischarge(null);
|
|
1241
|
+
setMigrateNote(null);
|
|
791
1242
|
setFindings(null);
|
|
792
1243
|
setCacheInfo(null);
|
|
793
1244
|
setProgress({
|
|
@@ -856,6 +1307,7 @@ window.__ModuleLoader__.load({
|
|
|
856
1307
|
const openDetail = (sessionId) => {
|
|
857
1308
|
setError(null);
|
|
858
1309
|
setDischarge(null);
|
|
1310
|
+
setMigrateNote(null);
|
|
859
1311
|
callHostAny("session-health-session", { sessionId }, 12e4).then((res) => {
|
|
860
1312
|
if (res.ok === true) {
|
|
861
1313
|
setDetail(res);
|
|
@@ -886,6 +1338,28 @@ window.__ModuleLoader__.load({
|
|
|
886
1338
|
setCopied(text);
|
|
887
1339
|
} catch {}
|
|
888
1340
|
};
|
|
1341
|
+
const runSourceMigrate = (sessionId) => {
|
|
1342
|
+
setMigrating(true);
|
|
1343
|
+
setError(null);
|
|
1344
|
+
setMigrateNote(null);
|
|
1345
|
+
callHostAny("session-health-source-migrate", { sessionId }, 12e4).then((res) => {
|
|
1346
|
+
if (res.after !== void 0) {
|
|
1347
|
+
setDetail({
|
|
1348
|
+
ok: true,
|
|
1349
|
+
report: res.after,
|
|
1350
|
+
prescriptions: detail?.prescriptions ?? []
|
|
1351
|
+
});
|
|
1352
|
+
reconcileRow(res.after);
|
|
1353
|
+
}
|
|
1354
|
+
const changed = res.outcome?.changedRows ?? 0;
|
|
1355
|
+
if (res.ok === true && changed > 0) setMigrateNote(translate(t, "health.sourceMigrated", {
|
|
1356
|
+
n: changed,
|
|
1357
|
+
backup: res.outcome?.backup ?? ""
|
|
1358
|
+
}));
|
|
1359
|
+
else if (res.ok === true) setMigrateNote(translate(t, "health.sourceMigrateNone"));
|
|
1360
|
+
else setMigrateNote(translate(t, "health.sourceMigrateFail", { error: res.outcome?.error ?? res.error ?? "未知原因" }));
|
|
1361
|
+
}).catch((err) => setError(String(err instanceof Error ? err.message : err))).finally(() => setMigrating(false));
|
|
1362
|
+
};
|
|
889
1363
|
const report = detail?.report ?? discharge?.after;
|
|
890
1364
|
const lines = [];
|
|
891
1365
|
lines.push((0, react.createElement)("div", {
|
|
@@ -1052,6 +1526,25 @@ window.__ModuleLoader__.load({
|
|
|
1052
1526
|
className: "dss_spinner",
|
|
1053
1527
|
"aria-hidden": "true"
|
|
1054
1528
|
}) : null, (0, react.createElement)("span", { key: "tx" }, repairing ? translate(t, "health.repairing") : translate(t, "health.repair"))])]));
|
|
1529
|
+
if (report.gates.some((gate) => gate.id === "source-kind" && gate.level === "warn")) lines.push((0, react.createElement)("div", {
|
|
1530
|
+
key: "migrate",
|
|
1531
|
+
className: "dss_phaseRow"
|
|
1532
|
+
}, [(0, react.createElement)("button", {
|
|
1533
|
+
key: "m",
|
|
1534
|
+
type: "button",
|
|
1535
|
+
className: "dss_actBtn",
|
|
1536
|
+
disabled: migrating,
|
|
1537
|
+
onClick: () => {
|
|
1538
|
+
runSourceMigrate(report.sessionId);
|
|
1539
|
+
}
|
|
1540
|
+
}, [migrating ? (0, react.createElement)("span", {
|
|
1541
|
+
key: "sp",
|
|
1542
|
+
className: "dss_spinner",
|
|
1543
|
+
"aria-hidden": "true"
|
|
1544
|
+
}) : null, (0, react.createElement)("span", { key: "tx" }, migrating ? translate(t, "health.sourceMigrating") : translate(t, "health.sourceMigrate"))]), migrateNote !== null && (0, react.createElement)("span", {
|
|
1545
|
+
key: "note",
|
|
1546
|
+
className: "dss_status"
|
|
1547
|
+
}, migrateNote)]));
|
|
1055
1548
|
const prescriptions = detail?.prescriptions ?? discharge?.prescriptions ?? [];
|
|
1056
1549
|
if (prescriptions.length > 0) lines.push((0, react.createElement)("div", {
|
|
1057
1550
|
key: "cmds",
|
|
@@ -1227,9 +1720,31 @@ window.__ModuleLoader__.load({
|
|
|
1227
1720
|
const style = document.createElement("style");
|
|
1228
1721
|
style.id = id;
|
|
1229
1722
|
style.textContent = `
|
|
1723
|
+
/* 侧栏 footer 槽位公约(2026-09-26;2026-10-01 收紧行距并强制居中):一行多
|
|
1724
|
+
入口(第三方 dsh-context 等)会互相挤占 —— 宿主 .footerActions 是 nowrap
|
|
1725
|
+
flex 行。这里允许容器换行,并把本插件入口钉成独占一整行(flex-basis:100%);
|
|
1726
|
+
其余入口(含第三方)自然落到后续行,各行内部自行布局,谁也不挤谁。
|
|
1727
|
+
justify-content:center 让行内所有入口(含不占满行的)统一居中;row-gap:0
|
|
1728
|
+
配合入口自身 32px 高度压缩纵向占位。类名用 [class*=] 中段匹配:宿主是 CSS
|
|
1729
|
+
Module 哈希类名(实测形如 hHd-Xa_footerActions —— <hash>_<name>,哈希在前),
|
|
1730
|
+
中段跨版本稳定。 */
|
|
1731
|
+
[class*="footerActions"]{flex-wrap:wrap;justify-content:center;row-gap:0;height:auto;min-height:0}
|
|
1732
|
+
/* —— 第三方矫正:dsh-context「上下文洞察」入口(2026-10-01)——
|
|
1733
|
+
.lc-ov-entry 按"独占整行"设计(width:calc(100% + 4px)、无 justify-content、
|
|
1734
|
+
42px 高、不对称 padding),与本槽位公约(每个入口独占一行、行内居中、32px)
|
|
1735
|
+
冲突,表现为文字靠左、纵向松散。这里按公约强制矫正;:not() 排除收起轨道的
|
|
1736
|
+
36px 圆钮形态。lc-ov-* 是 dsh-context 源码硬编码类名(非构建哈希),跨版本
|
|
1737
|
+
稳定(实测 0.56.1 / 0.60.0 规则一致)。两个自有插件各自携带同一矫正块:
|
|
1738
|
+
任一被禁用时矫正仍生效。 */
|
|
1739
|
+
.lc-ov-entry:not(.lc-ov-entry-rail){width:auto!important;flex:0 0 100%!important;min-width:0!important;justify-content:center!important;height:32px!important;margin:0!important;padding:0 10px!important}
|
|
1740
|
+
.lc-ov-entry-label{flex:0 1 auto!important}
|
|
1741
|
+
/* 宽栏:独占一整行、放弃主动收缩(flex-shrink:0),行内居中;收起轨道回落自然宽度。 */
|
|
1230
1742
|
.dss_entryWrap{flex:0 1 auto;display:inline-flex;align-items:center;min-width:0}
|
|
1231
|
-
.dss_entryWrapWide{margin-left:
|
|
1232
|
-
|
|
1743
|
+
.dss_entryWrapWide{flex:0 0 100%;width:100%;justify-content:center;margin-left:0}
|
|
1744
|
+
/* 高度 32px(内容 22px 行高 + 上下各 5px):宿主默认 42px 的上下裕度在多行
|
|
1745
|
+
堆叠后过于松散;左右内边距对称(10px/10px),否则整行居中时按钮内容会因
|
|
1746
|
+
不对称 padding 向左偏 1px。 */
|
|
1747
|
+
.dss_footerEntry{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:4px;height:32px;padding:0 10px;border:none;border-radius:12px;background:transparent;cursor:pointer;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:14px;line-height:22px;white-space:nowrap;overflow:hidden;transition:background-color 160ms ease-out,color 160ms ease-out}
|
|
1233
1748
|
.dss_footerEntry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
1234
1749
|
.dss_footerEntryRail{width:28px;height:28px;padding:0;gap:0;border-radius:50%}
|
|
1235
1750
|
.dss_footerIcon{flex:none;font-size:15px;line-height:1}
|
|
@@ -1319,42 +1834,115 @@ window.__ModuleLoader__.load({
|
|
|
1319
1834
|
}
|
|
1320
1835
|
/**
|
|
1321
1836
|
* 客户端插件主体。
|
|
1322
|
-
* @param ctx - 客户端上下文(slots、可选 locale /
|
|
1837
|
+
* @param ctx - 客户端上下文(slots、可选 locale / configForms)。
|
|
1323
1838
|
*/
|
|
1324
1839
|
function apply(ctx) {
|
|
1325
1840
|
ctx.effect(() => injectStyles(), "dsh-manage-session: stylesheet");
|
|
1326
1841
|
const locale = ctx.get("locale");
|
|
1327
1842
|
if (locale !== void 0 && typeof locale.register === "function") ctx.effect(() => locale.register(NS, {
|
|
1328
1843
|
zh,
|
|
1329
|
-
en
|
|
1844
|
+
en,
|
|
1845
|
+
fr,
|
|
1846
|
+
de,
|
|
1847
|
+
it,
|
|
1848
|
+
ru,
|
|
1849
|
+
es
|
|
1330
1850
|
}), "dsh-manage-session: dictionaries");
|
|
1331
|
-
const
|
|
1851
|
+
const configForms = ctx.get("configForms");
|
|
1852
|
+
const legacySettings = ctx.get("settingsScope");
|
|
1853
|
+
const bound = configForms?.get("dsh-manage-session") ?? legacySettings?.bind({ namespace: "session-steward" });
|
|
1332
1854
|
const slots = ctx.get("slots");
|
|
1333
1855
|
if (slots === void 0) return;
|
|
1334
1856
|
slots.inject("sidebar.footer.action", () => slots.register({
|
|
1335
1857
|
name: "sidebar.footer.action",
|
|
1336
1858
|
id: STEWARD_ENTRY_ID,
|
|
1337
|
-
order:
|
|
1859
|
+
order: 6
|
|
1338
1860
|
}, (props) => (0, react.createElement)(StewardEntry, {
|
|
1339
1861
|
...props,
|
|
1340
1862
|
scope: bound
|
|
1341
1863
|
})), "dsh-manage-session: sidebar footer entry");
|
|
1342
|
-
slots.inject("
|
|
1343
|
-
name: "
|
|
1344
|
-
id:
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1864
|
+
slots.inject("dsh-family.tab", () => slots.register({
|
|
1865
|
+
name: "dsh-family.tab",
|
|
1866
|
+
id: STEWARD_ENTRY_ID,
|
|
1867
|
+
order: 40,
|
|
1868
|
+
label: () => translate(locale?.bind?.(NS), "card.title"),
|
|
1869
|
+
locale: NS
|
|
1870
|
+
}, (props) => (0, react.createElement)(StewardSettingsCard, {
|
|
1871
|
+
scope: bound,
|
|
1872
|
+
t: props.t
|
|
1873
|
+
})), "dsh-manage-session: family settings tab");
|
|
1874
|
+
const familyTabsHooks = makeFamilyTabsHooks(slots);
|
|
1875
|
+
ctx.effect(() => {
|
|
1876
|
+
let claimed;
|
|
1877
|
+
const timer = setTimeout(() => {
|
|
1878
|
+
if (slots.entries("settings.section").some((e) => e.options.id === FAMILY_SECTION_ID)) return;
|
|
1879
|
+
try {
|
|
1880
|
+
claimed = slots.register({
|
|
1881
|
+
name: "settings.section",
|
|
1882
|
+
id: FAMILY_SECTION_ID,
|
|
1883
|
+
order: 40,
|
|
1884
|
+
label: () => translate(locale?.bind?.(NS), "family.title"),
|
|
1885
|
+
locale: NS,
|
|
1886
|
+
inject: () => ({ hooks: { tabs: familyTabsHooks } }),
|
|
1887
|
+
children: { [FAMILY_CHILD_KEY]: {
|
|
1888
|
+
kind: "list",
|
|
1889
|
+
scope: "root"
|
|
1890
|
+
} }
|
|
1891
|
+
}, StewardFamilySection);
|
|
1892
|
+
} catch {}
|
|
1893
|
+
}, FAMILY_HOST_GRACE_MS);
|
|
1894
|
+
return () => {
|
|
1895
|
+
clearTimeout(timer);
|
|
1896
|
+
if (typeof claimed === "function") claimed();
|
|
1897
|
+
};
|
|
1898
|
+
}, "dsh-manage-session: family fallback host");
|
|
1899
|
+
}
|
|
1900
|
+
/** 家族节固定 id(与 thinking-levels / guard 的注册严格一致)。 */
|
|
1901
|
+
const FAMILY_SECTION_ID = "dsh-family";
|
|
1902
|
+
/** 家族子席位 key(与 thinking-levels 的声明严格一致)。 */
|
|
1903
|
+
const FAMILY_CHILD_KEY = "dsh-family.tab";
|
|
1904
|
+
/** 接管宽限期:guard 2000ms 先试,本插件 2600ms 兜底。 */
|
|
1905
|
+
const FAMILY_HOST_GRACE_MS = 2600;
|
|
1906
|
+
/** 接管节的账本投影 hooks(与 thinking-levels 的 FamilySectionInjected 同形;locale 变更也触发重渲染)。 */
|
|
1907
|
+
function makeFamilyTabsHooks(slots) {
|
|
1908
|
+
let version = -1;
|
|
1909
|
+
let tabs = [];
|
|
1910
|
+
return {
|
|
1911
|
+
getSnapshot: () => {
|
|
1912
|
+
const next = slots.getVersion(FAMILY_CHILD_KEY);
|
|
1913
|
+
if (next !== version) {
|
|
1914
|
+
version = next;
|
|
1915
|
+
tabs = slots.entries(FAMILY_CHILD_KEY).map((entry) => ({
|
|
1916
|
+
id: entry.options.id ?? "",
|
|
1917
|
+
order: entry.options.order ?? 0,
|
|
1918
|
+
label: typeof entry.options.label === "function" ? (() => {
|
|
1919
|
+
try {
|
|
1920
|
+
return String(entry.options.label() ?? entry.options.id ?? "");
|
|
1921
|
+
} catch {
|
|
1922
|
+
return String(entry.options.id ?? "");
|
|
1923
|
+
}
|
|
1924
|
+
})() : String(entry.options.label ?? entry.options.id ?? "")
|
|
1925
|
+
})).sort((a, b) => a.order - b.order);
|
|
1926
|
+
}
|
|
1927
|
+
return tabs;
|
|
1928
|
+
},
|
|
1929
|
+
subscribe: (listener) => slots.subscribe(FAMILY_CHILD_KEY, listener)
|
|
1930
|
+
};
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* 家族节接管组件(fallback host section):纯通用渲染 —— 把 `dsh-family.tab`
|
|
1934
|
+
* 账本里的每张贡献卡(含本插件自己的,接管时本插件也声明了该子席位)按
|
|
1935
|
+
* order 依次 renderSlot;各卡本身是默认展开的抽屉,整节即一页抽屉。
|
|
1936
|
+
*/
|
|
1937
|
+
function StewardFamilySection(props) {
|
|
1938
|
+
const tabs = (0, react.useSyncExternalStore)(props.hooks.tabs.subscribe, props.hooks.tabs.getSnapshot);
|
|
1939
|
+
return (0, react.createElement)("div", { style: {
|
|
1940
|
+
display: "grid",
|
|
1941
|
+
gap: "12px"
|
|
1942
|
+
} }, ...tabs.map((row) => (0, react.createElement)("div", { key: row.id }, props.renderSlot(FAMILY_CHILD_KEY, {}, {
|
|
1943
|
+
only: row.id,
|
|
1944
|
+
fallback: null
|
|
1945
|
+
}))));
|
|
1358
1946
|
}
|
|
1359
1947
|
/** 入口按钮:持有面板开关;两个页签的可见性来自配置快照。 */
|
|
1360
1948
|
function StewardEntry(props) {
|