fixes
This commit is contained in:
parent
e8800dc88c
commit
5e188e2f94
|
|
@ -1 +1 @@
|
|||
1.1.89
|
||||
1.1.92
|
||||
|
|
@ -172,7 +172,7 @@
|
|||
const allHistory = await db.historyEntries.filter(h => !h.deletedAt).toArray();
|
||||
const allContexts = await db.contexts.filter(c => !c.deletedAt).toArray();
|
||||
|
||||
const results: { topicId: string; historyEntryId: string; topicTitle: string; contextName: string; date: string; text: string }[] = [];
|
||||
const results: { topicId: string; historyEntryId: string; topicTitle: string; contextId: string; contextName: string; date: string; text: string }[] = [];
|
||||
|
||||
for (const h of allHistory) {
|
||||
const topic = allTopics.find(t => t.id === h.topicId);
|
||||
|
|
@ -194,6 +194,7 @@
|
|||
topicId: topic.id,
|
||||
historyEntryId: h.id,
|
||||
topicTitle: topic.title,
|
||||
contextId: ctx?.id ?? '',
|
||||
contextName: ctx?.name ?? 'Unknown',
|
||||
date: h.date,
|
||||
text: h.text
|
||||
|
|
@ -531,14 +532,23 @@
|
|||
</div>
|
||||
|
||||
{#each $activityLog ?? [] as entry}
|
||||
<div class="mb-2.5 border-l-2 border-[#444] pl-2.5" data-topic-id={entry.topicId} data-history-entry-id={entry.historyEntryId}>
|
||||
<div class="mb-0.5 text-xs text-[#aaa]">
|
||||
{entry.date} in <span class="text-accent">{entry.contextName}</span>: {entry.topicTitle}
|
||||
<div class="mb-2.5 border-l-2 border-[#444] pl-2.5">
|
||||
<div class="mb-0.5 flex items-baseline gap-1 text-xs text-[#aaa]">
|
||||
<a
|
||||
href="/context/daily-log?date={entry.date}"
|
||||
class="font-mono text-[#888] hover:text-white underline-offset-2 hover:underline"
|
||||
>{entry.date}</a>
|
||||
<span>in</span>
|
||||
<a
|
||||
href="/context/{entry.contextId}"
|
||||
class="text-accent hover:brightness-125 underline-offset-2 hover:underline"
|
||||
>{entry.contextName}</a>:
|
||||
<span>{entry.topicTitle}</span>
|
||||
</div>
|
||||
<RenderedMarkdown text={entry.text} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-muted">No entries found.</div>
|
||||
<div class="text-muted">Keine Einträge gefunden.</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
let years = now.getFullYear() - start.getFullYear();
|
||||
let months = now.getMonth() - start.getMonth();
|
||||
if (months < 0) { years--; months += 12; }
|
||||
if (years > 0 && months > 0) return `${years} J. ${months} Mo.`;
|
||||
if (years > 0 && months > 0) return `${years}J ${months}M`;
|
||||
if (years > 0) return `${years} J.`;
|
||||
return `${months} Mo.`;
|
||||
}
|
||||
|
|
@ -66,6 +66,7 @@
|
|||
{@const subType = (meta?.personSubType ?? 'contact') as PersonSubType}
|
||||
{@const showBirthday = subType === 'family' || subType === 'employee' || subType === 'colleague'}
|
||||
{@const showTenure = subType === 'employee' && !!meta?.joinDate}
|
||||
{@const hasInfo = (showBirthday && !!meta?.birthday) || showTenure}
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex flex-col">
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'up')} disabled={i === 0} title="Nach oben">▲</button>
|
||||
|
|
@ -77,19 +78,23 @@
|
|||
title={ctx.isFavorite ? 'Aus Sidebar entfernen' : 'In Sidebar anzeigen'}
|
||||
>★</button>
|
||||
<button
|
||||
class="flex flex-1 items-center justify-between rounded-lg border border-[#444] bg-sidebar px-4 py-3 text-left transition-colors hover:border-[#666] hover:bg-[#2a2a2a]"
|
||||
class="flex flex-1 flex-col rounded-lg border border-[#444] bg-sidebar px-4 py-3 text-left transition-colors hover:border-[#666] hover:bg-[#2a2a2a]"
|
||||
onclick={() => goto(`/context/${ctx.id}`)}
|
||||
>
|
||||
<span class="font-bold text-white">{displayName(ctx.name)}</span>
|
||||
<span class="flex items-center gap-2">
|
||||
{#if showBirthday && meta?.birthday}
|
||||
<span class="text-xs text-muted">🎂 {formatDate(meta.birthday)}</span>
|
||||
{/if}
|
||||
{#if showTenure && meta?.joinDate}
|
||||
<span class="text-xs text-muted" title="seit {formatDate(meta.joinDate)}">⏱ {tenure(meta.joinDate)}</span>
|
||||
{/if}
|
||||
<span class="rounded px-2 py-0.5 text-xs {subTypeColors[subType]}">{subTypeLabels[subType]}</span>
|
||||
</span>
|
||||
<div class="flex w-full items-center justify-between gap-2">
|
||||
<span class="font-bold text-white">{displayName(ctx.name)}</span>
|
||||
<span class="shrink-0 rounded px-2 py-0.5 text-xs {subTypeColors[subType]}">{subTypeLabels[subType]}</span>
|
||||
</div>
|
||||
{#if hasInfo}
|
||||
<div class="mt-1 flex items-center gap-3 text-xs text-muted">
|
||||
{#if showBirthday && meta?.birthday}
|
||||
<span>🎂 {formatDate(meta.birthday)}</span>
|
||||
{/if}
|
||||
{#if showTenure && meta?.joinDate}
|
||||
<span title="seit {formatDate(meta.joinDate)}">⏱ {tenure(meta.joinDate)}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
class="rounded border border-[#444] bg-sidebar px-2.5 py-2.5 text-[#888] transition-colors hover:border-red-900 hover:text-red-400"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@
|
|||
{#if createError}<p class="mb-3 -mt-2 text-xs text-red-400">{createError}</p>{/if}
|
||||
{/if}
|
||||
|
||||
<div class="mb-4 flex flex-wrap gap-1 border-b border-[#333] pb-2">
|
||||
<div class="mb-4 flex gap-1 overflow-x-auto border-b border-[#333] pb-2 scrollbar-none">
|
||||
{#each tabs as tab}
|
||||
{@const count = tab.key === 'all' ? persons.length : persons.filter(c => ((c.meta as PersonMeta | null)?.personSubType ?? 'contact') === tab.key).length}
|
||||
{#if count > 0 || tab.key === 'all'}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -126,6 +126,16 @@ export async function runIfMissed(): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
function parseCreatedAt(filename: string): string {
|
||||
// filename: backup-{userId}-YYYY-MM-DDTHH-MM-SS.zip
|
||||
const base = filename.slice(0, -4); // strip .zip
|
||||
const ts = base.slice(base.lastIndexOf('-', base.length - 16) + 1);
|
||||
// ts: "2026-02-27T14-30-45" → restore colons in time part
|
||||
const iso = ts.replace(/T(\d{2})-(\d{2})-(\d{2})$/, 'T$1:$2:$3') + 'Z';
|
||||
const d = new Date(iso);
|
||||
return isNaN(d.getTime()) ? new Date(0).toISOString() : d.toISOString();
|
||||
}
|
||||
|
||||
export async function listBackups(): Promise<BackupEntry[]> {
|
||||
await ensureBackupDir();
|
||||
const entries = await fs.readdir(BACKUP_DIR);
|
||||
|
|
@ -133,7 +143,7 @@ export async function listBackups(): Promise<BackupEntry[]> {
|
|||
for (const name of entries) {
|
||||
if (!name.endsWith('.zip')) continue;
|
||||
const stat = await fs.stat(path.join(BACKUP_DIR, name));
|
||||
result.push({ filename: name, size: stat.size, createdAt: stat.mtime.toISOString() });
|
||||
result.push({ filename: name, size: stat.size, createdAt: parseCreatedAt(name) });
|
||||
}
|
||||
return result.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue