This commit is contained in:
beo3000 2026-02-21 11:20:40 +01:00
parent a320b1c291
commit 71d5a6593a
3 changed files with 34 additions and 16 deletions

View File

@ -1 +1 @@
1.0.6 1.0.7

View File

@ -9,7 +9,7 @@
import { newId } from '$lib/db/helpers'; import { newId } from '$lib/db/helpers';
import type { AgendaContext, ContextType } from '@ka-note/shared'; import type { AgendaContext, ContextType } from '@ka-note/shared';
import { account, logout } from '$lib/auth/authStore.js'; import { account, logout } from '$lib/auth/authStore.js';
import { syncStatus, lastSyncAt } from '$lib/sync/syncService'; import { syncStatus, lastSyncAt, fullSync } from '$lib/sync/syncService';
const isDev = import.meta.env.DEV; const isDev = import.meta.env.DEV;
let appVersion = $state('…'); let appVersion = $state('…');
@ -285,17 +285,27 @@
{/if} {/if}
<div class="mt-auto border-t border-border pt-3"> <div class="mt-auto border-t border-border pt-3">
<div class="mb-2 flex items-center gap-1.5 px-1 text-xs text-muted"> <div class="mb-2 flex items-center justify-between px-1">
{#if $syncStatus === 'syncing'} <div class="flex items-center gap-1.5 text-xs text-muted">
<svg class="h-3 w-3 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> {#if $syncStatus === 'syncing'}
<path d="M21 12a9 9 0 1 1-6.219-8.56" stroke-linecap="round"/> <svg class="h-3 w-3 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
</svg> <path d="M21 12a9 9 0 1 1-6.219-8.56" stroke-linecap="round"/>
<span>Syncing…</span> </svg>
{:else if $syncStatus === 'error'} <span>Syncing…</span>
<span class="text-danger">✗ Sync error</span> {:else if $syncStatus === 'error'}
{:else if $lastSyncAt} <span class="text-danger">✗ Sync error</span>
<span>{$lastSyncAt.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span> {:else if $lastSyncAt}
{/if} <span>{$lastSyncAt.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>
{:else}
<span>Not synced</span>
{/if}
</div>
<button
class="text-xs text-muted hover:text-white disabled:opacity-30 transition-colors"
onclick={() => fullSync()}
disabled={$syncStatus === 'syncing'}
title="Full sync"
>⟳</button>
</div> </div>
<button <button
class="mb-1 w-full rounded px-2.5 py-2 text-left text-xs text-muted transition-colors hover:bg-white/5 hover:text-white" class="mb-1 w-full rounded px-2.5 py-2 text-left text-xs text-muted transition-colors hover:bg-white/5 hover:text-white"

View File

@ -82,11 +82,19 @@ async function pushAll(): Promise<void> {
if (!res.ok) throw new Error(`Push failed: ${res.status}`); if (!res.ok) throw new Error(`Push failed: ${res.status}`);
} }
export async function fullSync(): Promise<void> {
await doSync(null);
}
export async function sync(): Promise<void> { export async function sync(): Promise<void> {
let since: Date | null = null;
lastSyncAt.subscribe((v) => (since = v))();
await doSync(since);
}
async function doSync(since: Date | null): Promise<void> {
syncStatus.set('syncing'); syncStatus.set('syncing');
try { try {
let since: Date | null = null;
lastSyncAt.subscribe((v) => (since = v))();
const serverTimestamp = await pullAndMerge(since); const serverTimestamp = await pullAndMerge(since);
await pushAll(); await pushAll();
const syncTime = new Date(serverTimestamp); const syncTime = new Date(serverTimestamp);
@ -95,7 +103,7 @@ export async function sync(): Promise<void> {
syncStatus.set('idle'); syncStatus.set('idle');
} catch (err) { } catch (err) {
const msg = err instanceof Error ? err.message : String(err); const msg = err instanceof Error ? err.message : String(err);
if (err instanceof TypeError && msg === 'Failed to fetch') { if (err instanceof TypeError && (msg === 'Failed to fetch' || msg.includes('fetch'))) {
// Offline or server unreachable — stay idle silently // Offline or server unreachable — stay idle silently
syncStatus.set('idle'); syncStatus.set('idle');
} else if (msg === 'Redirecting for token' || msg.includes('no_account_in_silent_request')) { } else if (msg === 'Redirecting for token' || msg.includes('no_account_in_silent_request')) {