opencode-mem 2.11.4 → 2.11.7
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/dist/services/sqlite/hnsw-index.d.ts +1 -0
- package/dist/services/sqlite/hnsw-index.d.ts.map +1 -1
- package/dist/services/sqlite/hnsw-index.js +33 -32
- package/dist/services/sqlite/vector-search.d.ts.map +1 -1
- package/dist/services/sqlite/vector-search.js +5 -0
- package/dist/services/tags.d.ts.map +1 -1
- package/dist/services/tags.js +8 -1
- package/dist/services/web-server.d.ts.map +1 -1
- package/dist/services/web-server.js +3 -0
- package/dist/web/app.js +98 -105
- package/dist/web/i18n.d.ts +2 -0
- package/dist/web/i18n.d.ts.map +1 -0
- package/dist/web/i18n.js +265 -0
- package/dist/web/index.html +76 -50
- package/dist/web/styles.css +17 -0
- package/package.json +1 -1
package/dist/web/app.js
CHANGED
|
@@ -57,8 +57,8 @@ function populateTagDropdowns() {
|
|
|
57
57
|
const tagFilter = document.getElementById("tag-filter");
|
|
58
58
|
const addTag = document.getElementById("add-tag");
|
|
59
59
|
|
|
60
|
-
tagFilter.innerHTML =
|
|
61
|
-
addTag.innerHTML =
|
|
60
|
+
tagFilter.innerHTML = `<option value="">${t("opt-all-tags")}</option>`;
|
|
61
|
+
addTag.innerHTML = `<option value="">${t("opt-select-tag")}</option>`;
|
|
62
62
|
|
|
63
63
|
const scopeTags = state.tags.project;
|
|
64
64
|
|
|
@@ -83,7 +83,7 @@ function renderMemories() {
|
|
|
83
83
|
const container = document.getElementById("memories-list");
|
|
84
84
|
|
|
85
85
|
if (state.memories.length === 0) {
|
|
86
|
-
container.innerHTML =
|
|
86
|
+
container.innerHTML = `<div class="empty-state">${t("empty-memories")}</div>`;
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -162,14 +162,13 @@ function renderCombinedCard(pair) {
|
|
|
162
162
|
memory.updatedAt && memory.updatedAt !== memory.createdAt ? formatDate(memory.updatedAt) : null;
|
|
163
163
|
|
|
164
164
|
const dateInfo = updatedDate
|
|
165
|
-
? `<span
|
|
166
|
-
: `<span
|
|
167
|
-
|
|
165
|
+
? `<span>${t("date-created")} ${createdDate}</span><span>${t("date-updated")} ${updatedDate}</span>`
|
|
166
|
+
: `<span>${t("date-created")} ${createdDate}</span>`;
|
|
168
167
|
return `
|
|
169
168
|
<div class="combined-card ${isSelected ? "selected" : ""} ${isPinned ? "pinned" : ""}" data-id="${memory.id}">
|
|
170
169
|
<div class="combined-prompt-section">
|
|
171
170
|
<div class="combined-header">
|
|
172
|
-
<span class="badge badge-prompt"
|
|
171
|
+
<span class="badge badge-prompt">${t("badge-prompt")}</span>
|
|
173
172
|
<span class="prompt-date">${formatDate(prompt.createdAt)}</span>
|
|
174
173
|
</div>
|
|
175
174
|
<div class="prompt-content">${escapeHtml(prompt.content)}</div>
|
|
@@ -183,17 +182,17 @@ function renderCombinedCard(pair) {
|
|
|
183
182
|
<div class="memory-header">
|
|
184
183
|
<div class="meta">
|
|
185
184
|
<input type="checkbox" class="memory-checkbox" data-id="${memory.id}" ${isSelected ? "checked" : ""} />
|
|
186
|
-
<span class="badge badge-memory"
|
|
185
|
+
<span class="badge badge-memory">${t("badge-memory")}</span>
|
|
187
186
|
${memory.memoryType ? `<span class="badge badge-type">${memory.memoryType}</span>` : ""}
|
|
188
187
|
${similarityHtml}
|
|
189
|
-
${isPinned ?
|
|
188
|
+
${isPinned ? `<span class="badge badge-pinned">${t("badge-pinned")}</span>` : ""}
|
|
190
189
|
<span class="memory-display-name">${escapeHtml(memory.displayName || memory.id)}</span>
|
|
191
190
|
</div>
|
|
192
191
|
<div class="memory-actions">
|
|
193
192
|
${pinButton}
|
|
194
193
|
<button class="btn-edit" onclick="editMemory('${memory.id}')"><i data-lucide="edit-3" class="icon"></i></button>
|
|
195
194
|
<button class="btn-delete" onclick="deleteMemoryWithLink('${memory.id}', true)">
|
|
196
|
-
<i data-lucide="trash-2" class="icon"></i>
|
|
195
|
+
<i data-lucide="trash-2" class="icon"></i> ${t("btn-delete-pair")}
|
|
197
196
|
</button>
|
|
198
197
|
</div>
|
|
199
198
|
</div>
|
|
@@ -219,21 +218,21 @@ function renderPromptCard(prompt) {
|
|
|
219
218
|
<div class="meta">
|
|
220
219
|
<input type="checkbox" class="memory-checkbox" data-id="${prompt.id}" ${isSelected ? "checked" : ""} />
|
|
221
220
|
<i data-lucide="message-circle" class="icon"></i>
|
|
222
|
-
<span class="badge badge-prompt"
|
|
223
|
-
${isLinked ?
|
|
221
|
+
<span class="badge badge-prompt">${t("badge-prompt")}</span>
|
|
222
|
+
${isLinked ? `<span class="badge badge-linked"><i data-lucide="link" class="icon-sm"></i> ${t("badge-linked")}</span>` : ""}
|
|
224
223
|
<span class="prompt-date">${promptDate}</span>
|
|
225
224
|
</div>
|
|
226
225
|
<div class="prompt-actions">
|
|
227
226
|
<button class="btn-delete" onclick="deletePromptWithLink('${prompt.id}', ${isLinked})">
|
|
228
227
|
<i data-lucide="trash-2" class="icon"></i>
|
|
229
|
-
${isLinked ? "
|
|
228
|
+
${isLinked ? t("btn-delete-pair") : t("btn-delete")}
|
|
230
229
|
</button>
|
|
231
230
|
</div>
|
|
232
231
|
</div>
|
|
233
232
|
<div class="prompt-content">
|
|
234
233
|
${escapeHtml(prompt.content)}
|
|
235
234
|
</div>
|
|
236
|
-
${isLinked ?
|
|
235
|
+
${isLinked ? `<div class="link-indicator"><i data-lucide="arrow-down" class="icon-sm"></i> ${t("text-generated-above")} <i data-lucide="arrow-up" class="icon-sm"></i></div>` : ""}
|
|
237
236
|
</div>
|
|
238
237
|
`;
|
|
239
238
|
}
|
|
@@ -270,9 +269,8 @@ function renderMemoryCard(memory) {
|
|
|
270
269
|
memory.updatedAt && memory.updatedAt !== memory.createdAt ? formatDate(memory.updatedAt) : null;
|
|
271
270
|
|
|
272
271
|
const dateInfo = updatedDate
|
|
273
|
-
? `<span
|
|
274
|
-
: `<span
|
|
275
|
-
|
|
272
|
+
? `<span>${t("date-created")} ${createdDate}</span><span>${t("date-updated")} ${updatedDate}</span>`
|
|
273
|
+
: `<span>${t("date-created")} ${createdDate}</span>`;
|
|
276
274
|
const tagsHtml =
|
|
277
275
|
memory.tags && memory.tags.length > 0
|
|
278
276
|
? `<div class="tags-list">${memory.tags.map((t) => `<span class="tag-badge">${escapeHtml(t)}</span>`).join("")}</div>`
|
|
@@ -284,9 +282,9 @@ function renderMemoryCard(memory) {
|
|
|
284
282
|
<div class="meta">
|
|
285
283
|
<input type="checkbox" class="memory-checkbox" data-id="${memory.id}" ${isSelected ? "checked" : ""} />
|
|
286
284
|
${memory.memoryType ? `<span class="badge badge-type">${memory.memoryType}</span>` : ""}
|
|
287
|
-
${isLinked ?
|
|
285
|
+
${isLinked ? `<span class="badge badge-linked"><i data-lucide="link" class="icon-sm"></i> ${t("badge-linked")}</span>` : ""}
|
|
288
286
|
${similarityHtml}
|
|
289
|
-
${isPinned ?
|
|
287
|
+
${isPinned ? `<span class="badge badge-pinned">${t("badge-pinned")}</span>` : ""}
|
|
290
288
|
<span class="memory-display-name">${escapeHtml(displayInfo)}</span>
|
|
291
289
|
${subtitle}
|
|
292
290
|
</div>
|
|
@@ -295,13 +293,13 @@ function renderMemoryCard(memory) {
|
|
|
295
293
|
<button class="btn-edit" onclick="editMemory('${memory.id}')"><i data-lucide="edit-3" class="icon"></i></button>
|
|
296
294
|
<button class="btn-delete" onclick="deleteMemoryWithLink('${memory.id}', ${isLinked})">
|
|
297
295
|
<i data-lucide="trash-2" class="icon"></i>
|
|
298
|
-
${isLinked ? "
|
|
296
|
+
${isLinked ? t("btn-delete-pair") : t("btn-delete")}
|
|
299
297
|
</button>
|
|
300
298
|
</div>
|
|
301
299
|
</div>
|
|
302
300
|
${tagsHtml}
|
|
303
301
|
<div class="memory-content markdown-content">${renderMarkdown(memory.content)}</div>
|
|
304
|
-
${isLinked ?
|
|
302
|
+
${isLinked ? `<div class="link-indicator"><i data-lucide="arrow-up" class="icon-sm"></i> ${t("text-from-below")} <i data-lucide="arrow-down" class="icon-sm"></i></div>` : ""}
|
|
305
303
|
<div class="memory-footer">
|
|
306
304
|
${dateInfo}
|
|
307
305
|
<span>ID: ${memory.id}</span>
|
|
@@ -340,17 +338,16 @@ function updateBulkActions() {
|
|
|
340
338
|
|
|
341
339
|
if (state.selectedMemories.size > 0) {
|
|
342
340
|
bulkActions.classList.remove("hidden");
|
|
343
|
-
selectedCount.textContent =
|
|
341
|
+
selectedCount.textContent = t("text-selected", { count: state.selectedMemories.size });
|
|
344
342
|
} else {
|
|
345
343
|
bulkActions.classList.add("hidden");
|
|
346
344
|
}
|
|
347
345
|
}
|
|
348
346
|
|
|
349
347
|
function updatePagination() {
|
|
350
|
-
const pageInfo =
|
|
348
|
+
const pageInfo = t("text-page", { current: state.currentPage, total: state.totalPages });
|
|
351
349
|
document.getElementById("page-info-top").textContent = pageInfo;
|
|
352
350
|
document.getElementById("page-info-bottom").textContent = pageInfo;
|
|
353
|
-
|
|
354
351
|
const hasPrev = state.currentPage > 1;
|
|
355
352
|
const hasNext = state.currentPage < state.totalPages;
|
|
356
353
|
|
|
@@ -363,14 +360,16 @@ function updatePagination() {
|
|
|
363
360
|
function updateSectionTitle() {
|
|
364
361
|
const title = state.isSearching
|
|
365
362
|
? `└─ SEARCH RESULTS (${state.totalItems}) ──`
|
|
366
|
-
:
|
|
363
|
+
: t("section-project", { count: state.totalItems });
|
|
367
364
|
document.getElementById("section-title").textContent = title;
|
|
368
365
|
}
|
|
369
366
|
|
|
370
367
|
async function loadStats() {
|
|
371
368
|
const result = await fetchAPI("/api/stats");
|
|
372
369
|
if (result.success) {
|
|
373
|
-
document.getElementById("stats-total").textContent =
|
|
370
|
+
document.getElementById("stats-total").textContent = t("text-total", {
|
|
371
|
+
count: result.data.total,
|
|
372
|
+
});
|
|
374
373
|
}
|
|
375
374
|
}
|
|
376
375
|
|
|
@@ -389,7 +388,7 @@ async function addMemory(e) {
|
|
|
389
388
|
: [];
|
|
390
389
|
|
|
391
390
|
if (!content || !containerTag) {
|
|
392
|
-
showToast("
|
|
391
|
+
showToast(t("toast-add-error"), "error");
|
|
393
392
|
return;
|
|
394
393
|
}
|
|
395
394
|
|
|
@@ -400,12 +399,12 @@ async function addMemory(e) {
|
|
|
400
399
|
});
|
|
401
400
|
|
|
402
401
|
if (result.success) {
|
|
403
|
-
showToast("
|
|
402
|
+
showToast(t("toast-add-success"), "success");
|
|
404
403
|
document.getElementById("add-form").reset();
|
|
405
404
|
await loadMemories();
|
|
406
405
|
await loadStats();
|
|
407
406
|
} else {
|
|
408
|
-
showToast(result.error || "
|
|
407
|
+
showToast(result.error || t("toast-add-failed"), "error");
|
|
409
408
|
}
|
|
410
409
|
}
|
|
411
410
|
|
|
@@ -439,13 +438,12 @@ async function loadMemories() {
|
|
|
439
438
|
updatePagination();
|
|
440
439
|
updateSectionTitle();
|
|
441
440
|
} else {
|
|
442
|
-
showError(result.error || "
|
|
441
|
+
showError(result.error || t("toast-update-failed"));
|
|
443
442
|
}
|
|
444
443
|
}
|
|
445
444
|
|
|
446
445
|
async function deleteMemoryWithLink(id, isLinked) {
|
|
447
|
-
const message = isLinked ? "
|
|
448
|
-
|
|
446
|
+
const message = isLinked ? t("confirm-delete-pair") : t("confirm-delete");
|
|
449
447
|
if (!confirm(message)) return;
|
|
450
448
|
|
|
451
449
|
const result = await fetchAPI(`/api/memories/${id}?cascade=true`, {
|
|
@@ -453,22 +451,18 @@ async function deleteMemoryWithLink(id, isLinked) {
|
|
|
453
451
|
});
|
|
454
452
|
|
|
455
453
|
if (result.success) {
|
|
456
|
-
|
|
457
|
-
showToast(msg, "success");
|
|
454
|
+
showToast(t("toast-delete-success"), "success");
|
|
458
455
|
|
|
459
456
|
state.selectedMemories.delete(id);
|
|
460
457
|
await loadMemories();
|
|
461
458
|
await loadStats();
|
|
462
459
|
} else {
|
|
463
|
-
showToast(result.error || "
|
|
460
|
+
showToast(result.error || t("toast-delete-failed"), "error");
|
|
464
461
|
}
|
|
465
462
|
}
|
|
466
463
|
|
|
467
464
|
async function deletePromptWithLink(id, isLinked) {
|
|
468
|
-
const message = isLinked
|
|
469
|
-
? "Delete this prompt AND its linked memory summary?"
|
|
470
|
-
: "Delete this prompt?";
|
|
471
|
-
|
|
465
|
+
const message = isLinked ? t("confirm-delete-prompt") : t("confirm-delete");
|
|
472
466
|
if (!confirm(message)) return;
|
|
473
467
|
|
|
474
468
|
const result = await fetchAPI(`/api/prompts/${id}?cascade=true`, {
|
|
@@ -476,21 +470,20 @@ async function deletePromptWithLink(id, isLinked) {
|
|
|
476
470
|
});
|
|
477
471
|
|
|
478
472
|
if (result.success) {
|
|
479
|
-
|
|
480
|
-
showToast(msg, "success");
|
|
473
|
+
showToast(t("toast-delete-success"), "success");
|
|
481
474
|
|
|
482
475
|
state.selectedMemories.delete(id);
|
|
483
476
|
await loadMemories();
|
|
484
477
|
await loadStats();
|
|
485
478
|
} else {
|
|
486
|
-
showToast(result.error || "
|
|
479
|
+
showToast(result.error || t("toast-delete-failed"), "error");
|
|
487
480
|
}
|
|
488
481
|
}
|
|
489
482
|
|
|
490
483
|
async function bulkDelete() {
|
|
491
484
|
if (state.selectedMemories.size === 0) return;
|
|
492
485
|
|
|
493
|
-
const message =
|
|
486
|
+
const message = t("confirm-bulk-delete", { count: state.selectedMemories.size });
|
|
494
487
|
if (!confirm(message)) return;
|
|
495
488
|
|
|
496
489
|
const ids = Array.from(state.selectedMemories);
|
|
@@ -518,7 +511,7 @@ async function bulkDelete() {
|
|
|
518
511
|
if (result.success) deletedCount += result.data.deleted;
|
|
519
512
|
}
|
|
520
513
|
|
|
521
|
-
showToast(
|
|
514
|
+
showToast(t("toast-bulk-delete-success"), "success");
|
|
522
515
|
state.selectedMemories.clear();
|
|
523
516
|
await loadMemories();
|
|
524
517
|
await loadStats();
|
|
@@ -551,7 +544,7 @@ async function saveEdit(e) {
|
|
|
551
544
|
const content = document.getElementById("edit-content").value.trim();
|
|
552
545
|
|
|
553
546
|
if (!content) {
|
|
554
|
-
showToast("
|
|
547
|
+
showToast(t("toast-add-error"), "error");
|
|
555
548
|
return;
|
|
556
549
|
}
|
|
557
550
|
|
|
@@ -562,11 +555,11 @@ async function saveEdit(e) {
|
|
|
562
555
|
});
|
|
563
556
|
|
|
564
557
|
if (result.success) {
|
|
565
|
-
showToast("
|
|
558
|
+
showToast(t("toast-update-success"), "success");
|
|
566
559
|
closeModal();
|
|
567
560
|
await loadMemories();
|
|
568
561
|
} else {
|
|
569
|
-
showToast(result.error || "
|
|
562
|
+
showToast(result.error || t("toast-update-failed"), "error");
|
|
570
563
|
}
|
|
571
564
|
}
|
|
572
565
|
|
|
@@ -637,7 +630,8 @@ function showRefreshIndicator(show) {
|
|
|
637
630
|
|
|
638
631
|
function formatDate(isoString) {
|
|
639
632
|
const date = new Date(isoString);
|
|
640
|
-
|
|
633
|
+
const locale = getLanguage() === "zh" ? "zh-CN" : "en-US";
|
|
634
|
+
return date.toLocaleString(locale, {
|
|
641
635
|
year: "numeric",
|
|
642
636
|
month: "short",
|
|
643
637
|
day: "numeric",
|
|
@@ -650,10 +644,10 @@ async function pinMemory(id) {
|
|
|
650
644
|
const result = await fetchAPI(`/api/memories/${id}/pin`, { method: "POST" });
|
|
651
645
|
|
|
652
646
|
if (result.success) {
|
|
653
|
-
showToast("
|
|
647
|
+
showToast(t("toast-update-success"), "success");
|
|
654
648
|
await loadMemories();
|
|
655
649
|
} else {
|
|
656
|
-
showToast(result.error || "
|
|
650
|
+
showToast(result.error || t("toast-update-failed"), "error");
|
|
657
651
|
}
|
|
658
652
|
}
|
|
659
653
|
|
|
@@ -661,49 +655,40 @@ async function unpinMemory(id) {
|
|
|
661
655
|
const result = await fetchAPI(`/api/memories/${id}/unpin`, { method: "POST" });
|
|
662
656
|
|
|
663
657
|
if (result.success) {
|
|
664
|
-
showToast("
|
|
658
|
+
showToast(t("toast-update-success"), "success");
|
|
665
659
|
await loadMemories();
|
|
666
660
|
} else {
|
|
667
|
-
showToast(result.error || "
|
|
661
|
+
showToast(result.error || t("toast-update-failed"), "error");
|
|
668
662
|
}
|
|
669
663
|
}
|
|
670
664
|
|
|
671
665
|
async function runCleanup() {
|
|
672
|
-
if (!confirm("
|
|
666
|
+
if (!confirm(t("confirm-cleanup"))) return;
|
|
673
667
|
|
|
674
|
-
showToast("
|
|
668
|
+
showToast(t("status-cleanup"), "info");
|
|
675
669
|
const result = await fetchAPI("/api/cleanup", { method: "POST" });
|
|
676
670
|
|
|
677
671
|
if (result.success) {
|
|
678
|
-
|
|
679
|
-
showToast(
|
|
680
|
-
`Cleanup complete: ${data.deletedCount} deleted (user: ${data.userCount}, project: ${data.projectCount})`,
|
|
681
|
-
"success"
|
|
682
|
-
);
|
|
672
|
+
showToast(t("toast-cleanup-success"), "success");
|
|
683
673
|
await loadMemories();
|
|
684
674
|
await loadStats();
|
|
685
675
|
} else {
|
|
686
|
-
showToast(result.error || "
|
|
676
|
+
showToast(result.error || t("toast-cleanup-failed"), "error");
|
|
687
677
|
}
|
|
688
678
|
}
|
|
689
679
|
|
|
690
680
|
async function runDeduplication() {
|
|
691
|
-
if (!confirm("
|
|
681
|
+
if (!confirm(t("confirm-dedup"))) return;
|
|
692
682
|
|
|
693
|
-
showToast("
|
|
683
|
+
showToast(t("status-dedup"), "info");
|
|
694
684
|
const result = await fetchAPI("/api/deduplicate", { method: "POST" });
|
|
695
685
|
|
|
696
686
|
if (result.success) {
|
|
697
|
-
|
|
698
|
-
let message = `Deduplication complete: ${data.exactDuplicatesDeleted} exact duplicates deleted`;
|
|
699
|
-
if (data.nearDuplicateGroups.length > 0) {
|
|
700
|
-
message += `, ${data.nearDuplicateGroups.length} near-duplicate groups found`;
|
|
701
|
-
}
|
|
702
|
-
showToast(message, "success");
|
|
687
|
+
showToast(t("toast-dedup-success"), "success");
|
|
703
688
|
await loadMemories();
|
|
704
689
|
await loadStats();
|
|
705
690
|
} else {
|
|
706
|
-
showToast(result.error || "
|
|
691
|
+
showToast(result.error || t("toast-dedup-failed"), "error");
|
|
707
692
|
}
|
|
708
693
|
}
|
|
709
694
|
|
|
@@ -735,8 +720,7 @@ async function checkMigrationStatus() {
|
|
|
735
720
|
function showTagMigrationModal(count) {
|
|
736
721
|
const overlay = document.getElementById("tag-migration-overlay");
|
|
737
722
|
const status = document.getElementById("tag-migration-status");
|
|
738
|
-
status.textContent =
|
|
739
|
-
overlay.classList.remove("hidden");
|
|
723
|
+
status.textContent = t("migration-found-tags", { count });
|
|
740
724
|
|
|
741
725
|
document.getElementById("start-tag-migration-btn").onclick = runTagMigration;
|
|
742
726
|
}
|
|
@@ -747,7 +731,7 @@ async function runTagMigration() {
|
|
|
747
731
|
const progress = document.getElementById("tag-migration-progress");
|
|
748
732
|
|
|
749
733
|
actions.classList.add("hidden");
|
|
750
|
-
status.textContent = "
|
|
734
|
+
status.textContent = t("status-migration-init");
|
|
751
735
|
progress.style.width = "0%";
|
|
752
736
|
|
|
753
737
|
let totalProcessed = 0;
|
|
@@ -764,8 +748,7 @@ async function runTagMigration() {
|
|
|
764
748
|
});
|
|
765
749
|
|
|
766
750
|
if (!result.success) {
|
|
767
|
-
status.textContent = "
|
|
768
|
-
actions.classList.remove("hidden");
|
|
751
|
+
status.textContent = t("toast-migration-failed") + ": " + result.error;
|
|
769
752
|
return;
|
|
770
753
|
}
|
|
771
754
|
|
|
@@ -775,22 +758,20 @@ async function runTagMigration() {
|
|
|
775
758
|
const percent = total > 0 ? Math.round((totalProcessed / total) * 100) : 0;
|
|
776
759
|
|
|
777
760
|
progress.style.width = percent + "%";
|
|
778
|
-
status.textContent =
|
|
779
|
-
|
|
761
|
+
status.textContent = t("status-migration-progress", { current: totalProcessed, total: total });
|
|
780
762
|
if (hasMore) {
|
|
781
763
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
782
764
|
}
|
|
783
765
|
}
|
|
784
766
|
|
|
785
767
|
if (attempts >= maxAttempts) {
|
|
786
|
-
status.textContent = "
|
|
787
|
-
actions.classList.remove("hidden");
|
|
768
|
+
status.textContent = t("migration-stopped");
|
|
788
769
|
return;
|
|
789
770
|
}
|
|
790
771
|
|
|
791
772
|
progress.style.width = "100%";
|
|
792
|
-
status.textContent =
|
|
793
|
-
showToast("
|
|
773
|
+
status.textContent = t("toast-migration-success");
|
|
774
|
+
showToast(t("toast-migration-success"), "success");
|
|
794
775
|
setTimeout(() => {
|
|
795
776
|
document.getElementById("tag-migration-overlay").classList.add("hidden");
|
|
796
777
|
loadMemories();
|
|
@@ -804,11 +785,14 @@ function showMigrationWarning(data) {
|
|
|
804
785
|
|
|
805
786
|
const shardInfo =
|
|
806
787
|
data.shardMismatches.length > 0
|
|
807
|
-
?
|
|
808
|
-
: "dimension
|
|
788
|
+
? t("migration-shards-mismatch", { count: data.shardMismatches.length })
|
|
789
|
+
: t("migration-dimension-mismatch");
|
|
809
790
|
|
|
810
|
-
message.textContent =
|
|
811
|
-
|
|
791
|
+
message.textContent = t("migration-mismatch-details", {
|
|
792
|
+
configDimensions: data.configDimensions,
|
|
793
|
+
configModel: data.configModel,
|
|
794
|
+
shardInfo,
|
|
795
|
+
});
|
|
812
796
|
|
|
813
797
|
lucide.createIcons();
|
|
814
798
|
}
|
|
@@ -826,7 +810,7 @@ async function runMigration(strategy) {
|
|
|
826
810
|
const checkbox = document.getElementById("migration-confirm-checkbox");
|
|
827
811
|
|
|
828
812
|
if (!checkbox.checked) {
|
|
829
|
-
showToast("
|
|
813
|
+
showToast(t("toast-migration-failed"), "error");
|
|
830
814
|
return;
|
|
831
815
|
}
|
|
832
816
|
|
|
@@ -841,8 +825,7 @@ async function runMigration(strategy) {
|
|
|
841
825
|
return;
|
|
842
826
|
}
|
|
843
827
|
|
|
844
|
-
showToast("
|
|
845
|
-
|
|
828
|
+
showToast(t("status-migration-init"), "info");
|
|
846
829
|
const result = await fetchAPI("/api/migration/run", {
|
|
847
830
|
method: "POST",
|
|
848
831
|
headers: { "Content-Type": "application/json" },
|
|
@@ -859,15 +842,14 @@ async function runMigration(strategy) {
|
|
|
859
842
|
message += `Re-embedded ${data.reEmbeddedMemories} memories. Duration: ${(data.duration / 1000).toFixed(2)}s`;
|
|
860
843
|
}
|
|
861
844
|
|
|
862
|
-
showToast(
|
|
863
|
-
|
|
845
|
+
showToast(t("toast-migration-success"), "success");
|
|
864
846
|
document.getElementById("migration-section").classList.add("hidden");
|
|
865
847
|
document.getElementById("migration-confirm-checkbox").checked = false;
|
|
866
848
|
|
|
867
849
|
await loadMemories();
|
|
868
850
|
await loadStats();
|
|
869
851
|
} else {
|
|
870
|
-
showToast(result.error || "
|
|
852
|
+
showToast(result.error || t("toast-migration-failed"), "error");
|
|
871
853
|
}
|
|
872
854
|
}
|
|
873
855
|
|
|
@@ -877,7 +859,7 @@ async function loadUserProfile() {
|
|
|
877
859
|
state.userProfile = result.data;
|
|
878
860
|
renderUserProfile();
|
|
879
861
|
} else {
|
|
880
|
-
showError(result.error || "
|
|
862
|
+
showError(result.error || t("toast-update-failed"));
|
|
881
863
|
}
|
|
882
864
|
}
|
|
883
865
|
|
|
@@ -937,15 +919,15 @@ function renderUserProfile() {
|
|
|
937
919
|
<h3>${profile.displayName || profile.userId}</h3>
|
|
938
920
|
<div class="profile-stats">
|
|
939
921
|
<div class="stat-pill">
|
|
940
|
-
<span class="label"
|
|
922
|
+
<span class="label">${t("profile-version")}</span>
|
|
941
923
|
<span class="value">${profile.version}</span>
|
|
942
924
|
</div>
|
|
943
925
|
<div class="stat-pill">
|
|
944
|
-
<span class="label"
|
|
926
|
+
<span class="label">${t("profile-prompts")}</span>
|
|
945
927
|
<span class="value">${profile.totalPromptsAnalyzed}</span>
|
|
946
928
|
</div>
|
|
947
929
|
<div class="stat-pill">
|
|
948
|
-
<span class="label"
|
|
930
|
+
<span class="label">${t("profile-updated")}</span>
|
|
949
931
|
<span class="value">${formatDate(profile.lastAnalyzedAt)}</span>
|
|
950
932
|
</div>
|
|
951
933
|
</div>
|
|
@@ -957,10 +939,10 @@ function renderUserProfile() {
|
|
|
957
939
|
|
|
958
940
|
<div class="dashboard-grid">
|
|
959
941
|
<div class="dashboard-section preferences-section">
|
|
960
|
-
<h4><i data-lucide="heart" class="icon"></i>
|
|
942
|
+
<h4><i data-lucide="heart" class="icon"></i> ${t("profile-preferences")} <span class="count">${preferences.length}</span></h4>
|
|
961
943
|
${
|
|
962
944
|
preferences.length === 0
|
|
963
|
-
?
|
|
945
|
+
? `<p class="empty-text">${t("empty-preferences")}</p>`
|
|
964
946
|
: `
|
|
965
947
|
<div class="cards-grid">
|
|
966
948
|
${preferences
|
|
@@ -997,10 +979,10 @@ function renderUserProfile() {
|
|
|
997
979
|
</div>
|
|
998
980
|
|
|
999
981
|
<div class="dashboard-section patterns-section">
|
|
1000
|
-
<h4><i data-lucide="activity" class="icon"></i>
|
|
982
|
+
<h4><i data-lucide="activity" class="icon"></i> ${t("profile-patterns")} <span class="count">${patterns.length}</span></h4>
|
|
1001
983
|
${
|
|
1002
984
|
patterns.length === 0
|
|
1003
|
-
?
|
|
985
|
+
? `<p class="empty-text">${t("empty-patterns")}</p>`
|
|
1004
986
|
: `
|
|
1005
987
|
<div class="cards-grid">
|
|
1006
988
|
${patterns
|
|
@@ -1023,10 +1005,10 @@ function renderUserProfile() {
|
|
|
1023
1005
|
</div>
|
|
1024
1006
|
|
|
1025
1007
|
<div class="dashboard-section workflows-section full-width">
|
|
1026
|
-
<h4><i data-lucide="workflow" class="icon"></i>
|
|
1008
|
+
<h4><i data-lucide="workflow" class="icon"></i> ${t("profile-workflows")} <span class="count">${workflows.length}</span></h4>
|
|
1027
1009
|
${
|
|
1028
1010
|
workflows.length === 0
|
|
1029
|
-
?
|
|
1011
|
+
? `<p class="empty-text">${t("empty-workflows")}</p>`
|
|
1030
1012
|
: `
|
|
1031
1013
|
<div class="workflows-grid">
|
|
1032
1014
|
${workflows
|
|
@@ -1067,8 +1049,7 @@ async function showChangelog() {
|
|
|
1067
1049
|
const list = document.getElementById("changelog-list");
|
|
1068
1050
|
|
|
1069
1051
|
modal.classList.remove("hidden");
|
|
1070
|
-
list.innerHTML =
|
|
1071
|
-
|
|
1052
|
+
list.innerHTML = `<div class="loading">${t("loading-changelog")}</div>`;
|
|
1072
1053
|
const result = await fetchAPI(
|
|
1073
1054
|
`/api/user-profile/changelog?profileId=${state.userProfile.id}&limit=10`
|
|
1074
1055
|
);
|
|
@@ -1089,12 +1070,12 @@ async function showChangelog() {
|
|
|
1089
1070
|
)
|
|
1090
1071
|
.join("");
|
|
1091
1072
|
} else {
|
|
1092
|
-
list.innerHTML =
|
|
1073
|
+
list.innerHTML = `<div class="empty-state">${t("empty-changelog")}</div>`;
|
|
1093
1074
|
}
|
|
1094
1075
|
}
|
|
1095
1076
|
|
|
1096
1077
|
async function refreshProfile() {
|
|
1097
|
-
showToast("
|
|
1078
|
+
showToast(t("loading-profile"), "info");
|
|
1098
1079
|
const result = await fetchAPI("/api/user-profile/refresh", {
|
|
1099
1080
|
method: "POST",
|
|
1100
1081
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1105,7 +1086,7 @@ async function refreshProfile() {
|
|
|
1105
1086
|
showToast(result.data.message, "success");
|
|
1106
1087
|
await loadUserProfile();
|
|
1107
1088
|
} else {
|
|
1108
|
-
showToast(result.error || "
|
|
1089
|
+
showToast(result.error || t("toast-update-failed"), "error");
|
|
1109
1090
|
}
|
|
1110
1091
|
}
|
|
1111
1092
|
|
|
@@ -1144,6 +1125,18 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1144
1125
|
document.getElementById("changelog-modal").classList.add("hidden");
|
|
1145
1126
|
});
|
|
1146
1127
|
|
|
1128
|
+
document.getElementById("lang-toggle").addEventListener("click", () => {
|
|
1129
|
+
const newLang = getLanguage() === "en" ? "zh" : "en";
|
|
1130
|
+
setLanguage(newLang);
|
|
1131
|
+
document.getElementById("lang-toggle").textContent = newLang.toUpperCase();
|
|
1132
|
+
// Re-render dynamic content
|
|
1133
|
+
loadMemories();
|
|
1134
|
+
loadStats();
|
|
1135
|
+
if (state.currentView === "profile") loadUserProfile();
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
document.getElementById("lang-toggle").textContent = getLanguage().toUpperCase();
|
|
1139
|
+
|
|
1147
1140
|
document.getElementById("tag-filter").addEventListener("change", () => {
|
|
1148
1141
|
state.selectedTag = document.getElementById("tag-filter").value;
|
|
1149
1142
|
state.currentPage = 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/web/i18n.js"],"names":[],"mappings":""}
|