upd wiki on chachy
This commit is contained in:
parent
64b5a82498
commit
f28dc954e8
|
|
@ -40,7 +40,8 @@
|
||||||
"Bash(paru -S --noconfirm visual-studio-code-bin)",
|
"Bash(paru -S --noconfirm visual-studio-code-bin)",
|
||||||
"Bash(code --version)",
|
"Bash(code --version)",
|
||||||
"Bash(code --install-extension svelte.svelte-vscode --install-extension bradlc.vscode-tailwindcss --install-extension esbenp.prettier-vscode --install-extension dbaeumer.vscode-eslint)",
|
"Bash(code --install-extension svelte.svelte-vscode --install-extension bradlc.vscode-tailwindcss --install-extension esbenp.prettier-vscode --install-extension dbaeumer.vscode-eslint)",
|
||||||
"Bash(git config:*)"
|
"Bash(git config:*)",
|
||||||
|
"Bash(FILE=\"/home/d-chrka@internal.lan/Projekte/chrka/Ka-Note/ka-note/client/src/routes/wiki/[id]/+page.svelte\"\npython3 - \"$FILE\" <<'EOF'\nimport sys\npath = sys.argv[1]\nwith open\\(path, 'r'\\) as f:\n content = f.read\\(\\)\n\nold = '\\\\t\\\\t\\\\t\\\\t<input\\\\n\\\\t\\\\t\\\\t\\\\t\\\\tclass=\"flex-1 bg-transparent text-2xl font-bold text-white outline-none placeholder:text-muted\"'\nnew = '\\\\t\\\\t\\\\t\\\\t<input\\\\n\\\\t\\\\t\\\\t\\\\t\\\\tbind:this={titleInputEl}\\\\n\\\\t\\\\t\\\\t\\\\t\\\\tclass=\"flex-1 bg-transparent text-2xl font-bold text-white outline-none placeholder:text-muted\"'\n\nif old in content:\n content = content.replace\\(old, new, 1\\)\n with open\\(path, 'w'\\) as f:\n f.write\\(content\\)\n print\\(\"replaced\"\\)\nelse:\n print\\(\"NOT FOUND\"\\)\n # debug: show actual bytes around the area\n idx = content.find\\('<input'\\)\n print\\(repr\\(content[idx:idx+100]\\)\\)\nEOF)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
1.2.37
|
1.2.47
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { db } from '$lib/db/schema';
|
import { db } from '$lib/db/schema';
|
||||||
import { upsertPage, softDeletePage, togglePageFavorite, getNotebooksForPage, getBacklinksForPage, assignPageToNotebook, removePageFromNotebook, getAllNotebooks } from '$lib/db/repositories';
|
import { upsertPage, softDeletePage, togglePageFavorite, getNotebooksForPage, getBacklinksForPage, assignPageToNotebook, removePageFromNotebook, getAllNotebooks, createPage } from '$lib/db/repositories';
|
||||||
import MarkdownEditor from '$lib/components/MarkdownEditor.svelte';
|
import MarkdownEditor from '$lib/components/MarkdownEditor.svelte';
|
||||||
import RenderedMarkdown from '$lib/components/RenderedMarkdown.svelte';
|
import RenderedMarkdown from '$lib/components/RenderedMarkdown.svelte';
|
||||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
let autosaveTimer: ReturnType<typeof setTimeout> | undefined;
|
let autosaveTimer: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
|
||||||
let titleInput = $state('');
|
let titleInput = $state('');
|
||||||
|
let titleInputEl = $state<HTMLInputElement | undefined>();
|
||||||
let editorRef: MarkdownEditor | undefined = $state();
|
let editorRef: MarkdownEditor | undefined = $state();
|
||||||
let notebooks = $state<Notebook[]>([]);
|
let notebooks = $state<Notebook[]>([]);
|
||||||
let backlinks = $state<Page[]>([]);
|
let backlinks = $state<Page[]>([]);
|
||||||
|
|
@ -37,9 +38,10 @@
|
||||||
// Re-initialize whenever pageId changes (SvelteKit reuses component on param navigation)
|
// Re-initialize whenever pageId changes (SvelteKit reuses component on param navigation)
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const id = pageId; // track reactively
|
const id = pageId; // track reactively
|
||||||
|
const openInEdit = page.url.searchParams.get('edit') === '1';
|
||||||
currentPage = undefined;
|
currentPage = undefined;
|
||||||
titleInitialized = false;
|
titleInitialized = false;
|
||||||
editing = false;
|
editing = openInEdit;
|
||||||
notebooks = [];
|
notebooks = [];
|
||||||
backlinks = [];
|
backlinks = [];
|
||||||
db.pages.get(id).then(p => {
|
db.pages.get(id).then(p => {
|
||||||
|
|
@ -58,6 +60,10 @@
|
||||||
if (currentPage && !titleInitialized) {
|
if (currentPage && !titleInitialized) {
|
||||||
titleInput = currentPage.title;
|
titleInput = currentPage.title;
|
||||||
titleInitialized = true;
|
titleInitialized = true;
|
||||||
|
if (editing) {
|
||||||
|
// focus title on next tick so the input is rendered
|
||||||
|
setTimeout(() => titleInputEl?.focus(), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -88,6 +94,14 @@
|
||||||
currentPage = { ...currentPage!, title };
|
currentPage = { ...currentPage!, title };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function addPage() {
|
||||||
|
const newPage = await createPage('Neue Seite', scope === 'private');
|
||||||
|
for (const nb of notebooks) {
|
||||||
|
await assignPageToNotebook(newPage.id, nb.id);
|
||||||
|
}
|
||||||
|
goto(`/wiki/${newPage.id}?edit=1`);
|
||||||
|
}
|
||||||
|
|
||||||
async function handleDelete() {
|
async function handleDelete() {
|
||||||
await softDeletePage(pageId);
|
await softDeletePage(pageId);
|
||||||
goto('/wiki');
|
goto('/wiki');
|
||||||
|
|
@ -118,6 +132,7 @@
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
{#if editing}
|
{#if editing}
|
||||||
<input
|
<input
|
||||||
|
bind:this={titleInputEl}
|
||||||
class="flex-1 bg-transparent text-2xl font-bold text-white outline-none placeholder:text-muted"
|
class="flex-1 bg-transparent text-2xl font-bold text-white outline-none placeholder:text-muted"
|
||||||
bind:value={titleInput}
|
bind:value={titleInput}
|
||||||
onblur={saveTitle}
|
onblur={saveTitle}
|
||||||
|
|
@ -153,6 +168,13 @@
|
||||||
>
|
>
|
||||||
{editing ? '✓ Fertig' : '✎ Bearbeiten'}
|
{editing ? '✓ Fertig' : '✎ Bearbeiten'}
|
||||||
</button>
|
</button>
|
||||||
|
{#if !editing}
|
||||||
|
<button
|
||||||
|
class="rounded px-3 py-1.5 text-sm font-medium bg-white/10 text-[#ccc] hover:bg-white/20 hover:text-white transition-colors"
|
||||||
|
onclick={addPage}
|
||||||
|
title="Neue Seite mit gleichem Scope und Notizbüchern anlegen"
|
||||||
|
>+ Neue Seite</button>
|
||||||
|
{/if}
|
||||||
{#if editing}
|
{#if editing}
|
||||||
<span class="text-xs {savedState === 'saved' ? 'text-muted' : savedState === 'saving' ? 'text-muted animate-pulse' : 'text-warning'}">
|
<span class="text-xs {savedState === 'saved' ? 'text-muted' : savedState === 'saving' ? 'text-muted animate-pulse' : 'text-warning'}">
|
||||||
{savedState === 'saved' ? '✓ gespeichert' : savedState === 'saving' ? '…' : '● ungespeichert'}
|
{savedState === 'saved' ? '✓ gespeichert' : savedState === 'saving' ? '…' : '● ungespeichert'}
|
||||||
|
|
@ -204,7 +226,8 @@
|
||||||
|
|
||||||
<!-- Content: read or edit -->
|
<!-- Content: read or edit -->
|
||||||
{#if editing}
|
{#if editing}
|
||||||
<div class="rounded border border-accent/40 bg-sidebar/50 p-3 min-h-[300px]">
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="rounded border border-accent/40 bg-sidebar/50 p-3 min-h-[300px]" ondblclick={(e) => { if (!(e.target as Element).closest('.cm-editor')) switchToRead(); }}>
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
bind:this={editorRef}
|
bind:this={editorRef}
|
||||||
content={currentPage.body}
|
content={currentPage.body}
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ export default defineConfig({
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
server: {
|
server: {
|
||||||
host: '127.0.0.1',
|
host: 'localhost',
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': 'http://127.0.0.1:9000'
|
'/api': 'http://localhost:9000'
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
'Cache-Control': 'no-store'
|
'Cache-Control': 'no-store'
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
<#
|
<#
|
||||||
.PARAMETER CheckOnly
|
.PARAMETER CheckOnly
|
||||||
Download and verify the prod DB without building or deploying.
|
Download and verify the prod DB without building or deploying.
|
||||||
|
.PARAMETER SkipDbBackup
|
||||||
|
Skip the DB download/verification step (use when DB hasn't changed since last run).
|
||||||
#>
|
#>
|
||||||
param([switch]$CheckOnly)
|
param([switch]$CheckOnly, [switch]$SkipDbBackup)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
|
@ -34,60 +36,66 @@ if ($CheckOnly) {
|
||||||
$checkLabel = if ($CheckOnly) { " [check-only]" } else { "" }
|
$checkLabel = if ($CheckOnly) { " [check-only]" } else { "" }
|
||||||
Write-Host "=== Version: $VERSION$checkLabel ===" -ForegroundColor Yellow
|
Write-Host "=== Version: $VERSION$checkLabel ===" -ForegroundColor Yellow
|
||||||
|
|
||||||
Write-Host "=== Backup DB from Prod ===" -ForegroundColor Cyan
|
|
||||||
$KuduToken = az account get-access-token --resource "https://management.azure.com" --query accessToken -o tsv
|
|
||||||
if ($LASTEXITCODE -ne 0) { throw "Failed to get Azure access token" }
|
|
||||||
$KuduDbUrl = "https://${APP}.scm.azurewebsites.net/api/vfs/data/ka-note.db"
|
$KuduDbUrl = "https://${APP}.scm.azurewebsites.net/api/vfs/data/ka-note.db"
|
||||||
|
$AppUrl = "https://$APP.azurewebsites.net"
|
||||||
$BackupDir = Join-Path $PSScriptRoot "backups"
|
$BackupDir = Join-Path $PSScriptRoot "backups"
|
||||||
$null = New-Item -ItemType Directory -Path $BackupDir -Force
|
$null = New-Item -ItemType Directory -Path $BackupDir -Force
|
||||||
$BackupFile = Join-Path $BackupDir ("ka-note-pre-deploy-$VERSION.db")
|
$BackupFile = Join-Path $BackupDir ("ka-note-pre-deploy-$VERSION.db")
|
||||||
|
|
||||||
# Flush WAL before download so the snapshot is consistent (WAL file not included in Kudu download).
|
if ($SkipDbBackup) {
|
||||||
$AppUrl = "https://$APP.azurewebsites.net"
|
Write-Host "=== Skipping DB Backup (-SkipDbBackup) ===" -ForegroundColor Yellow
|
||||||
if ($env:KA_NOTE_DEPLOY_API_KEY) {
|
$KuduToken = $null
|
||||||
Write-Host " Flushing WAL checkpoint before download..." -ForegroundColor DarkGray
|
|
||||||
try {
|
|
||||||
$cpResult = Invoke-RestMethod -Uri "$AppUrl/api/admin/checkpoint" -Method POST `
|
|
||||||
-Headers @{ Authorization = "Bearer $env:KA_NOTE_DEPLOY_API_KEY" } `
|
|
||||||
-UseBasicParsing -TimeoutSec 30
|
|
||||||
Write-Host " Checkpoint: $($cpResult.checkpointed)/$($cpResult.log) pages" -ForegroundColor DarkGray
|
|
||||||
} catch {
|
|
||||||
Write-Host " Checkpoint call failed (continuing anyway): $_" -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Write-Host " KA_NOTE_DEPLOY_API_KEY not set, skipping WAL checkpoint" -ForegroundColor Yellow
|
Write-Host "=== Backup DB from Prod ===" -ForegroundColor Cyan
|
||||||
}
|
$KuduToken = az account get-access-token --resource "https://management.azure.com" --query accessToken -o tsv
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "Failed to get Azure access token" }
|
||||||
|
|
||||||
Write-Host " Downloading ka-note.db from prod..." -ForegroundColor DarkGray
|
# Flush WAL before download so the snapshot is consistent (WAL file not included in Kudu download).
|
||||||
try {
|
if ($env:KA_NOTE_DEPLOY_API_KEY) {
|
||||||
Invoke-WebRequest -Uri $KuduDbUrl `
|
Write-Host " Flushing WAL checkpoint before download..." -ForegroundColor DarkGray
|
||||||
-Headers @{ Authorization = "Bearer $KuduToken" } `
|
try {
|
||||||
-OutFile $BackupFile -UseBasicParsing
|
$cpResult = Invoke-RestMethod -Uri "$AppUrl/api/admin/checkpoint" -Method POST `
|
||||||
} catch {
|
-Headers @{ Authorization = "Bearer $env:KA_NOTE_DEPLOY_API_KEY" } `
|
||||||
throw "Kudu DB download failed: $_"
|
-UseBasicParsing -TimeoutSec 30
|
||||||
}
|
Write-Host " Checkpoint: $($cpResult.checkpointed)/$($cpResult.log) pages" -ForegroundColor DarkGray
|
||||||
|
} catch {
|
||||||
|
Write-Host " Checkpoint call failed (continuing anyway): $_" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host " KA_NOTE_DEPLOY_API_KEY not set, skipping WAL checkpoint" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
$DbSize = (Get-Item $BackupFile).Length
|
Write-Host " Downloading ka-note.db from prod..." -ForegroundColor DarkGray
|
||||||
Write-Host " Downloaded: $([math]::Round($DbSize/1KB,1)) KB" -ForegroundColor DarkGray
|
try {
|
||||||
|
Invoke-WebRequest -Uri $KuduDbUrl `
|
||||||
|
-Headers @{ Authorization = "Bearer $KuduToken" } `
|
||||||
|
-OutFile $BackupFile -UseBasicParsing
|
||||||
|
} catch {
|
||||||
|
throw "Kudu DB download failed: $_"
|
||||||
|
}
|
||||||
|
|
||||||
if ($DbSize -lt 4096) {
|
$DbSize = (Get-Item $BackupFile).Length
|
||||||
throw "DB backup is suspiciously small ($DbSize bytes) - aborting deploy"
|
Write-Host " Downloaded: $([math]::Round($DbSize/1KB,1)) KB" -ForegroundColor DarkGray
|
||||||
}
|
|
||||||
|
|
||||||
# Verify with sqlite3 (must be in PATH)
|
if ($DbSize -lt 4096) {
|
||||||
$IntegrityResult = & sqlite3 $BackupFile "PRAGMA integrity_check;" 2>&1
|
throw "DB backup is suspiciously small ($DbSize bytes) - aborting deploy"
|
||||||
if ($LASTEXITCODE -ne 0 -or $IntegrityResult -ne 'ok') {
|
}
|
||||||
throw "DB integrity_check FAILED: $IntegrityResult - aborting deploy. Backup saved at $BackupFile"
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host " integrity_check: ok ($([math]::Round($DbSize/1KB,1)) KB)" -ForegroundColor Green
|
# Verify with sqlite3 (must be in PATH)
|
||||||
|
$IntegrityResult = & sqlite3 $BackupFile "PRAGMA integrity_check;" 2>&1
|
||||||
|
if ($LASTEXITCODE -ne 0 -or $IntegrityResult -ne 'ok') {
|
||||||
|
throw "DB integrity_check FAILED: $IntegrityResult - aborting deploy. Backup saved at $BackupFile"
|
||||||
|
}
|
||||||
|
|
||||||
if ($CheckOnly) {
|
Write-Host " integrity_check: ok ($([math]::Round($DbSize/1KB,1)) KB)" -ForegroundColor Green
|
||||||
Write-Host ""
|
|
||||||
Write-Host "=== Check passed -- no deploy performed ===" -ForegroundColor Green
|
if ($CheckOnly) {
|
||||||
Write-Host " Backup: $BackupFile" -ForegroundColor DarkGray
|
Write-Host ""
|
||||||
Write-Host ""
|
Write-Host "=== Check passed -- no deploy performed ===" -ForegroundColor Green
|
||||||
exit 0
|
Write-Host " Backup: $BackupFile" -ForegroundColor DarkGray
|
||||||
|
Write-Host ""
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Bump version now that DB check passed
|
# Bump version now that DB check passed
|
||||||
|
|
@ -209,6 +217,10 @@ while ($keepValidating) {
|
||||||
$keepValidating = $true
|
$keepValidating = $true
|
||||||
} elseif ($answer -eq 'yes') {
|
} elseif ($answer -eq 'yes') {
|
||||||
Write-Host " Uploading backup to prod..." -ForegroundColor Cyan
|
Write-Host " Uploading backup to prod..." -ForegroundColor Cyan
|
||||||
|
if (-not $KuduToken) {
|
||||||
|
$KuduToken = az account get-access-token --resource "https://management.azure.com" --query accessToken -o tsv
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "Failed to get Azure access token for restore" }
|
||||||
|
}
|
||||||
Invoke-WebRequest -Uri $KuduDbUrl `
|
Invoke-WebRequest -Uri $KuduDbUrl `
|
||||||
-Method PUT `
|
-Method PUT `
|
||||||
-Headers @{ Authorization = "Bearer $KuduToken" } `
|
-Headers @{ Authorization = "Bearer $KuduToken" } `
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,46 @@
|
||||||
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
||||||
|
CREATE TABLE `__new_contexts` (
|
||||||
|
`id` text NOT NULL,
|
||||||
|
`user_id` text NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`type` text NOT NULL,
|
||||||
|
`sort_order` integer DEFAULT 0 NOT NULL,
|
||||||
|
`meta` text,
|
||||||
|
`archived_at` text,
|
||||||
|
`is_favorite` integer DEFAULT false NOT NULL,
|
||||||
|
`updated_at` text NOT NULL,
|
||||||
|
`deleted_at` text,
|
||||||
|
`version` integer DEFAULT 1 NOT NULL,
|
||||||
|
PRIMARY KEY(`id`, `user_id`)
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
INSERT INTO `__new_contexts`("id", "user_id", "name", "type", "sort_order", "meta", "archived_at", "is_favorite", "updated_at", "deleted_at", "version") SELECT "id", '', "name", "type", "sort_order", "meta", "archived_at", "is_favorite", "updated_at", "deleted_at", "version" FROM `contexts`;--> statement-breakpoint
|
||||||
|
DROP TABLE `contexts`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `__new_contexts` RENAME TO `contexts`;--> statement-breakpoint
|
||||||
|
CREATE INDEX `contexts_updated_at_idx` ON `contexts` (`updated_at`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `contexts_user_id_idx` ON `contexts` (`user_id`);--> statement-breakpoint
|
||||||
|
CREATE TABLE `__new_topics` (
|
||||||
|
`id` text NOT NULL,
|
||||||
|
`user_id` text NOT NULL,
|
||||||
|
`context_id` text NOT NULL,
|
||||||
|
`title` text NOT NULL,
|
||||||
|
`status` text DEFAULT 'active' NOT NULL,
|
||||||
|
`snooze_until` text,
|
||||||
|
`sort_order` integer DEFAULT 0 NOT NULL,
|
||||||
|
`is_new` integer DEFAULT true NOT NULL,
|
||||||
|
`updated_at` text NOT NULL,
|
||||||
|
`deleted_at` text,
|
||||||
|
`version` integer DEFAULT 1 NOT NULL,
|
||||||
|
PRIMARY KEY(`id`, `user_id`),
|
||||||
|
FOREIGN KEY (`context_id`,`user_id`) REFERENCES `contexts`(`id`,`user_id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
INSERT INTO `__new_topics`("id", "user_id", "context_id", "title", "status", "snooze_until", "sort_order", "is_new", "updated_at", "deleted_at", "version") SELECT "id", '', "context_id", "title", "status", "snooze_until", "sort_order", "is_new", "updated_at", "deleted_at", "version" FROM `topics`;--> statement-breakpoint
|
||||||
|
DROP TABLE `topics`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `__new_topics` RENAME TO `topics`;--> statement-breakpoint
|
||||||
|
CREATE INDEX `topics_updated_at_idx` ON `topics` (`updated_at`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `topics_context_id_idx` ON `topics` (`context_id`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `topics_user_id_idx` ON `topics` (`user_id`);--> statement-breakpoint
|
||||||
CREATE TABLE `__new_history_entries` (
|
CREATE TABLE `__new_history_entries` (
|
||||||
`id` text NOT NULL,
|
`id` text NOT NULL,
|
||||||
`user_id` text NOT NULL,
|
`user_id` text NOT NULL,
|
||||||
|
|
@ -18,7 +60,6 @@ CREATE TABLE `__new_history_entries` (
|
||||||
INSERT INTO `__new_history_entries`("id", "user_id", "topic_id", "date", "text", "sort_order", "linked_context_id", "done_at", "updated_at", "deleted_at", "version") SELECT "id", '', "topic_id", "date", "text", "sort_order", "linked_context_id", "done_at", "updated_at", "deleted_at", "version" FROM `history_entries`;--> statement-breakpoint
|
INSERT INTO `__new_history_entries`("id", "user_id", "topic_id", "date", "text", "sort_order", "linked_context_id", "done_at", "updated_at", "deleted_at", "version") SELECT "id", '', "topic_id", "date", "text", "sort_order", "linked_context_id", "done_at", "updated_at", "deleted_at", "version" FROM `history_entries`;--> statement-breakpoint
|
||||||
DROP TABLE `history_entries`;--> statement-breakpoint
|
DROP TABLE `history_entries`;--> statement-breakpoint
|
||||||
ALTER TABLE `__new_history_entries` RENAME TO `history_entries`;--> statement-breakpoint
|
ALTER TABLE `__new_history_entries` RENAME TO `history_entries`;--> statement-breakpoint
|
||||||
PRAGMA foreign_keys=ON;--> statement-breakpoint
|
|
||||||
CREATE INDEX `history_entries_updated_at_idx` ON `history_entries` (`updated_at`);--> statement-breakpoint
|
CREATE INDEX `history_entries_updated_at_idx` ON `history_entries` (`updated_at`);--> statement-breakpoint
|
||||||
CREATE INDEX `history_entries_topic_id_idx` ON `history_entries` (`topic_id`);--> statement-breakpoint
|
CREATE INDEX `history_entries_topic_id_idx` ON `history_entries` (`topic_id`);--> statement-breakpoint
|
||||||
CREATE INDEX `history_entries_user_id_idx` ON `history_entries` (`user_id`);--> statement-breakpoint
|
CREATE INDEX `history_entries_user_id_idx` ON `history_entries` (`user_id`);--> statement-breakpoint
|
||||||
|
|
@ -44,45 +85,4 @@ ALTER TABLE `__new_ratings` RENAME TO `ratings`;--> statement-breakpoint
|
||||||
CREATE INDEX `ratings_updated_at_idx` ON `ratings` (`updated_at`);--> statement-breakpoint
|
CREATE INDEX `ratings_updated_at_idx` ON `ratings` (`updated_at`);--> statement-breakpoint
|
||||||
CREATE INDEX `ratings_topic_id_idx` ON `ratings` (`topic_id`);--> statement-breakpoint
|
CREATE INDEX `ratings_topic_id_idx` ON `ratings` (`topic_id`);--> statement-breakpoint
|
||||||
CREATE INDEX `ratings_user_id_idx` ON `ratings` (`user_id`);--> statement-breakpoint
|
CREATE INDEX `ratings_user_id_idx` ON `ratings` (`user_id`);--> statement-breakpoint
|
||||||
CREATE TABLE `__new_topics` (
|
PRAGMA foreign_keys=ON;
|
||||||
`id` text NOT NULL,
|
|
||||||
`user_id` text NOT NULL,
|
|
||||||
`context_id` text NOT NULL,
|
|
||||||
`title` text NOT NULL,
|
|
||||||
`status` text DEFAULT 'active' NOT NULL,
|
|
||||||
`snooze_until` text,
|
|
||||||
`sort_order` integer DEFAULT 0 NOT NULL,
|
|
||||||
`is_new` integer DEFAULT true NOT NULL,
|
|
||||||
`updated_at` text NOT NULL,
|
|
||||||
`deleted_at` text,
|
|
||||||
`version` integer DEFAULT 1 NOT NULL,
|
|
||||||
PRIMARY KEY(`id`, `user_id`),
|
|
||||||
FOREIGN KEY (`context_id`,`user_id`) REFERENCES `contexts`(`id`,`user_id`) ON UPDATE no action ON DELETE no action
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
INSERT INTO `__new_topics`("id", "user_id", "context_id", "title", "status", "snooze_until", "sort_order", "is_new", "updated_at", "deleted_at", "version") SELECT "id", '', "context_id", "title", "status", "snooze_until", "sort_order", "is_new", "updated_at", "deleted_at", "version" FROM `topics`;--> statement-breakpoint
|
|
||||||
DROP TABLE `topics`;--> statement-breakpoint
|
|
||||||
ALTER TABLE `__new_topics` RENAME TO `topics`;--> statement-breakpoint
|
|
||||||
CREATE INDEX `topics_updated_at_idx` ON `topics` (`updated_at`);--> statement-breakpoint
|
|
||||||
CREATE INDEX `topics_context_id_idx` ON `topics` (`context_id`);--> statement-breakpoint
|
|
||||||
CREATE INDEX `topics_user_id_idx` ON `topics` (`user_id`);--> statement-breakpoint
|
|
||||||
CREATE TABLE `__new_contexts` (
|
|
||||||
`id` text NOT NULL,
|
|
||||||
`user_id` text NOT NULL,
|
|
||||||
`name` text NOT NULL,
|
|
||||||
`type` text NOT NULL,
|
|
||||||
`sort_order` integer DEFAULT 0 NOT NULL,
|
|
||||||
`meta` text,
|
|
||||||
`archived_at` text,
|
|
||||||
`is_favorite` integer DEFAULT false NOT NULL,
|
|
||||||
`updated_at` text NOT NULL,
|
|
||||||
`deleted_at` text,
|
|
||||||
`version` integer DEFAULT 1 NOT NULL,
|
|
||||||
PRIMARY KEY(`id`, `user_id`)
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
INSERT INTO `__new_contexts`("id", "user_id", "name", "type", "sort_order", "meta", "archived_at", "is_favorite", "updated_at", "deleted_at", "version") SELECT "id", '', "name", "type", "sort_order", "meta", "archived_at", "is_favorite", "updated_at", "deleted_at", "version" FROM `contexts`;--> statement-breakpoint
|
|
||||||
DROP TABLE `contexts`;--> statement-breakpoint
|
|
||||||
ALTER TABLE `__new_contexts` RENAME TO `contexts`;--> statement-breakpoint
|
|
||||||
CREATE INDEX `contexts_updated_at_idx` ON `contexts` (`updated_at`);--> statement-breakpoint
|
|
||||||
CREATE INDEX `contexts_user_id_idx` ON `contexts` (`user_id`);
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -48,7 +48,7 @@ router.post('/', handle('api-keys/create', async (c) => {
|
||||||
|
|
||||||
router.delete('/:id', handle('api-keys/delete', async (c) => {
|
router.delete('/:id', handle('api-keys/delete', async (c) => {
|
||||||
const { userId } = c.get('auth');
|
const { userId } = c.get('auth');
|
||||||
const id = c.req.param('id');
|
const id = c.req.param('id')!;
|
||||||
|
|
||||||
const result = await db
|
const result = await db
|
||||||
.update(apiKeys)
|
.update(apiKeys)
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ backup.get('/list', handle('backup/list', async (c) => {
|
||||||
|
|
||||||
// Download a stored backup file
|
// Download a stored backup file
|
||||||
backup.get('/download/:filename', handle('backup/download', async (c) => {
|
backup.get('/download/:filename', handle('backup/download', async (c) => {
|
||||||
const filename = c.req.param('filename');
|
const filename = c.req.param('filename')!;
|
||||||
let filePath: string;
|
let filePath: string;
|
||||||
try {
|
try {
|
||||||
filePath = backupFilePath(filename);
|
filePath = backupFilePath(filename);
|
||||||
|
|
@ -85,7 +85,7 @@ backup.get('/download/:filename', handle('backup/download', async (c) => {
|
||||||
|
|
||||||
// Delete a stored backup
|
// Delete a stored backup
|
||||||
backup.delete('/:filename', handle('backup/delete', async (c) => {
|
backup.delete('/:filename', handle('backup/delete', async (c) => {
|
||||||
const filename = c.req.param('filename');
|
const filename = c.req.param('filename')!;
|
||||||
try {
|
try {
|
||||||
await deleteBackup(filename);
|
await deleteBackup(filename);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ sync.get('/pull', handle('sync/pull', async (c) => {
|
||||||
|
|
||||||
sync.get('/blob/:id', handle('sync/blob', async (c) => {
|
sync.get('/blob/:id', handle('sync/blob', async (c) => {
|
||||||
const { userId } = c.get('auth');
|
const { userId } = c.get('auth');
|
||||||
const id = c.req.param('id');
|
const id = c.req.param('id')!;
|
||||||
const blob = await fetchBlob(id, userId);
|
const blob = await fetchBlob(id, userId);
|
||||||
if (!blob) return c.json({ error: 'Not found' }, 404);
|
if (!blob) return c.json({ error: 'Not found' }, 404);
|
||||||
return c.json(blob);
|
return c.json(blob);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue