jettypod 4.4.118 → 4.4.121
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/.env +4 -3
- package/Cargo.lock +6450 -0
- package/Cargo.toml +35 -0
- package/README.md +5 -1
- package/TAURI-MIGRATION-PLAN.md +840 -0
- package/apps/dashboard/app/connect-claude/page.tsx +5 -6
- package/apps/dashboard/app/decision/[id]/page.tsx +63 -58
- package/apps/dashboard/app/demo/gates/page.tsx +43 -45
- package/apps/dashboard/app/design-system/page.tsx +868 -0
- package/apps/dashboard/app/globals.css +80 -4
- package/apps/dashboard/app/install-claude/page.tsx +4 -6
- package/apps/dashboard/app/login/page.tsx +72 -54
- package/apps/dashboard/app/page.tsx +101 -48
- package/apps/dashboard/app/settings/page.tsx +61 -13
- package/apps/dashboard/app/signup/page.tsx +242 -0
- package/apps/dashboard/app/subscribe/page.tsx +0 -2
- package/apps/dashboard/app/tests/page.tsx +37 -4
- package/apps/dashboard/app/welcome/page.tsx +13 -16
- package/apps/dashboard/app/work/[id]/page.tsx +117 -118
- package/apps/dashboard/app/work/[id]/proof/page.tsx +1489 -0
- package/apps/dashboard/components/AppShell.tsx +92 -85
- package/apps/dashboard/components/CardMenu.tsx +45 -12
- package/apps/dashboard/components/ClaudePanel.tsx +771 -850
- package/apps/dashboard/components/ClaudePanelInput.tsx +43 -15
- package/apps/dashboard/components/ConnectClaudeScreen.tsx +17 -34
- package/apps/dashboard/components/CopyableId.tsx +3 -4
- package/apps/dashboard/components/DetailReviewActions.tsx +100 -0
- package/apps/dashboard/components/DragContext.tsx +134 -63
- package/apps/dashboard/components/DraggableCard.tsx +3 -5
- package/apps/dashboard/components/DropZone.tsx +6 -7
- package/apps/dashboard/components/EditableDetailDescription.tsx +7 -13
- package/apps/dashboard/components/EditableDetailTitle.tsx +6 -13
- package/apps/dashboard/components/EditableTitle.tsx +26 -7
- package/apps/dashboard/components/ElapsedTimer.tsx +66 -0
- package/apps/dashboard/components/EpicGroup.tsx +359 -0
- package/apps/dashboard/components/GateCard.tsx +79 -17
- package/apps/dashboard/components/GateChoiceCard.tsx +15 -18
- package/apps/dashboard/components/InstallClaudeScreen.tsx +15 -32
- package/apps/dashboard/components/JettyLoader.tsx +37 -0
- package/apps/dashboard/components/KanbanBoard.tsx +368 -958
- package/apps/dashboard/components/KanbanCard.tsx +740 -0
- package/apps/dashboard/components/LazyCard.tsx +62 -0
- package/apps/dashboard/components/LazyMarkdown.tsx +11 -0
- package/apps/dashboard/components/MainNav.tsx +38 -73
- package/apps/dashboard/components/MessageBlock.tsx +468 -0
- package/apps/dashboard/components/ModeStartCard.tsx +15 -16
- package/apps/dashboard/components/OnboardingWelcome.tsx +213 -0
- package/apps/dashboard/components/PlaceholderCard.tsx +3 -4
- package/apps/dashboard/components/ProjectSwitcher.tsx +30 -30
- package/apps/dashboard/components/PrototypeTimeline.tsx +72 -51
- package/apps/dashboard/components/RealTimeKanbanWrapper.tsx +406 -388
- package/apps/dashboard/components/RealTimeTestsWrapper.tsx +373 -235
- package/apps/dashboard/components/ReviewFooter.tsx +139 -0
- package/apps/dashboard/components/SessionList.tsx +19 -19
- package/apps/dashboard/components/SubscribeContent.tsx +91 -47
- package/apps/dashboard/components/TestTree.tsx +16 -16
- package/apps/dashboard/components/TipCard.tsx +16 -17
- package/apps/dashboard/components/Toast.tsx +5 -6
- package/apps/dashboard/components/TypeIcon.tsx +55 -0
- package/apps/dashboard/components/ViewModeToolbar.tsx +104 -0
- package/apps/dashboard/components/WaveCompletionAnimation.tsx +52 -65
- package/apps/dashboard/components/WelcomeScreen.tsx +19 -35
- package/apps/dashboard/components/WorkItemHeader.tsx +4 -5
- package/apps/dashboard/components/WorkItemTree.tsx +11 -32
- package/apps/dashboard/components/settings/AccountSection.tsx +55 -35
- package/apps/dashboard/components/settings/AiContextSection.tsx +89 -0
- package/apps/dashboard/components/settings/ContextDocumentsSection.tsx +317 -0
- package/apps/dashboard/components/settings/EnvVarsSection.tsx +74 -152
- package/apps/dashboard/components/settings/GeneralSection.tsx +162 -56
- package/apps/dashboard/components/settings/ProjectStackSection.tsx +948 -0
- package/apps/dashboard/components/settings/SettingsLayout.tsx +4 -5
- package/apps/dashboard/components/ui/Button.tsx +104 -0
- package/apps/dashboard/components/ui/Input.tsx +78 -0
- package/apps/dashboard/components.json +1 -1
- package/apps/dashboard/contexts/ClaudeSessionContext.tsx +711 -418
- package/apps/dashboard/contexts/ConnectionStatusContext.tsx +25 -5
- package/apps/dashboard/contexts/UsageContext.tsx +87 -32
- package/apps/dashboard/dev.sh +35 -0
- package/apps/dashboard/eslint.config.mjs +9 -9
- package/apps/dashboard/hooks/useKanbanAnimation.ts +29 -0
- package/apps/dashboard/hooks/useKanbanUndo.ts +83 -0
- package/apps/dashboard/hooks/useWebSocket.ts +138 -83
- package/apps/dashboard/index.html +73 -0
- package/apps/dashboard/lib/constants.ts +43 -0
- package/apps/dashboard/lib/data-bridge.ts +722 -0
- package/apps/dashboard/lib/db.ts +69 -1265
- package/apps/dashboard/lib/environment-config.ts +173 -0
- package/apps/dashboard/lib/environment-verification.ts +119 -0
- package/apps/dashboard/lib/kanban-utils.ts +270 -0
- package/apps/dashboard/lib/proof-run.ts +495 -0
- package/apps/dashboard/lib/proof-scenario-runner.ts +346 -0
- package/apps/dashboard/lib/run-migrations.js +27 -2
- package/apps/dashboard/lib/service-recovery.ts +326 -0
- package/apps/dashboard/lib/session-state-machine.ts +1 -0
- package/apps/dashboard/lib/session-state-utils.ts +0 -164
- package/apps/dashboard/lib/session-stream-manager.ts +308 -134
- package/apps/dashboard/lib/shadows.ts +7 -0
- package/apps/dashboard/lib/stream-manager-registry.ts +46 -6
- package/apps/dashboard/lib/tauri-bridge.ts +102 -0
- package/apps/dashboard/lib/tauri.ts +106 -0
- package/apps/dashboard/lib/utils.ts +6 -0
- package/apps/dashboard/next-env.d.ts +1 -1
- package/apps/dashboard/package.json +21 -32
- package/apps/dashboard/public/bug-icon.png +0 -0
- package/apps/dashboard/public/buoy-icon.png +0 -0
- package/apps/dashboard/public/fonts/Satoshi-Variable.woff2 +0 -0
- package/apps/dashboard/public/fonts/Satoshi-VariableItalic.woff2 +0 -0
- package/apps/dashboard/public/in-flight-seagull.png +0 -0
- package/apps/dashboard/public/jetty-icon-loading-alt.svg +11 -0
- package/apps/dashboard/public/jetty-icon-loading.svg +11 -0
- package/apps/dashboard/public/jettypod_logo.png +0 -0
- package/apps/dashboard/public/pier-icon.png +0 -0
- package/apps/dashboard/public/star-icon.png +0 -0
- package/apps/dashboard/public/wrench-icon.png +0 -0
- package/apps/dashboard/scripts/tauri-build.js +228 -0
- package/apps/dashboard/scripts/upload-tauri-to-r2.js +125 -0
- package/apps/dashboard/scripts/ws-server.js +191 -0
- package/apps/dashboard/src/main.tsx +12 -0
- package/apps/dashboard/src/router.tsx +107 -0
- package/apps/dashboard/src/vite-env.d.ts +1 -0
- package/apps/dashboard/tsconfig.json +7 -12
- package/apps/dashboard/tsconfig.tsbuildinfo +1 -1
- package/apps/dashboard/vite.config.ts +33 -0
- package/apps/update-server/src/index.ts +228 -80
- package/claude-hooks/global-guardrails.js +14 -13
- package/crates/jettypod-cli/Cargo.toml +19 -0
- package/crates/jettypod-cli/src/commands.rs +1249 -0
- package/crates/jettypod-cli/src/main.rs +595 -0
- package/crates/jettypod-core/Cargo.toml +26 -0
- package/crates/jettypod-core/build.rs +98 -0
- package/crates/jettypod-core/migrations/V1__baseline.sql +197 -0
- package/crates/jettypod-core/migrations/V2__work_items_indexes.sql +6 -0
- package/crates/jettypod-core/migrations/V3__qa_steps.sql +2 -0
- package/crates/jettypod-core/src/auth.rs +294 -0
- package/crates/jettypod-core/src/config.rs +397 -0
- package/crates/jettypod-core/src/db/mod.rs +507 -0
- package/crates/jettypod-core/src/db/recovery.rs +114 -0
- package/crates/jettypod-core/src/db/startup.rs +101 -0
- package/crates/jettypod-core/src/db/validate.rs +149 -0
- package/crates/jettypod-core/src/error.rs +76 -0
- package/crates/jettypod-core/src/git.rs +458 -0
- package/crates/jettypod-core/src/lib.rs +20 -0
- package/crates/jettypod-core/src/sessions.rs +625 -0
- package/crates/jettypod-core/src/skills.rs +556 -0
- package/crates/jettypod-core/src/work.rs +1086 -0
- package/crates/jettypod-core/src/worktree.rs +628 -0
- package/crates/jettypod-core/src/ws.rs +767 -0
- package/cucumber-test.cjs +6 -0
- package/cucumber.js +9 -3
- package/docs/COMMAND_REFERENCE.md +34 -0
- package/hooks/post-checkout +32 -75
- package/hooks/post-merge +111 -10
- package/jest.setup.js +1 -0
- package/jettypod.js +145 -116
- package/lib/bdd-preflight.js +96 -0
- package/lib/chore-taxonomy.js +33 -10
- package/lib/database.js +36 -16
- package/lib/db-watcher.js +1 -1
- package/lib/git-hooks/pre-commit +1 -1
- package/lib/jettypod-backup.js +27 -4
- package/lib/merge-lock.js +111 -253
- package/lib/migrations/027-plan-at-creation-column.js +3 -1
- package/lib/migrations/029-remove-autoincrement.js +307 -0
- package/lib/migrations/029-rename-corrupted-to-cleaned.js +149 -0
- package/lib/migrations/030-rejection-round-columns.js +54 -0
- package/lib/migrations/031-session-isolation-index.js +17 -0
- package/lib/migrations/index.js +47 -4
- package/lib/schema.js +10 -5
- package/lib/seed-onboarding.js +1 -1
- package/lib/update-command/index.js +9 -175
- package/lib/work-commands/index.js +144 -19
- package/lib/work-tracking/index.js +148 -27
- package/lib/worktree-diagnostics.js +16 -16
- package/lib/worktree-facade.js +1 -1
- package/lib/worktree-manager.js +8 -8
- package/lib/worktree-reconciler.js +5 -5
- package/package.json +9 -2
- package/scripts/ndjson-to-cucumber-json.js +152 -0
- package/scripts/postinstall.js +25 -0
- package/skills-templates/bug-mode/SKILL.md +79 -20
- package/skills-templates/bug-planning/SKILL.md +25 -29
- package/skills-templates/chore-mode/SKILL.md +171 -69
- package/skills-templates/chore-mode/verification.js +51 -10
- package/skills-templates/chore-planning/SKILL.md +47 -18
- package/skills-templates/design-system-selection/SKILL.md +273 -0
- package/skills-templates/epic-planning/SKILL.md +82 -48
- package/skills-templates/external-transition/SKILL.md +47 -47
- package/skills-templates/feature-planning/SKILL.md +173 -74
- package/skills-templates/production-mode/SKILL.md +69 -49
- package/skills-templates/request-routing/SKILL.md +4 -4
- package/skills-templates/simple-improvement/SKILL.md +74 -29
- package/skills-templates/speed-mode/SKILL.md +217 -141
- package/skills-templates/stable-mode/SKILL.md +148 -89
- package/apps/dashboard/README.md +0 -36
- package/apps/dashboard/app/api/claude/[workItemId]/message/route.ts +0 -386
- package/apps/dashboard/app/api/claude/[workItemId]/pin/route.ts +0 -24
- package/apps/dashboard/app/api/claude/[workItemId]/route.ts +0 -167
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/content/route.ts +0 -52
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/message/route.ts +0 -378
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/pin/route.ts +0 -24
- package/apps/dashboard/app/api/claude/sessions/cleanup/route.ts +0 -34
- package/apps/dashboard/app/api/claude/sessions/route.ts +0 -184
- package/apps/dashboard/app/api/decisions/[id]/route.ts +0 -25
- package/apps/dashboard/app/api/internal/set-project/route.ts +0 -17
- package/apps/dashboard/app/api/kanban/route.ts +0 -15
- package/apps/dashboard/app/api/settings/env-vars/route.ts +0 -125
- package/apps/dashboard/app/api/settings/general/route.ts +0 -21
- package/apps/dashboard/app/api/tests/route.ts +0 -9
- package/apps/dashboard/app/api/tests/run/route.ts +0 -82
- package/apps/dashboard/app/api/tests/run/stream/route.ts +0 -71
- package/apps/dashboard/app/api/tests/undefined/route.ts +0 -9
- package/apps/dashboard/app/api/usage/route.ts +0 -17
- package/apps/dashboard/app/api/work/[id]/description/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/epic/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/order/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/status/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/title/route.ts +0 -21
- package/apps/dashboard/app/layout.tsx +0 -43
- package/apps/dashboard/components/UpgradeBanner.tsx +0 -29
- package/apps/dashboard/electron/ipc-handlers.js +0 -1028
- package/apps/dashboard/electron/main.js +0 -2124
- package/apps/dashboard/electron/preload.js +0 -123
- package/apps/dashboard/electron/session-manager.js +0 -141
- package/apps/dashboard/electron-builder.config.js +0 -357
- package/apps/dashboard/hooks/useClaudeSessions.ts +0 -299
- package/apps/dashboard/lib/claude-process-manager.ts +0 -492
- package/apps/dashboard/lib/db-bridge.ts +0 -282
- package/apps/dashboard/lib/prototypes.ts +0 -202
- package/apps/dashboard/lib/test-results-db.ts +0 -307
- package/apps/dashboard/lib/tests.ts +0 -282
- package/apps/dashboard/next.config.js +0 -50
- package/apps/dashboard/postcss.config.mjs +0 -7
- package/apps/dashboard/public/file.svg +0 -1
- package/apps/dashboard/public/globe.svg +0 -1
- package/apps/dashboard/public/next.svg +0 -1
- package/apps/dashboard/public/vercel.svg +0 -1
- package/apps/dashboard/public/window.svg +0 -1
- package/apps/dashboard/scripts/download-node.js +0 -104
- package/apps/dashboard/scripts/upload-to-r2.js +0 -89
- package/docs/bdd-guidance.md +0 -390
|
@@ -1,30 +1,9 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
1
|
import { useState } from 'react';
|
|
4
|
-
import Link from '
|
|
2
|
+
import { Link } from 'react-router-dom';
|
|
5
3
|
import type { WorkItem } from '@/lib/db';
|
|
6
4
|
import { CopyableId } from './CopyableId';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
epic: '🎯',
|
|
10
|
-
feature: '✨',
|
|
11
|
-
chore: '🔧',
|
|
12
|
-
bug: '🐛',
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const statusColors: Record<string, string> = {
|
|
16
|
-
backlog: 'text-zinc-500',
|
|
17
|
-
todo: 'text-zinc-500',
|
|
18
|
-
in_progress: 'text-blue-600 dark:text-blue-400',
|
|
19
|
-
done: 'text-green-600 dark:text-green-400',
|
|
20
|
-
cancelled: 'text-red-500',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const modeLabels: Record<string, { label: string; color: string }> = {
|
|
24
|
-
speed: { label: 'speed', color: 'bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200' },
|
|
25
|
-
stable: { label: 'stable', color: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200' },
|
|
26
|
-
production: { label: 'prod', color: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200' },
|
|
27
|
-
};
|
|
5
|
+
import { STATUS_COLORS, MODE_LABELS } from '@/lib/constants';
|
|
6
|
+
import { TypeIcon } from './TypeIcon';
|
|
28
7
|
|
|
29
8
|
interface WorkItemNodeProps {
|
|
30
9
|
item: WorkItem;
|
|
@@ -38,7 +17,7 @@ function WorkItemNode({ item, depth = 0 }: WorkItemNodeProps) {
|
|
|
38
17
|
return (
|
|
39
18
|
<div className="select-none">
|
|
40
19
|
<div
|
|
41
|
-
className={`flex items-center gap-
|
|
20
|
+
className={`flex items-center gap-3 py-2 px-3 rounded hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors duration-200 ease-out group`}
|
|
42
21
|
style={{ paddingLeft: `${depth * 20 + 8}px` }}
|
|
43
22
|
>
|
|
44
23
|
{/* Expand/collapse toggle */}
|
|
@@ -54,23 +33,23 @@ function WorkItemNode({ item, depth = 0 }: WorkItemNodeProps) {
|
|
|
54
33
|
)}
|
|
55
34
|
|
|
56
35
|
{/* Type icon */}
|
|
57
|
-
<span className="text-
|
|
36
|
+
<span className="text-base"><TypeIcon type={item.type} /></span>
|
|
58
37
|
|
|
59
38
|
{/* ID with click-to-copy */}
|
|
60
39
|
<CopyableId id={item.id} title={item.title} type={item.type} />
|
|
61
40
|
|
|
62
41
|
{/* Title */}
|
|
63
42
|
<Link
|
|
64
|
-
|
|
65
|
-
className={`flex-1 truncate hover:underline ${
|
|
43
|
+
to={`/work/${item.id}`}
|
|
44
|
+
className={`flex-1 truncate hover:underline ${STATUS_COLORS[item.status]}`}
|
|
66
45
|
>
|
|
67
46
|
{item.title}
|
|
68
47
|
</Link>
|
|
69
48
|
|
|
70
49
|
{/* Mode badge */}
|
|
71
|
-
{item.mode &&
|
|
72
|
-
<span className={`text-xs px-
|
|
73
|
-
{
|
|
50
|
+
{item.mode && MODE_LABELS[item.mode] && (
|
|
51
|
+
<span className={`text-xs px-2 py-1 rounded ${MODE_LABELS[item.mode].color}`}>
|
|
52
|
+
{MODE_LABELS[item.mode].label}
|
|
74
53
|
</span>
|
|
75
54
|
)}
|
|
76
55
|
|
|
@@ -108,7 +87,7 @@ export function WorkItemTree({ items }: WorkItemTreeProps) {
|
|
|
108
87
|
}
|
|
109
88
|
|
|
110
89
|
return (
|
|
111
|
-
<div className="font-mono text-
|
|
90
|
+
<div className="font-mono text-base">
|
|
112
91
|
{items.map((item) => (
|
|
113
92
|
<WorkItemNode key={item.id} item={item} />
|
|
114
93
|
))}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
1
|
import { useState, useEffect } from 'react';
|
|
4
|
-
import {
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
5
3
|
import { useUsage } from '@/contexts/UsageContext';
|
|
6
4
|
import { SubscribeContent } from '@/components/SubscribeContent';
|
|
5
|
+
import { Button } from '@/components/ui/Button';
|
|
6
|
+
import { isTauri, auth, shell } from '@/lib/tauri-bridge';
|
|
7
|
+
|
|
8
|
+
const API_BASE = 'https://jettypod-update-server.spangbaryn2.workers.dev';
|
|
7
9
|
|
|
8
10
|
const planColors: Record<string, string> = {
|
|
9
11
|
free: 'bg-zinc-200 dark:bg-zinc-700 text-zinc-700 dark:text-zinc-300',
|
|
10
|
-
monthly: 'bg-
|
|
12
|
+
monthly: 'bg-[#e8f0f0] dark:bg-[#819D9F]/20 text-[#5a7d7f] dark:text-[#a3bfc0]',
|
|
11
13
|
lifetime: 'bg-purple-100 dark:bg-purple-900/40 text-purple-700 dark:text-purple-300',
|
|
12
14
|
};
|
|
13
15
|
|
|
14
16
|
export function AccountSection() {
|
|
15
|
-
const
|
|
17
|
+
const navigate = useNavigate();
|
|
16
18
|
const { plan, used, limit, loading, refresh } = useUsage();
|
|
17
19
|
const [email, setEmail] = useState<string | null>(null);
|
|
18
20
|
const [portalError, setPortalError] = useState<string | null>(null);
|
|
@@ -21,9 +23,9 @@ export function AccountSection() {
|
|
|
21
23
|
|
|
22
24
|
useEffect(() => {
|
|
23
25
|
async function loadAuth() {
|
|
24
|
-
if (!
|
|
26
|
+
if (!isTauri()) return;
|
|
25
27
|
try {
|
|
26
|
-
const status = await
|
|
28
|
+
const status = await auth.getStatus();
|
|
27
29
|
if (status.authenticated && status.user) {
|
|
28
30
|
setEmail(status.user.email);
|
|
29
31
|
}
|
|
@@ -38,13 +40,27 @@ export function AccountSection() {
|
|
|
38
40
|
const isAtCapacity = isFree && limit > 0 && used >= limit;
|
|
39
41
|
|
|
40
42
|
const handleManageSubscription = async () => {
|
|
41
|
-
if (!window.electronAPI?.billing?.openCustomerPortal) return;
|
|
42
43
|
setPortalError(null);
|
|
43
44
|
setPortalLoading(true);
|
|
44
45
|
try {
|
|
45
|
-
const
|
|
46
|
-
if (
|
|
47
|
-
setPortalError(
|
|
46
|
+
const token = await auth.getToken();
|
|
47
|
+
if (!token) {
|
|
48
|
+
setPortalError('Not authenticated');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const res = await fetch(`${API_BASE}/billing/customer-portal`, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
54
|
+
});
|
|
55
|
+
if (res.ok) {
|
|
56
|
+
const data = await res.json() as { url?: string };
|
|
57
|
+
if (data.url) {
|
|
58
|
+
await shell.openUrl(data.url);
|
|
59
|
+
} else {
|
|
60
|
+
setPortalError('Unable to open billing portal');
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
setPortalError('Unable to open billing portal');
|
|
48
64
|
}
|
|
49
65
|
} catch {
|
|
50
66
|
setPortalError('Unable to open billing portal');
|
|
@@ -54,9 +70,8 @@ export function AccountSection() {
|
|
|
54
70
|
};
|
|
55
71
|
|
|
56
72
|
const handleLogout = async () => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
router.push('/login');
|
|
73
|
+
await auth.logout();
|
|
74
|
+
navigate('/login');
|
|
60
75
|
};
|
|
61
76
|
|
|
62
77
|
const handleUpgradeClose = () => {
|
|
@@ -67,15 +82,17 @@ export function AccountSection() {
|
|
|
67
82
|
if (showUpgrade) {
|
|
68
83
|
return (
|
|
69
84
|
<section id="account" className="relative min-h-[500px]">
|
|
70
|
-
<
|
|
85
|
+
<Button
|
|
71
86
|
onClick={handleUpgradeClose}
|
|
72
|
-
|
|
87
|
+
variant="ghost"
|
|
88
|
+
size="icon"
|
|
89
|
+
className="absolute top-0 right-0 z-10"
|
|
73
90
|
aria-label="Close upgrade"
|
|
74
91
|
>
|
|
75
92
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
76
93
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
77
94
|
</svg>
|
|
78
|
-
</
|
|
95
|
+
</Button>
|
|
79
96
|
<div className="flex flex-col items-center justify-center min-h-[500px] py-8">
|
|
80
97
|
<SubscribeContent onClose={handleUpgradeClose} />
|
|
81
98
|
</div>
|
|
@@ -85,25 +102,25 @@ export function AccountSection() {
|
|
|
85
102
|
|
|
86
103
|
return (
|
|
87
104
|
<section id="account">
|
|
88
|
-
<div className="flex items-center justify-between mb-
|
|
105
|
+
<div className="flex items-center justify-between mb-6">
|
|
89
106
|
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
|
|
90
107
|
Account
|
|
91
108
|
</h2>
|
|
92
109
|
</div>
|
|
93
110
|
|
|
94
111
|
{/* Email & Plan */}
|
|
95
|
-
<div className="p-
|
|
112
|
+
<div className="p-6 bg-zinc-50 dark:bg-zinc-800/50 rounded-xl space-y-4">
|
|
96
113
|
<div className="flex items-center justify-between">
|
|
97
114
|
<div>
|
|
98
|
-
<label className="block text-
|
|
115
|
+
<label className="block text-base font-medium text-zinc-900 dark:text-zinc-100">
|
|
99
116
|
Email
|
|
100
117
|
</label>
|
|
101
|
-
<p className="text-
|
|
118
|
+
<p className="text-base text-zinc-600 dark:text-zinc-400 mt-1">
|
|
102
119
|
{loading ? '...' : email || 'Not signed in'}
|
|
103
120
|
</p>
|
|
104
121
|
</div>
|
|
105
|
-
<div className="flex items-center gap-
|
|
106
|
-
<span className={`px-2 py-
|
|
122
|
+
<div className="flex items-center gap-3">
|
|
123
|
+
<span className={`px-2 py-1 text-xs font-medium rounded-full ${planColors[plan] || planColors.free}`}>
|
|
107
124
|
{plan}
|
|
108
125
|
</span>
|
|
109
126
|
</div>
|
|
@@ -112,13 +129,13 @@ export function AccountSection() {
|
|
|
112
129
|
{/* Usage Bar (free users only) */}
|
|
113
130
|
{isFree && (
|
|
114
131
|
<div>
|
|
115
|
-
<div className="flex items-center justify-between text-
|
|
132
|
+
<div className="flex items-center justify-between text-base text-zinc-500 dark:text-zinc-400 mb-1.5">
|
|
116
133
|
<span>Weekly usage</span>
|
|
117
134
|
<span>{used} / {limit} work items</span>
|
|
118
135
|
</div>
|
|
119
136
|
<div className="w-full h-2 bg-zinc-200 dark:bg-zinc-700 rounded-full overflow-hidden">
|
|
120
137
|
<div
|
|
121
|
-
className={`h-full rounded-full transition-
|
|
138
|
+
className={`h-full rounded-full transition-[width,background-color] duration-200 ease-out ${isAtCapacity ? 'bg-red-500' : 'bg-[#819D9F]'}`}
|
|
122
139
|
style={{ width: `${limit > 0 ? Math.min((used / limit) * 100, 100) : 0}%` }}
|
|
123
140
|
/>
|
|
124
141
|
</div>
|
|
@@ -129,33 +146,36 @@ export function AccountSection() {
|
|
|
129
146
|
<div className="pt-2 border-t border-zinc-200 dark:border-zinc-700 flex items-center justify-between">
|
|
130
147
|
<div>
|
|
131
148
|
{isFree ? (
|
|
132
|
-
<
|
|
149
|
+
<Button
|
|
133
150
|
onClick={() => setShowUpgrade(true)}
|
|
134
|
-
|
|
151
|
+
variant="accent"
|
|
152
|
+
size="sm"
|
|
135
153
|
>
|
|
136
154
|
Upgrade
|
|
137
|
-
</
|
|
155
|
+
</Button>
|
|
138
156
|
) : (
|
|
139
157
|
<>
|
|
140
|
-
<
|
|
158
|
+
<Button
|
|
141
159
|
onClick={handleManageSubscription}
|
|
142
160
|
disabled={portalLoading}
|
|
143
|
-
|
|
161
|
+
variant="secondary"
|
|
162
|
+
size="sm"
|
|
144
163
|
>
|
|
145
164
|
{portalLoading ? 'Opening...' : 'Manage Subscription'}
|
|
146
|
-
</
|
|
165
|
+
</Button>
|
|
147
166
|
{portalError && (
|
|
148
|
-
<p className="text-
|
|
167
|
+
<p className="text-base text-red-500 mt-1">{portalError}</p>
|
|
149
168
|
)}
|
|
150
169
|
</>
|
|
151
170
|
)}
|
|
152
171
|
</div>
|
|
153
|
-
<
|
|
172
|
+
<Button
|
|
154
173
|
onClick={handleLogout}
|
|
155
|
-
|
|
174
|
+
variant="destructive"
|
|
175
|
+
size="sm"
|
|
156
176
|
>
|
|
157
177
|
Log Out
|
|
158
|
-
</
|
|
178
|
+
</Button>
|
|
159
179
|
</div>
|
|
160
180
|
</div>
|
|
161
181
|
</section>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { invoke } from '@/lib/tauri';
|
|
3
|
+
import { openDialog } from '@/lib/tauri';
|
|
4
|
+
import { Button } from '@/components/ui/Button';
|
|
5
|
+
import { ContextDocumentsSection } from './ContextDocumentsSection';
|
|
6
|
+
import type { ContextDocument } from '@/lib/data-bridge';
|
|
7
|
+
|
|
8
|
+
interface AiContextSectionProps {
|
|
9
|
+
initialDesignSystemDir: string | null;
|
|
10
|
+
initialContextDocuments: ContextDocument[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function AiContextSection({ initialDesignSystemDir, initialContextDocuments }: AiContextSectionProps) {
|
|
14
|
+
const [designSystemDir, setDesignSystemDir] = useState<string | null>(initialDesignSystemDir);
|
|
15
|
+
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
|
16
|
+
|
|
17
|
+
const showSuccess = (message: string) => {
|
|
18
|
+
setSuccessMessage(message);
|
|
19
|
+
setTimeout(() => setSuccessMessage(null), 3000);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const handleBrowse = async () => {
|
|
23
|
+
const selected = await openDialog({ directory: true, title: 'Select Design System Directory' });
|
|
24
|
+
if (selected && typeof selected === 'string') {
|
|
25
|
+
await invoke('db_set_design_system_dir', { dir: selected });
|
|
26
|
+
setDesignSystemDir(selected);
|
|
27
|
+
showSuccess('Design system directory set');
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const handleClear = async () => {
|
|
32
|
+
await invoke('db_reset_design_system_dir');
|
|
33
|
+
setDesignSystemDir(null);
|
|
34
|
+
showSuccess('Design system directory cleared');
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<section id="ai-context">
|
|
39
|
+
<div className="flex items-center justify-between mb-6">
|
|
40
|
+
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
|
|
41
|
+
AI Context
|
|
42
|
+
</h2>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
{successMessage && (
|
|
46
|
+
<div className="mb-4 px-6 py-3 bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-300 rounded-lg text-base">
|
|
47
|
+
{successMessage}
|
|
48
|
+
</div>
|
|
49
|
+
)}
|
|
50
|
+
|
|
51
|
+
{/* Design System Directory Setting */}
|
|
52
|
+
<div className="p-6 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg">
|
|
53
|
+
<div>
|
|
54
|
+
<label className="block text-base font-medium text-zinc-900 dark:text-zinc-100">
|
|
55
|
+
Design System Directory
|
|
56
|
+
</label>
|
|
57
|
+
<p className="text-base text-zinc-500 dark:text-zinc-400 mt-1">
|
|
58
|
+
Select a folder that includes your design system. Claude will use this when prototyping and building parts of your project.
|
|
59
|
+
</p>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div className="mt-4">
|
|
63
|
+
{designSystemDir ? (
|
|
64
|
+
<div className="flex items-center gap-3">
|
|
65
|
+
<span className="font-mono text-sm text-zinc-900 dark:text-zinc-100 bg-zinc-200 dark:bg-zinc-700 px-3 py-2 rounded flex-1 truncate">
|
|
66
|
+
{designSystemDir}
|
|
67
|
+
</span>
|
|
68
|
+
<Button onClick={handleBrowse} variant="ghost" size="sm">
|
|
69
|
+
Change
|
|
70
|
+
</Button>
|
|
71
|
+
<Button onClick={handleClear} variant="ghost" size="sm">
|
|
72
|
+
Clear
|
|
73
|
+
</Button>
|
|
74
|
+
</div>
|
|
75
|
+
) : (
|
|
76
|
+
<div className="flex items-center gap-3">
|
|
77
|
+
<Button onClick={handleBrowse} size="sm">
|
|
78
|
+
Browse...
|
|
79
|
+
</Button>
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
{/* Context Documents */}
|
|
86
|
+
<ContextDocumentsSection initialDocuments={initialContextDocuments} />
|
|
87
|
+
</section>
|
|
88
|
+
);
|
|
89
|
+
}
|