Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 33 additions & 43 deletions src/lib/components/settings-dialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@
{ id: 'themes', label: 'Themes' },
{ id: 'shortcuts', label: 'Keyboard shortcuts' },
{ id: 'github', label: 'Backup & sync' },
{ id: 'repository', label: 'Sync repository' },
{ id: 'backup', label: 'Sync status' },
{ id: 'storage', label: 'Storage choices' },
{ id: 'transfer', label: 'Import & export' },
{ id: 'vault', label: 'Vault' }
Expand Down Expand Up @@ -140,7 +138,7 @@
);

$effect(() => {
if (section === 'repository' && connected && isOnline && !repositoriesLoaded) void loadRepositories();
if (section === 'github' && connected && isOnline && !repositoriesLoaded) void loadRepositories();
if (section === 'storage' && !usage && usageState === 'idle') void loadUsage();
});

Expand Down Expand Up @@ -444,22 +442,33 @@
<div class="settings-account">
<span class="github-avatar" aria-hidden="true">{githubUser.login.slice(0, 1)}</span>
<span><strong>{githubUser.name || githubUser.login}</strong><small>@{githubUser.login}</small></span>
<button disabled={!isOnline} onclick={onDisconnectGithub}><LogOut size={14} /> Disconnect</button>
<button disabled={!isOnline} onclick={onDisconnectGithub}><LogOut size={14} /> Disconnect</button>
</div>
{:else}
<div class="settings-account empty">
<CloudOff size={22} />
<span><strong>Local only</strong><small>{githubMessage || 'Sign in to enable GitHub backup and cross-device sync.'}</small></span>
<button class="settings-primary" disabled={!isOnline || githubState === 'loading'} onclick={onConnectGithub}>
{#if githubState === 'loading'}<LoaderCircle class="spin" size={14} />{:else}<GithubIcon size={14} />{/if} Sign in with GitHub
{#if githubBackup}
<h3 class="settings-group-heading">Sync status</h3>
<dl class="settings-facts">
<div><dt>Repository</dt><dd>{githubBackup.owner}/{githubBackup.repository}</dd></div>
<div><dt>GitHub account</dt><dd>@{githubBackup.githubAccountLogin || 'Needs re-selection'}</dd></div>
<div><dt>Branch</dt><dd>{githubBackup.branch}</dd></div>
<div><dt>Directory</dt><dd>{githubBackup.directory || 'repository root'}</dd></div>
<div><dt>Last backup</dt><dd>{formatDate(githubBackup.lastBackedUpAt)}</dd></div>
<div><dt>Last commit</dt><dd>{githubBackup.lastCommitSha ? githubBackup.lastCommitSha.slice(0, 7) : 'None yet'}</dd></div>
<div><dt>Pending changes</dt><dd>{pendingBackupCount === 0 ? 'Up to date' : `${pendingBackupCount} ${pendingBackupCount === 1 ? 'change' : 'changes'}`}</dd></div>
</dl>
{/if}
<div class="settings-actions">
<button class="settings-primary" disabled={!isOnline || !vault || backupState === 'backing-up'} onclick={onBackup}>
{#if backupState === 'backing-up'}<LoaderCircle class="spin" size={14} />{:else}<CloudUpload size={14} />{/if} Back up now
</button>
<button disabled={!isOnline || !vault} onclick={onRestore}><CloudDownload size={14} /> Restore a commit</button>
</div>
{/if}
{:else if section === 'repository'}
<h3>Sync repository</h3>
{#if !connected}
<p class="settings-hint">Sign in with GitHub to choose where this vault is backed up for cross-device restore.</p>
{:else}
{#if backupMessage}
<p class="settings-hint" class:error={backupState === 'error'}>
{backupMessage}
{#if backupCommitUrl}<a href={backupCommitUrl} target="_blank" rel="noreferrer">View commit <ExternalLink size={12} /></a>{/if}
</p>
{/if}
<h3 class="settings-group-heading">Sync repository</h3>
<p class="settings-hint">“{vaultName}” backs up on its own. Only private repositories with write access can be used, and notes are written under the directory below.</p>
<div class="settings-field">
<label for="settings-repository">Repository</label>
Expand Down Expand Up @@ -491,34 +500,15 @@
<button class="settings-primary" disabled={!isOnline || !newRepositoryName.trim()} onclick={() => onCreateRepository(newRepositoryName)}>Create and back up</button>
</div>
</div>
{/if}
{:else if section === 'backup'}
<h3>Backup and sync status</h3>
{#if !githubBackup}
<p class="settings-hint">“{vaultName}” has no repository yet. Choose one in the Repository section to enable backups for this repository alone.</p>
{:else}
<dl class="settings-facts">
<div><dt>Repository</dt><dd>{githubBackup.owner}/{githubBackup.repository}</dd></div>
<div><dt>GitHub account</dt><dd>@{githubBackup.githubAccountLogin || 'Needs re-selection'}</dd></div>
<div><dt>Branch</dt><dd>{githubBackup.branch}</dd></div>
<div><dt>Directory</dt><dd>{githubBackup.directory || 'repository root'}</dd></div>
<div><dt>Last backup</dt><dd>{formatDate(githubBackup.lastBackedUpAt)}</dd></div>
<div><dt>Last commit</dt><dd>{githubBackup.lastCommitSha ? githubBackup.lastCommitSha.slice(0, 7) : 'None yet'}</dd></div>
<div><dt>Pending changes</dt><dd>{pendingBackupCount === 0 ? 'Up to date' : `${pendingBackupCount} ${pendingBackupCount === 1 ? 'change' : 'changes'}`}</dd></div>
</dl>
{/if}
{#if backupMessage}
<p class="settings-hint" class:error={backupState === 'error'}>
{backupMessage}
{#if backupCommitUrl}<a href={backupCommitUrl} target="_blank" rel="noreferrer">View commit <ExternalLink size={12} /></a>{/if}
</p>
<div class="settings-account empty">
<CloudOff size={22} />
<span><strong>Local only</strong><small>{githubMessage || 'Sign in to enable GitHub backup and cross-device sync.'}</small></span>
<button class="settings-primary" disabled={!isOnline || githubState === 'loading'} onclick={onConnectGithub}>
{#if githubState === 'loading'}<LoaderCircle class="spin" size={14} />{:else}<GithubIcon size={14} />{/if} Sign in with GitHub
</button>
</div>
{/if}
<div class="settings-actions">
<button class="settings-primary" disabled={!isOnline || !connected || !vault || backupState === 'backing-up'} onclick={onBackup}>
{#if backupState === 'backing-up'}<LoaderCircle class="spin" size={14} />{:else}<CloudUpload size={14} />{/if} Back up now
</button>
<button disabled={!isOnline || !connected || !vault} onclick={onRestore}><CloudDownload size={14} /> Restore a commit</button>
</div>
{:else if section === 'storage'}
<h3>Storage choices</h3>
<p class="settings-hint">Onyx always keeps a working vault on this device. Add a folder for accessible local files or GitHub for an off-device backup you can restore elsewhere.</p>
Expand Down Expand Up @@ -559,7 +549,7 @@
<section class="settings-storage-option">
<div><CloudUpload size={18} /><span><strong>GitHub backup and sync</strong><small>Optional off-device history for restoring this vault on another device.</small></span></div>
<p class="settings-hint">{connected ? githubBackup ? `Backing up to ${githubBackup.owner}/${githubBackup.repository}.` : 'Signed in. Choose a private repository to finish setup.' : 'Not enabled. Your local vault continues to work normally.'}</p>
<div class="settings-actions"><button onclick={() => (section = connected ? githubBackup ? 'backup' : 'repository' : 'github')}>{connected ? githubBackup ? 'View sync status' : 'Choose repository' : 'Learn about GitHub sync'}</button></div>
<div class="settings-actions"><button onclick={() => (section = 'github')}>{connected ? 'View backup & sync' : 'Learn about GitHub sync'}</button></div>
</section>
<div class="settings-actions">
<button disabled={usageState === 'loading'} onclick={() => void loadUsage()}><RefreshCw size={14} /> Refresh</button>
Expand Down
2 changes: 0 additions & 2 deletions src/lib/components/settings-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ export type SettingsSection =
| "themes"
| "shortcuts"
| "github"
| "repository"
| "backup"
| "storage"
| "transfer"
| "vault";
23 changes: 4 additions & 19 deletions src/routes/page-controller.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1051,25 +1051,10 @@ Press \`${commandPaletteShortcut}\` for the command palette, \`${saveShortcut}\`
group: "Settings",
label: "GitHub backup & sync settings",
icon: CloudUpload,
keywords: "account sign in backup cross device",
keywords:
"account sign in backup cross device repository branch directory remote status history commit pending changes",
run: () => openSettings("github"),
},
{
id: "settings-repository",
group: "Settings",
label: "Sync repository settings",
icon: FolderOutput,
keywords: "github repository branch directory remote",
run: () => openSettings("repository"),
},
{
id: "settings-backup",
group: "Settings",
label: "Sync status settings",
icon: CloudDownload,
keywords: "backup history commit pending changes",
run: () => openSettings("backup"),
},
{
id: "storage",
group: "Settings",
Expand Down Expand Up @@ -1387,7 +1372,7 @@ Press \`${commandPaletteShortcut}\` for the command palette, \`${saveShortcut}\`
if (!isOnline || !vault || backupState === "backing-up") return;
if (markdown !== lastSavedMarkdown && !(await saveDraft())) return;
if (!githubBackup) {
void openSettings("repository").catch(() => undefined);
void openSettings("github").catch(() => undefined);
return;
}
await runBackup(githubBackup);
Expand Down Expand Up @@ -1433,7 +1418,7 @@ Press \`${commandPaletteShortcut}\` for the command palette, \`${saveShortcut}\`
backupState = "idle";
backupCommitUrl = "";
backupMessage = `Backups now target ${state.owner}/${state.repository}.`;
settingsSection = "backup";
settingsSection = "github";
} catch (error) {
showBackupError(error);
}
Expand Down
14 changes: 9 additions & 5 deletions src/routes/page.svelte.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,6 @@ test("opens every settings section from the command palette", async ({ page }) =
["settings-themes", "Theme settings", "Themes"],
["shortcuts", "Keyboard shortcuts", "Keyboard shortcuts"],
["settings-github", "GitHub backup & sync settings", "Backup & sync"],
["settings-repository", "Sync repository settings", "Sync repository"],
["settings-backup", "Sync status settings", "Sync status"],
["storage", "Storage choices", "Storage choices"],
["settings-transfer", "Import & export settings", "Import & export"],
["settings-vault", "Vault settings", "Vault"],
Expand Down Expand Up @@ -804,6 +802,9 @@ test("keeps the editor usable and pauses GitHub features offline", async ({ cont
page.getByText("GitHub settings are paused until your connection returns."),
).toBeVisible();
await expect(page.getByRole("button", { name: "Sign in with GitHub" })).toBeDisabled();
await expect(page.getByRole("button", { name: "Sync repository", exact: true })).toHaveCount(0);
await expect(page.getByRole("button", { name: "Sync status", exact: true })).toHaveCount(0);
await expect(page.getByLabel("Repository", { exact: true })).toHaveCount(0);
await page.getByRole("button", { name: "Close settings" }).click();

const editor = page.getByRole("textbox", { name: "Markdown editor" });
Expand Down Expand Up @@ -1910,9 +1911,12 @@ test("binds a backup repository to the authenticated GitHub account", async ({ p
await page.goto("/");
await expect(page.getByText("@octocat").first()).toBeVisible({ timeout: 12_000 });
await page.getByRole("button", { name: "Settings", exact: true }).click();
await page.getByRole("button", { name: "Sync repository", exact: true }).click();
await page.getByRole("button", { name: "Backup & sync", exact: true }).click();
await page.getByLabel("Repository", { exact: true }).selectOption("octocat/onyx-vault");
await page.getByRole("button", { name: "Use this repository" }).click();
await expect(page.getByRole("heading", { name: "Sync status" })).toBeVisible();
await expect(page.getByRole("button", { name: "Sync repository", exact: true })).toHaveCount(0);
await expect(page.getByRole("button", { name: "Sync status", exact: true })).toHaveCount(0);

account = { id: 2, login: "hubot" };
await page.evaluate(() => window.dispatchEvent(new Event("online")));
Expand Down Expand Up @@ -1974,7 +1978,7 @@ test("refuses to upload a backup when its repository is public", async ({ page }
await page.goto("/");
await expect(page.getByText("@octocat").first()).toBeVisible({ timeout: 12_000 });
await page.getByRole("button", { name: "Settings", exact: true }).click();
await page.getByRole("button", { name: "Sync repository", exact: true }).click();
await page.getByRole("button", { name: "Backup & sync", exact: true }).click();
await page.getByLabel("Repository", { exact: true }).selectOption("octocat/onyx-vault");
await page.getByRole("button", { name: "Use this repository" }).click();

Expand Down Expand Up @@ -2166,7 +2170,7 @@ test("restores a selected GitHub commit into the local vault", async ({ page })
await page.keyboard.press("ControlOrMeta+S");
await waitForBlockedVaultWrite(page);
await page.getByRole("button", { name: "Settings", exact: true }).click();
await page.getByRole("button", { name: "Sync status" }).click();
await page.getByRole("button", { name: "Backup & sync", exact: true }).click();
await page.getByRole("button", { name: "Restore a commit" }).click();
await expect(page.getByRole("dialog", { name: "Choose a backup commit" })).toBeHidden({
timeout: 200,
Expand Down
Loading