@knotpad/app 0.1.0 → 0.1.1
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/bin/brief.js +165 -78
- package/package.json +3 -17
- package/app/(app)/calendar/page.tsx +0 -57
- package/app/(app)/error.tsx +0 -35
- package/app/(app)/graph/page.tsx +0 -32
- package/app/(app)/guide/page.tsx +0 -21
- package/app/(app)/kanban/loading.tsx +0 -24
- package/app/(app)/kanban/page.tsx +0 -59
- package/app/(app)/layout.tsx +0 -122
- package/app/(app)/list/loading.tsx +0 -21
- package/app/(app)/list/page.tsx +0 -137
- package/app/(app)/loading.tsx +0 -18
- package/app/(app)/notes/[noteId]/page.tsx +0 -84
- package/app/(app)/notes/layout.tsx +0 -30
- package/app/(app)/notes/page.tsx +0 -39
- package/app/(app)/page.tsx +0 -5
- package/app/(app)/settings/agent-token/page.tsx +0 -59
- package/app/(app)/settings/backup/page.tsx +0 -49
- package/app/(app)/settings/billing/page.tsx +0 -53
- package/app/(app)/settings/calendar/page.tsx +0 -41
- package/app/(app)/settings/layout.test.tsx +0 -39
- package/app/(app)/settings/layout.tsx +0 -71
- package/app/(app)/settings/page.tsx +0 -4
- package/app/(app)/settings/security/page.tsx +0 -43
- package/app/(app)/settings/team/page.tsx +0 -74
- package/app/(app)/settings/workspace/page.tsx +0 -27
- package/app/(app)/tasks/[taskId]/page.tsx +0 -79
- package/app/(auth)/forgot-password/page.tsx +0 -106
- package/app/(auth)/guest/page.tsx +0 -56
- package/app/(auth)/layout.tsx +0 -13
- package/app/(auth)/login/page.tsx +0 -14
- package/app/(auth)/register/page.tsx +0 -193
- package/app/(auth)/reset-password/page.tsx +0 -138
- package/app/api/account/claim/route.tsx +0 -135
- package/app/api/admin/backfill-encryption/route.tsx +0 -43
- package/app/api/admin/license/route.tsx +0 -42
- package/app/api/auth/2fa/route.tsx +0 -148
- package/app/api/auth/[...nextauth]/route.tsx +0 -3
- package/app/api/auth/change-password/route.tsx +0 -61
- package/app/api/auth/check-2fa/route.tsx +0 -19
- package/app/api/auth/forgot-password/route.tsx +0 -65
- package/app/api/auth/reset-password/route.tsx +0 -52
- package/app/api/auth/verify-2fa/route.tsx +0 -88
- package/app/api/backup/download/db/route.ts +0 -29
- package/app/api/backup/download/notes/route.ts +0 -25
- package/app/api/backup/settings/route.ts +0 -92
- package/app/api/billing/checkout/route.tsx +0 -81
- package/app/api/billing/migrate/route.tsx +0 -163
- package/app/api/billing/portal/route.tsx +0 -24
- package/app/api/billing/setup-intent/route.tsx +0 -55
- package/app/api/billing/status/route.tsx +0 -36
- package/app/api/billing/subscribe/route.tsx +0 -85
- package/app/api/billing/webhook/route.tsx +0 -199
- package/app/api/calendar-feeds/[feedId]/route.tsx +0 -67
- package/app/api/calendar-feeds/[feedId]/sync/route.tsx +0 -37
- package/app/api/calendar-feeds/events/route.tsx +0 -82
- package/app/api/calendar-feeds/route.tsx +0 -52
- package/app/api/calendar-feeds/sync-all/route.tsx +0 -34
- package/app/api/cron/calendar-feeds/route.tsx +0 -31
- package/app/api/cron/stale-tasks/route.tsx +0 -51
- package/app/api/cron/sync/route.tsx +0 -34
- package/app/api/devices/[deviceId]/route.tsx +0 -25
- package/app/api/devices/route.tsx +0 -41
- package/app/api/export/route.tsx +0 -40
- package/app/api/feedback/route.tsx +0 -54
- package/app/api/folders/[folderId]/route.tsx +0 -51
- package/app/api/folders/route.tsx +0 -37
- package/app/api/graph/route.tsx +0 -242
- package/app/api/guest/route.tsx +0 -58
- package/app/api/health/route.tsx +0 -10
- package/app/api/holidays/countries/route.tsx +0 -14
- package/app/api/holidays/route.tsx +0 -49
- package/app/api/holidays/states/route.tsx +0 -21
- package/app/api/invites/[token]/route.tsx +0 -131
- package/app/api/invites/route.tsx +0 -74
- package/app/api/mcp/generate-token/route.tsx +0 -55
- package/app/api/mcp/revoke-token/[tokenId]/route.tsx +0 -30
- package/app/api/mcp/update-alias/[tokenId]/route.tsx +0 -22
- package/app/api/notes/[noteId]/export/route.tsx +0 -45
- package/app/api/notes/[noteId]/route.tsx +0 -360
- package/app/api/notes/route.tsx +0 -112
- package/app/api/notifications/route.tsx +0 -44
- package/app/api/register/route.tsx +0 -67
- package/app/api/restore/route.tsx +0 -148
- package/app/api/sync/conflicts/[conflictId]/route.tsx +0 -134
- package/app/api/sync/conflicts/route.tsx +0 -48
- package/app/api/sync/status/route.tsx +0 -49
- package/app/api/sync/trigger/route.tsx +0 -15
- package/app/api/tasks/[taskId]/detail/route.tsx +0 -68
- package/app/api/tasks/[taskId]/route.tsx +0 -259
- package/app/api/tasks/bulk/route.tsx +0 -133
- package/app/api/tasks/route.tsx +0 -36
- package/app/api/workspace/active/route.tsx +0 -39
- package/app/api/workspace/create-team/route.tsx +0 -42
- package/app/api/workspace/kanban-statuses/route.tsx +0 -71
- package/app/api/workspace/members/[memberId]/route.tsx +0 -69
- package/app/api/workspace/route.tsx +0 -24
- package/app/download/page.tsx +0 -170
- package/app/favicon.ico +0 -0
- package/app/generated/prisma/client.d.ts +0 -1
- package/app/generated/prisma/client.js +0 -5
- package/app/generated/prisma/default.d.ts +0 -1
- package/app/generated/prisma/default.js +0 -5
- package/app/generated/prisma/edge.d.ts +0 -1
- package/app/generated/prisma/edge.js +0 -497
- package/app/generated/prisma/index-browser.js +0 -523
- package/app/generated/prisma/index.d.ts +0 -46376
- package/app/generated/prisma/index.js +0 -497
- package/app/generated/prisma/package.json +0 -144
- package/app/generated/prisma/query_compiler_fast_bg.js +0 -2
- package/app/generated/prisma/query_compiler_fast_bg.wasm +0 -0
- package/app/generated/prisma/query_compiler_fast_bg.wasm-base64.js +0 -2
- package/app/generated/prisma/runtime/client.d.ts +0 -3386
- package/app/generated/prisma/runtime/client.js +0 -86
- package/app/generated/prisma/runtime/index-browser.d.ts +0 -90
- package/app/generated/prisma/runtime/index-browser.js +0 -6
- package/app/generated/prisma/runtime/wasm-compiler-edge.js +0 -76
- package/app/generated/prisma/schema.prisma +0 -456
- package/app/generated/prisma/wasm-edge-light-loader.mjs +0 -5
- package/app/generated/prisma/wasm-worker-loader.mjs +0 -5
- package/app/globals.css +0 -54
- package/app/invite/[token]/page.tsx +0 -52
- package/app/layout.tsx +0 -90
- package/app/mcp/route.tsx +0 -430
- package/app/opengraph-image.tsx +0 -120
- package/app/page.tsx +0 -398
- package/app/privacy/page.tsx +0 -69
- package/app/robots.tsx +0 -25
- package/app/sitemap.tsx +0 -36
- package/app/terms/page.tsx +0 -69
- package/app/upgrade/page.tsx +0 -75
- package/auth.config.ts +0 -33
- package/auth.ts +0 -79
- package/components/auth/login-form.tsx +0 -302
- package/components/auth/password-checklist.tsx +0 -31
- package/components/auth/password-input.tsx +0 -36
- package/components/auth/switch-account-button.test.tsx +0 -22
- package/components/auth/switch-account-button.tsx +0 -19
- package/components/auth/two-factor-input.tsx +0 -116
- package/components/billing/billing-dashboard.tsx +0 -265
- package/components/billing/card-form.tsx +0 -210
- package/components/billing/claim-account-form.tsx +0 -99
- package/components/branding/app-logo.test.tsx +0 -20
- package/components/branding/app-logo.tsx +0 -25
- package/components/calendar/calendar-agenda.tsx +0 -150
- package/components/calendar/calendar-drag.test.tsx +0 -177
- package/components/calendar/calendar-grid.tsx +0 -357
- package/components/calendar/calendar-hooks.test.tsx +0 -27
- package/components/calendar/calendar-hooks.ts +0 -351
- package/components/calendar/calendar-toolbar.test.tsx +0 -68
- package/components/calendar/calendar-toolbar.tsx +0 -291
- package/components/calendar/calendar-types.ts +0 -148
- package/components/calendar/calendar-view.test.tsx +0 -295
- package/components/calendar/calendar-view.tsx +0 -307
- package/components/calendar/day-detail-popover.tsx +0 -174
- package/components/calendar/task-chip.tsx +0 -86
- package/components/command/command-palette.test.tsx +0 -33
- package/components/command/command-palette.tsx +0 -310
- package/components/download-cta.tsx +0 -87
- package/components/feedback/feedback-popup.tsx +0 -207
- package/components/graph/graph-draw.ts +0 -337
- package/components/graph/graph-overlays.tsx +0 -160
- package/components/graph/graph-page.test.tsx +0 -131
- package/components/graph/graph-page.tsx +0 -263
- package/components/graph/graph-types.ts +0 -47
- package/components/graph/graph-view.tsx +0 -322
- package/components/guide/guide-view.tsx +0 -522
- package/components/kanban/kanban-board.test.tsx +0 -128
- package/components/kanban/kanban-board.tsx +0 -361
- package/components/kanban/kanban-card-menu.tsx +0 -102
- package/components/kanban/kanban-card.tsx +0 -227
- package/components/kanban/kanban-column.tsx +0 -49
- package/components/kanban/kanban-status-context.tsx +0 -28
- package/components/landing/calendar-sandbox.test.tsx +0 -15
- package/components/landing/calendar-sandbox.tsx +0 -107
- package/components/landing/graph-sandbox.test.tsx +0 -27
- package/components/landing/graph-sandbox.tsx +0 -80
- package/components/landing/kanban-sandbox.test.tsx +0 -24
- package/components/landing/kanban-sandbox.tsx +0 -101
- package/components/landing/landing-showcase.test.tsx +0 -21
- package/components/landing/landing-showcase.tsx +0 -54
- package/components/landing/list-sandbox.tsx +0 -86
- package/components/landing/mock-workspace.ts +0 -168
- package/components/landing/notes-sandbox.test.tsx +0 -14
- package/components/landing/notes-sandbox.tsx +0 -88
- package/components/layout/app-shell.tsx +0 -83
- package/components/layout/backup-scheduler.tsx +0 -122
- package/components/layout/bottom-nav.tsx +0 -43
- package/components/layout/icon-bar.test.tsx +0 -29
- package/components/layout/icon-bar.tsx +0 -118
- package/components/layout/mobile-top-bar.tsx +0 -68
- package/components/layout/notes-panel-folder.tsx +0 -127
- package/components/layout/notes-panel-note-item.tsx +0 -140
- package/components/layout/notes-panel-task-tab.tsx +0 -63
- package/components/layout/notes-panel-types.ts +0 -44
- package/components/layout/notes-panel.tsx +0 -476
- package/components/layout/notification-bell.tsx +0 -251
- package/components/layout/paywall-screen.tsx +0 -41
- package/components/layout/pro-banner.tsx +0 -76
- package/components/layout/sw-register.tsx +0 -27
- package/components/layout/workspace-switcher.tsx +0 -90
- package/components/notes/mobile-bottom-sheet.tsx +0 -99
- package/components/notes/note-editor-context-menu.tsx +0 -47
- package/components/notes/note-editor-dom.ts +0 -33
- package/components/notes/note-editor-dropdowns.tsx +0 -484
- package/components/notes/note-editor-hooks.ts +0 -692
- package/components/notes/note-editor-keyboard.ts +0 -305
- package/components/notes/note-editor-overlay.tsx +0 -90
- package/components/notes/note-editor.test.tsx +0 -372
- package/components/notes/note-editor.tsx +0 -662
- package/components/notes/note-preview-pane.tsx +0 -156
- package/components/notes/note-tabs.tsx +0 -120
- package/components/notes/note-types.tsx +0 -157
- package/components/settings/accept-invite.tsx +0 -108
- package/components/settings/agent-token-settings.tsx +0 -369
- package/components/settings/backup-restore-settings.test.tsx +0 -25
- package/components/settings/backup-restore-settings.tsx +0 -327
- package/components/settings/calendar-feeds-settings.tsx +0 -489
- package/components/settings/calendar-general-settings.tsx +0 -174
- package/components/settings/confirm-danger-action.test.tsx +0 -215
- package/components/settings/confirm-danger-action.tsx +0 -65
- package/components/settings/security-settings.tsx +0 -252
- package/components/settings/settings-guidance.test.tsx +0 -98
- package/components/settings/team-settings.tsx +0 -319
- package/components/settings/two-factor-auth.tsx +0 -296
- package/components/settings/workspace-settings-client.tsx +0 -363
- package/components/settings/workspace-settings-form.tsx +0 -73
- package/components/sync/conflict-viewer.tsx +0 -247
- package/components/sync/sync-indicator.tsx +0 -171
- package/components/tasks/snippet-thread.tsx +0 -119
- package/components/tasks/status-dot.tsx +0 -47
- package/components/tasks/task-badge.tsx +0 -43
- package/components/tasks/task-detail.test.tsx +0 -187
- package/components/tasks/task-detail.tsx +0 -458
- package/components/tasks/task-list-filters.test.tsx +0 -75
- package/components/tasks/task-list-filters.tsx +0 -163
- package/components/tasks/task-list-types.ts +0 -20
- package/components/tasks/task-list.test.tsx +0 -175
- package/components/tasks/task-list.tsx +0 -481
- package/components/tasks/task-row.tsx +0 -85
- package/components/tasks/task-table-row.tsx +0 -259
- package/components/ui/skeleton.tsx +0 -3
- package/components/ui/toast.test.tsx +0 -42
- package/components/ui/toast.tsx +0 -70
- package/electron/main.ts +0 -251
- package/electron/preload.ts +0 -56
- package/instrumentation.tsx +0 -23
- package/lib/api-error.ts +0 -50
- package/lib/backup/backup-runner.test.ts +0 -32
- package/lib/backup/backup-runner.ts +0 -19
- package/lib/backup/backup-schedule.test.ts +0 -23
- package/lib/backup/backup-schedule.ts +0 -55
- package/lib/backup/backup-settings.test.ts +0 -30
- package/lib/backup/backup-settings.ts +0 -27
- package/lib/backup/export-notes-zip.test.ts +0 -26
- package/lib/backup/export-notes-zip.ts +0 -82
- package/lib/backup/export-workspace-backup.test.ts +0 -17
- package/lib/backup/export-workspace-backup.ts +0 -77
- package/lib/backup/restore-workspace-from-export.test.ts +0 -18
- package/lib/backup/restore-workspace-from-export.ts +0 -183
- package/lib/backup/types.ts +0 -14
- package/lib/brand-icons.ts +0 -1
- package/lib/calendar-feed-crypto.ts +0 -38
- package/lib/calendar-feed.ts +0 -239
- package/lib/client/online-status.ts +0 -47
- package/lib/conflict-resolver.test.ts +0 -57
- package/lib/conflict-resolver.ts +0 -240
- package/lib/db-init.ts +0 -79
- package/lib/email.ts +0 -159
- package/lib/encryption.test.ts +0 -41
- package/lib/encryption.ts +0 -98
- package/lib/extract-snippet.test.ts +0 -123
- package/lib/extract-snippet.ts +0 -69
- package/lib/kanban-status.ts +0 -55
- package/lib/license.ts +0 -21
- package/lib/limits.ts +0 -31
- package/lib/mcp-auth.test.ts +0 -58
- package/lib/mcp-auth.ts +0 -65
- package/lib/mcp-contract.test.ts +0 -25
- package/lib/mcp-contract.ts +0 -210
- package/lib/mcp-handler.ts +0 -31
- package/lib/mcp-url.test.ts +0 -12
- package/lib/mcp-url.ts +0 -7
- package/lib/mentions.test.ts +0 -45
- package/lib/mentions.ts +0 -73
- package/lib/note-crypto.ts +0 -108
- package/lib/note-sync.ts +0 -201
- package/lib/note-title.ts +0 -93
- package/lib/prisma.ts +0 -193
- package/lib/pro-flush.ts +0 -292
- package/lib/rate-limit.ts +0 -57
- package/lib/stripe.ts +0 -38
- package/lib/sync-worker.ts +0 -388
- package/lib/task-parser.test.ts +0 -91
- package/lib/task-parser.ts +0 -81
- package/lib/task-utils.ts +0 -52
- package/lib/use-is-electron.ts +0 -19
- package/lib/use-is-mobile.ts +0 -22
- package/lib/validation/calendar-feed.ts +0 -31
- package/lib/validation/note.ts +0 -27
- package/lib/validation/task.ts +0 -26
- package/lib/view-preferences.test.ts +0 -54
- package/lib/view-preferences.ts +0 -28
- package/lib/workspace.ts +0 -66
- package/next.config.ts +0 -21
- package/postcss.config.mjs +0 -7
- package/prisma/migrations/20260519021916_init/migration.sql +0 -388
- package/prisma/migrations/20260519061113_drop_sync_password/migration.sql +0 -8
- package/prisma/migrations/20260520065016_add_task_start_date/migration.sql +0 -2
- package/prisma/migrations/20260529010600_remove_encryption_fields/migration.sql +0 -12
- package/prisma/migrations/20260529020000_restore_encryption_salt/migration.sql +0 -3
- package/prisma/migrations/20260529030000_add_folders/migration.sql +0 -17
- package/prisma/migrations/20260605000000_deferred_fixes/migration.sql +0 -31
- package/prisma/migrations/20260605020806_add_pending_sync_to_note_and_task/migration.sql +0 -5
- package/prisma/migrations/20260605063634_add_stripe_webhook_event_sync_lock/migration.sql +0 -14
- package/prisma/migrations/20260605100000_add_prod_indexes/migration.sql +0 -26
- package/prisma/migrations/20260608081404_add_kanban_statuses/migration.sql +0 -23
- package/prisma/migrations/20260611032723_add_calendar_feeds/migration.sql +0 -43
- package/prisma/migrations/20260611040000_add_calendar_feed_color/migration.sql +0 -2
- package/prisma/migrations/20260611050000_add_task_priority/migration.sql +0 -14
- package/prisma/migrations/20260612060000_add_critical_priority/migration.sql +0 -2
- package/prisma/migrations/20260613090000_add_backup_settings/migration.sql +0 -25
- package/prisma/migrations/20260614160000_add_feedback/migration.sql +0 -20
- package/prisma/migrations/20260614210000_add_2fa/migration.sql +0 -4
- package/prisma/migrations/migration_lock.toml +0 -3
- package/prisma/schema.prisma +0 -457
- package/public/Logo_icon.svg +0 -1
- package/public/file.svg +0 -1
- package/public/globe.svg +0 -1
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/icon.svg +0 -4
- package/public/icon_dark.svg +0 -1
- package/public/knotpad_icon.svg +0 -1
- package/public/knotpad_logo_full.svg +0 -1
- package/public/manifest.json +0 -14
- package/public/next.svg +0 -1
- package/public/sw.js +0 -137
- package/public/vercel.svg +0 -1
- package/public/window.svg +0 -1
- package/tsconfig.json +0 -35
package/bin/brief.js
CHANGED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
*
|
|
8
8
|
* What it does:
|
|
9
9
|
* 1. Checks Node version
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
12
|
-
* 4.
|
|
10
|
+
* 2. Downloads/clones the Knotpad source code if not present
|
|
11
|
+
* 3. Finds or creates a .env file in the current directory
|
|
12
|
+
* 4. Generates NEXTAUTH_SECRET / MCP_SECRET if not present
|
|
13
|
+
* 5. Starts the Next.js server on port 3099
|
|
13
14
|
* → PGlite (embedded local DB) bootstraps automatically at startup
|
|
14
15
|
* via instrumentation.tsx → lib/prisma.ts + lib/db-init.ts
|
|
15
|
-
*
|
|
16
|
+
* 6. Opens an app-mode window (Chrome/Edge — no address bar) or falls back to browser
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
"use strict";
|
|
@@ -21,6 +22,7 @@ const { execSync, spawn } = require("child_process");
|
|
|
21
22
|
const fs = require("fs");
|
|
22
23
|
const path = require("path");
|
|
23
24
|
const { randomBytes } = require("crypto");
|
|
25
|
+
const https = require("https");
|
|
24
26
|
|
|
25
27
|
// ── Helpers ────────────────────────────────────────────────────────────────────
|
|
26
28
|
|
|
@@ -40,6 +42,67 @@ function openBrowser(url) {
|
|
|
40
42
|
try { execSync(cmd, { stdio: "ignore" }); } catch {}
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
// ── Download source code ──────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
async function downloadSource() {
|
|
48
|
+
const INSTALL_DIR = path.join(WORK_DIR, ".brief", "app");
|
|
49
|
+
|
|
50
|
+
if (fs.existsSync(INSTALL_DIR)) {
|
|
51
|
+
log("Knotpad source already installed");
|
|
52
|
+
return INSTALL_DIR;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
log("Downloading Knotpad source (this may take a minute)…");
|
|
56
|
+
fs.mkdirSync(path.dirname(INSTALL_DIR), { recursive: true });
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
// Try git clone first (faster and more reliable)
|
|
60
|
+
execSync(`git clone --depth 1 https://github.com/knotpad/brief.git "${INSTALL_DIR}"`, {
|
|
61
|
+
stdio: "inherit",
|
|
62
|
+
cwd: path.dirname(INSTALL_DIR)
|
|
63
|
+
});
|
|
64
|
+
ok("Source downloaded via git");
|
|
65
|
+
return INSTALL_DIR;
|
|
66
|
+
} catch (e) {
|
|
67
|
+
// Fallback: download zip from GitHub
|
|
68
|
+
log("Git not available, downloading zip…");
|
|
69
|
+
const zipPath = path.join(path.dirname(INSTALL_DIR), "brief.zip");
|
|
70
|
+
|
|
71
|
+
await new Promise((resolve, reject) => {
|
|
72
|
+
const file = fs.createWriteStream(zipPath);
|
|
73
|
+
https.get("https://github.com/knotpad/brief/archive/refs/heads/main.zip", (response) => {
|
|
74
|
+
response.pipe(file);
|
|
75
|
+
file.on("finish", () => {
|
|
76
|
+
file.close();
|
|
77
|
+
log("Extracting…");
|
|
78
|
+
try {
|
|
79
|
+
if (process.platform === "win32") {
|
|
80
|
+
execSync(`tar -xf "${zipPath}" -C "${path.dirname(INSTALL_DIR)}"`, { stdio: "inherit" });
|
|
81
|
+
} else {
|
|
82
|
+
execSync(`unzip -q "${zipPath}" -d "${path.dirname(INSTALL_DIR)}"`, { stdio: "inherit" });
|
|
83
|
+
}
|
|
84
|
+
fs.unlinkSync(zipPath);
|
|
85
|
+
// Move the extracted folder to the expected location
|
|
86
|
+
const extractedDir = path.join(path.dirname(INSTALL_DIR), "brief-main");
|
|
87
|
+
if (fs.existsSync(extractedDir)) {
|
|
88
|
+
fs.renameSync(extractedDir, INSTALL_DIR);
|
|
89
|
+
}
|
|
90
|
+
ok("Source downloaded and extracted");
|
|
91
|
+
resolve();
|
|
92
|
+
} catch (err) {
|
|
93
|
+
reject(err);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}).on("error", (err) => {
|
|
97
|
+
if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath);
|
|
98
|
+
reject(err);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return INSTALL_DIR;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
43
106
|
// ── Chrome / Edge app-mode detection ──────────────────────────────────────────
|
|
44
107
|
|
|
45
108
|
/**
|
|
@@ -131,94 +194,118 @@ function openAppWindow(url) {
|
|
|
131
194
|
const [major] = process.versions.node.split(".").map(Number);
|
|
132
195
|
if (major < 18) die(`Node 18+ required (you have ${process.versions.node}). Install from https://nodejs.org`);
|
|
133
196
|
|
|
134
|
-
// ── 2.
|
|
197
|
+
// ── 2. Download source ───────────────────────────────────────────────────────────
|
|
135
198
|
|
|
136
|
-
const PKG_DIR = path.resolve(__dirname, "..");
|
|
137
199
|
const WORK_DIR = process.cwd();
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
200
|
+
let PKG_DIR;
|
|
201
|
+
|
|
202
|
+
async function main() {
|
|
203
|
+
PKG_DIR = await downloadSource();
|
|
204
|
+
|
|
205
|
+
// ── 3. Install dependencies ─────────────────────────────────────────────────────
|
|
206
|
+
|
|
207
|
+
const NODE_MODULES = path.join(PKG_DIR, "node_modules");
|
|
208
|
+
if (!fs.existsSync(NODE_MODULES)) {
|
|
209
|
+
log("Installing dependencies (this may take a minute)…");
|
|
210
|
+
try {
|
|
211
|
+
execSync("npm install", { cwd: PKG_DIR, stdio: "inherit" });
|
|
212
|
+
ok("Dependencies installed");
|
|
213
|
+
} catch (e) {
|
|
214
|
+
die("Failed to install dependencies. Please run manually: cd .brief/app && npm install");
|
|
215
|
+
}
|
|
146
216
|
}
|
|
147
|
-
log(".env found, loading existing config");
|
|
148
|
-
} else {
|
|
149
|
-
log("Creating .env with defaults…");
|
|
150
|
-
}
|
|
151
217
|
|
|
152
|
-
//
|
|
153
|
-
// Port 3099 avoids clashing with dev servers (3000) commonly running alongside.
|
|
154
|
-
const defaults = {
|
|
155
|
-
NEXTAUTH_SECRET: genSecret(),
|
|
156
|
-
NEXTAUTH_URL: "http://localhost:3099",
|
|
157
|
-
MCP_SECRET: genSecret(),
|
|
158
|
-
ENCRYPTION_PEPPER: genSecret(),
|
|
159
|
-
NEXT_PUBLIC_APP_URL: "http://localhost:3099",
|
|
160
|
-
NEXT_PUBLIC_MCP_URL: "http://localhost:3099/mcp",
|
|
161
|
-
IS_CLOUD: "false",
|
|
162
|
-
CRON_SECRET: genSecret(16),
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
let changed = false;
|
|
166
|
-
for (const [k, v] of Object.entries(defaults)) {
|
|
167
|
-
if (!env[k]) { env[k] = v; changed = true; }
|
|
168
|
-
}
|
|
218
|
+
// ── 4. .env setup ──────────────────────────────────────────────────────────────
|
|
169
219
|
|
|
170
|
-
|
|
171
|
-
const lines = Object.entries(env).map(([k, v]) => `${k}="${v}"`).join("\n");
|
|
172
|
-
fs.writeFileSync(ENV_PATH, lines + "\n", "utf8");
|
|
173
|
-
ok(".env written");
|
|
174
|
-
}
|
|
220
|
+
const ENV_PATH = path.join(WORK_DIR, ".env");
|
|
175
221
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
222
|
+
let env = {};
|
|
223
|
+
if (fs.existsSync(ENV_PATH)) {
|
|
224
|
+
const raw = fs.readFileSync(ENV_PATH, "utf8");
|
|
225
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
226
|
+
const m = /^([A-Z_][A-Z0-9_]*)=(.*)$/.exec(line.trim());
|
|
227
|
+
if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, "");
|
|
228
|
+
}
|
|
229
|
+
log(".env found, loading existing config");
|
|
230
|
+
} else {
|
|
231
|
+
log("Creating .env with defaults…");
|
|
232
|
+
}
|
|
180
233
|
|
|
181
|
-
//
|
|
234
|
+
// Fill defaults — no DATABASE_URL needed; PGlite handles local storage automatically
|
|
235
|
+
// Port 3099 avoids clashing with dev servers (3000) commonly running alongside.
|
|
236
|
+
const defaults = {
|
|
237
|
+
NEXTAUTH_SECRET: genSecret(),
|
|
238
|
+
NEXTAUTH_URL: "http://localhost:3099",
|
|
239
|
+
MCP_SECRET: genSecret(),
|
|
240
|
+
ENCRYPTION_PEPPER: genSecret(),
|
|
241
|
+
NEXT_PUBLIC_APP_URL: "http://localhost:3099",
|
|
242
|
+
NEXT_PUBLIC_MCP_URL: "http://localhost:3099/mcp",
|
|
243
|
+
IS_CLOUD: "false",
|
|
244
|
+
CRON_SECRET: genSecret(16),
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
let changed = false;
|
|
248
|
+
for (const [k, v] of Object.entries(defaults)) {
|
|
249
|
+
if (!env[k]) { env[k] = v; changed = true; }
|
|
250
|
+
}
|
|
182
251
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
log("Building Knotpad (first run — takes ~30 seconds)…");
|
|
188
|
-
try {
|
|
189
|
-
execSync("npx next build", { cwd: PKG_DIR, stdio: "inherit", env: process.env });
|
|
190
|
-
ok("Build complete");
|
|
191
|
-
} catch {
|
|
192
|
-
die("Build failed. Run `npx @knotpad/app` again after fixing any errors.");
|
|
252
|
+
if (changed) {
|
|
253
|
+
const lines = Object.entries(env).map(([k, v]) => `${k}="${v}"`).join("\n");
|
|
254
|
+
fs.writeFileSync(ENV_PATH, lines + "\n", "utf8");
|
|
255
|
+
ok(".env written");
|
|
193
256
|
}
|
|
194
|
-
}
|
|
195
257
|
|
|
196
|
-
//
|
|
258
|
+
// Apply env for this process
|
|
259
|
+
for (const [k, v] of Object.entries(env)) {
|
|
260
|
+
process.env[k] = v;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ── 5. Build (if not already built) ───────────────────────────────────────────
|
|
264
|
+
|
|
265
|
+
// BUILD_ID is only written after a successful build — a leftover .next/ from a
|
|
266
|
+
// failed build won't have it, so we correctly re-run in that case.
|
|
267
|
+
const BUILD_ID = path.join(PKG_DIR, ".next", "BUILD_ID");
|
|
268
|
+
if (!fs.existsSync(BUILD_ID)) {
|
|
269
|
+
log("Building Knotpad (first run — takes ~30 seconds)…");
|
|
270
|
+
try {
|
|
271
|
+
execSync("npx next build", { cwd: PKG_DIR, stdio: "inherit", env: process.env });
|
|
272
|
+
ok("Build complete");
|
|
273
|
+
} catch {
|
|
274
|
+
die("Build failed. Run `npx @knotpad/app` again after fixing any errors.");
|
|
275
|
+
}
|
|
276
|
+
}
|
|
197
277
|
|
|
198
|
-
//
|
|
199
|
-
fs.mkdirSync(path.join(WORK_DIR, ".brief", "db"), { recursive: true });
|
|
278
|
+
// ── 6. Start server ────────────────────────────────────────────────────────────
|
|
200
279
|
|
|
201
|
-
|
|
202
|
-
|
|
280
|
+
// Pre-create PGlite data directory so the app can open it immediately at startup
|
|
281
|
+
fs.mkdirSync(path.join(WORK_DIR, ".brief", "db"), { recursive: true });
|
|
203
282
|
|
|
204
|
-
|
|
205
|
-
|
|
283
|
+
const PORT = parseInt(process.env.PORT ?? "3099", 10);
|
|
284
|
+
const URL = `http://localhost:${PORT}`;
|
|
206
285
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
cwd: PKG_DIR,
|
|
210
|
-
stdio: "inherit",
|
|
211
|
-
env: process.env,
|
|
212
|
-
});
|
|
286
|
+
ok(`\nStarting Knotpad on ${URL}\n`);
|
|
287
|
+
process.stdout.write(` ${"\x1b[2m"}Ctrl+C to stop${"\x1b[0m"}\n\n`);
|
|
213
288
|
|
|
214
|
-
|
|
215
|
-
server.
|
|
216
|
-
|
|
217
|
-
|
|
289
|
+
const NEXT_BIN = path.join(PKG_DIR, "node_modules", "next", "dist", "bin", "next");
|
|
290
|
+
const server = spawn(process.execPath, [NEXT_BIN, "start", "--port", String(PORT)], {
|
|
291
|
+
cwd: PKG_DIR,
|
|
292
|
+
stdio: "inherit",
|
|
293
|
+
env: process.env,
|
|
294
|
+
});
|
|
218
295
|
|
|
219
|
-
|
|
220
|
-
|
|
296
|
+
server.on("error", (e) => die(`Failed to start server: ${e.message}`));
|
|
297
|
+
server.on("exit", (code) => {
|
|
298
|
+
if (code !== 0 && code !== null) die(`Server exited with code ${code}`);
|
|
299
|
+
});
|
|
221
300
|
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
301
|
+
// Open in app-mode Chrome/Edge window (falls back to browser if not found)
|
|
302
|
+
setTimeout(() => openAppWindow(URL), 1500);
|
|
303
|
+
|
|
304
|
+
// Graceful exit
|
|
305
|
+
process.on("SIGINT", () => { server.kill("SIGINT"); process.exit(0); });
|
|
306
|
+
process.on("SIGTERM", () => { server.kill("SIGTERM"); process.exit(0); });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
main().catch((err) => {
|
|
310
|
+
die(`Error: ${err.message}`);
|
|
311
|
+
});
|
package/package.json
CHANGED
|
@@ -1,28 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knotpad/app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Note-first project management with AI agent task routing",
|
|
5
5
|
"bin": {
|
|
6
|
-
"knotpad": "
|
|
6
|
+
"knotpad": "bin/brief.js"
|
|
7
7
|
},
|
|
8
8
|
"main": "dist-electron/main.js",
|
|
9
9
|
"files": [
|
|
10
10
|
"package.json",
|
|
11
|
-
"
|
|
12
|
-
"app",
|
|
13
|
-
"components",
|
|
14
|
-
"lib",
|
|
15
|
-
"prisma",
|
|
16
|
-
"public",
|
|
17
|
-
"bin",
|
|
18
|
-
"electron",
|
|
19
|
-
"auth.ts",
|
|
20
|
-
"auth.config.ts",
|
|
21
|
-
"middleware.ts",
|
|
22
|
-
"tailwind.config.ts",
|
|
23
|
-
"tsconfig.json",
|
|
24
|
-
"postcss.config.mjs",
|
|
25
|
-
"instrumentation.tsx"
|
|
11
|
+
"bin"
|
|
26
12
|
],
|
|
27
13
|
"publishConfig": {
|
|
28
14
|
"access": "public"
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { auth } from "@/auth";
|
|
2
|
-
import { redirect } from "next/navigation";
|
|
3
|
-
import { prisma } from "@/lib/prisma";
|
|
4
|
-
import { getActiveWorkspaceId } from "@/lib/workspace";
|
|
5
|
-
import { CalendarView } from "@/components/calendar/calendar-view";
|
|
6
|
-
|
|
7
|
-
export default async function CalendarPage({
|
|
8
|
-
searchParams,
|
|
9
|
-
}: {
|
|
10
|
-
searchParams: Promise<{ note?: string; month?: string; folder?: string }>;
|
|
11
|
-
}) {
|
|
12
|
-
const session = await auth();
|
|
13
|
-
if (!session) redirect("/login");
|
|
14
|
-
|
|
15
|
-
const { note: filterNoteId, month, folder: filterFolderId } = await searchParams;
|
|
16
|
-
|
|
17
|
-
const workspaceId = await getActiveWorkspaceId(session.user.id);
|
|
18
|
-
if (!workspaceId) redirect("/login");
|
|
19
|
-
|
|
20
|
-
const tasks = await prisma.task.findMany({
|
|
21
|
-
where: {
|
|
22
|
-
workspaceId,
|
|
23
|
-
...(filterNoteId ? { noteId: filterNoteId } : {}),
|
|
24
|
-
...(filterFolderId && { note: { folderId: filterFolderId } }),
|
|
25
|
-
status: { not: "DONE" },
|
|
26
|
-
},
|
|
27
|
-
orderBy: { dueDate: "asc" },
|
|
28
|
-
include: {
|
|
29
|
-
note: { select: { id: true, title: true } },
|
|
30
|
-
assignee: { select: { id: true, name: true } },
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const serialized = tasks.map((t) => ({
|
|
35
|
-
id: t.id,
|
|
36
|
-
title: t.title,
|
|
37
|
-
status: t.status,
|
|
38
|
-
startDate: t.startDate?.toISOString() ?? null,
|
|
39
|
-
dueDate: t.dueDate?.toISOString() ?? null,
|
|
40
|
-
noteId: t.noteId,
|
|
41
|
-
noteTitle: t.note.title,
|
|
42
|
-
assigneeName: t.assignee?.name ?? null,
|
|
43
|
-
assigneeType: t.assigneeType,
|
|
44
|
-
claimedByAlias: t.claimedByAlias,
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<div className="flex flex-1 flex-col overflow-hidden">
|
|
49
|
-
<div className="border-b border-zinc-800 px-6 py-3">
|
|
50
|
-
<h1 className="text-sm font-semibold text-zinc-300">
|
|
51
|
-
{filterFolderId ? "Filtered tasks" : "Calendar"}
|
|
52
|
-
</h1>
|
|
53
|
-
</div>
|
|
54
|
-
<CalendarView tasks={serialized} initialMonth={month} filterNoteId={filterNoteId} filterFolderId={filterFolderId} />
|
|
55
|
-
</div>
|
|
56
|
-
);
|
|
57
|
-
}
|
package/app/(app)/error.tsx
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useEffect } from "react";
|
|
4
|
-
import { AlertTriangle } from "lucide-react";
|
|
5
|
-
|
|
6
|
-
export default function Error({
|
|
7
|
-
error,
|
|
8
|
-
reset,
|
|
9
|
-
}: {
|
|
10
|
-
error: Error & { digest?: string };
|
|
11
|
-
reset: () => void;
|
|
12
|
-
}) {
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
// Surfaces in the server/console; hook a real error tracker here later.
|
|
15
|
-
console.error(error);
|
|
16
|
-
}, [error]);
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div className="flex flex-1 flex-col items-center justify-center gap-4 p-8 text-center">
|
|
20
|
-
<AlertTriangle size={28} className="text-amber-500" />
|
|
21
|
-
<div className="space-y-1">
|
|
22
|
-
<p className="text-sm font-medium text-zinc-300">Something went wrong</p>
|
|
23
|
-
<p className="max-w-sm text-xs text-zinc-600">
|
|
24
|
-
This view failed to load. You can retry, or head back to your notes.
|
|
25
|
-
</p>
|
|
26
|
-
</div>
|
|
27
|
-
<button
|
|
28
|
-
onClick={reset}
|
|
29
|
-
className="rounded-md border border-zinc-700 px-3 py-1.5 text-sm text-zinc-300 transition-colors ring-focus hover:bg-zinc-800 hover:text-zinc-100"
|
|
30
|
-
>
|
|
31
|
-
Try again
|
|
32
|
-
</button>
|
|
33
|
-
</div>
|
|
34
|
-
);
|
|
35
|
-
}
|
package/app/(app)/graph/page.tsx
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { auth } from "@/auth";
|
|
2
|
-
import { redirect } from "next/navigation";
|
|
3
|
-
import { prisma } from "@/lib/prisma";
|
|
4
|
-
import { GraphPage } from "@/components/graph/graph-page";
|
|
5
|
-
|
|
6
|
-
export default async function GraphRoute({
|
|
7
|
-
searchParams,
|
|
8
|
-
}: {
|
|
9
|
-
searchParams: Promise<{ notes?: string }>;
|
|
10
|
-
}) {
|
|
11
|
-
const session = await auth();
|
|
12
|
-
if (!session) redirect("/login");
|
|
13
|
-
|
|
14
|
-
const { notes: notesParam } = await searchParams;
|
|
15
|
-
const selectedNoteIds = notesParam ? notesParam.split(",").filter(Boolean) : [];
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<div className="flex flex-1 flex-col overflow-hidden">
|
|
19
|
-
<div className="border-b border-zinc-800 px-6 py-3">
|
|
20
|
-
<h1 className="text-sm font-semibold text-zinc-300">
|
|
21
|
-
Graph
|
|
22
|
-
{selectedNoteIds.length > 0 && (
|
|
23
|
-
<span className="ml-2 text-xs font-normal text-zinc-500">
|
|
24
|
-
— {selectedNoteIds.length} note{selectedNoteIds.length > 1 ? "s" : ""} selected
|
|
25
|
-
</span>
|
|
26
|
-
)}
|
|
27
|
-
</h1>
|
|
28
|
-
</div>
|
|
29
|
-
<GraphPage selectedNoteIds={selectedNoteIds} />
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
32
|
-
}
|
package/app/(app)/guide/page.tsx
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { auth } from "@/auth";
|
|
2
|
-
import { redirect } from "next/navigation";
|
|
3
|
-
import { GuideView } from "@/components/guide/guide-view";
|
|
4
|
-
|
|
5
|
-
export const metadata = {
|
|
6
|
-
title: "User Guide - Knotpad",
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export default async function GuidePage() {
|
|
10
|
-
const session = await auth();
|
|
11
|
-
if (!session) redirect("/login");
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<div className="flex flex-1 flex-col overflow-hidden">
|
|
15
|
-
<div className="border-b border-zinc-800 px-6 py-3">
|
|
16
|
-
<h1 className="text-sm font-semibold text-zinc-300">User Guide</h1>
|
|
17
|
-
</div>
|
|
18
|
-
<GuideView />
|
|
19
|
-
</div>
|
|
20
|
-
);
|
|
21
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
-
|
|
3
|
-
export default function KanbanLoading() {
|
|
4
|
-
return (
|
|
5
|
-
<div className="flex flex-1 flex-col overflow-hidden">
|
|
6
|
-
<div className="border-b border-zinc-800 px-6 py-3">
|
|
7
|
-
<Skeleton className="h-4 w-20" />
|
|
8
|
-
</div>
|
|
9
|
-
<div className="flex flex-1 flex-col gap-3 overflow-hidden p-3 md:flex-row md:p-4">
|
|
10
|
-
{[0, 1, 2].map((c) => (
|
|
11
|
-
<div
|
|
12
|
-
key={c}
|
|
13
|
-
className="flex w-full shrink-0 flex-col gap-2 rounded-lg border border-zinc-800 bg-zinc-900/40 p-2 md:w-64"
|
|
14
|
-
>
|
|
15
|
-
<Skeleton className="mb-1 h-4 w-24" />
|
|
16
|
-
{[0, 1, 2].map((card) => (
|
|
17
|
-
<Skeleton key={card} className="h-14 w-full" />
|
|
18
|
-
))}
|
|
19
|
-
</div>
|
|
20
|
-
))}
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { auth } from "@/auth";
|
|
2
|
-
import { redirect } from "next/navigation";
|
|
3
|
-
import { prisma } from "@/lib/prisma";
|
|
4
|
-
import { getActiveWorkspaceId } from "@/lib/workspace";
|
|
5
|
-
import { KanbanBoard } from "@/components/kanban/kanban-board";
|
|
6
|
-
|
|
7
|
-
export default async function KanbanPage({
|
|
8
|
-
searchParams,
|
|
9
|
-
}: {
|
|
10
|
-
searchParams: Promise<{ note?: string; folder?: string }>;
|
|
11
|
-
}) {
|
|
12
|
-
const session = await auth();
|
|
13
|
-
if (!session) redirect("/login");
|
|
14
|
-
|
|
15
|
-
const { note: filterNoteId, folder: filterFolderId } = await searchParams;
|
|
16
|
-
|
|
17
|
-
const workspaceId = await getActiveWorkspaceId(session.user.id);
|
|
18
|
-
if (!workspaceId) redirect("/login");
|
|
19
|
-
|
|
20
|
-
const tasks = await prisma.task.findMany({
|
|
21
|
-
where: {
|
|
22
|
-
workspaceId,
|
|
23
|
-
...(filterNoteId && { noteId: filterNoteId }),
|
|
24
|
-
...(filterFolderId && { note: { folderId: filterFolderId } }),
|
|
25
|
-
},
|
|
26
|
-
orderBy: { createdAt: "asc" },
|
|
27
|
-
include: {
|
|
28
|
-
note: { select: { id: true, title: true, folder: { select: { id: true, name: true } } } },
|
|
29
|
-
assignee: { select: { id: true, name: true, email: true } },
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Serialize dates for the client component
|
|
34
|
-
const serialized = tasks.map((t) => ({
|
|
35
|
-
id: t.id,
|
|
36
|
-
title: t.title,
|
|
37
|
-
status: t.status,
|
|
38
|
-
claimedBy: t.claimedBy,
|
|
39
|
-
claimedByAlias: t.claimedByAlias,
|
|
40
|
-
lastHeartbeat: t.lastHeartbeat?.toISOString() ?? null,
|
|
41
|
-
assigneeType: t.assigneeType,
|
|
42
|
-
assignee: t.assignee,
|
|
43
|
-
note: t.note,
|
|
44
|
-
dueDate: t.dueDate?.toISOString() ?? null,
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<div className="flex flex-1 flex-col overflow-hidden">
|
|
49
|
-
<div className="border-b border-zinc-800 px-6 py-3">
|
|
50
|
-
<h1 className="text-sm font-semibold text-zinc-300">
|
|
51
|
-
{filterNoteId || filterFolderId ? "Filtered tasks" : "Kanban"}
|
|
52
|
-
</h1>
|
|
53
|
-
</div>
|
|
54
|
-
<div className="flex-1 overflow-hidden">
|
|
55
|
-
<KanbanBoard tasks={serialized} filterNoteId={filterNoteId} filterFolderId={filterFolderId} />
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
);
|
|
59
|
-
}
|