@nexttylabs/echo 0.4.0 → 0.6.0
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/CHANGELOG.md +27 -0
- package/app/(dashboard)/admin/feedback/[id]/edit/page.tsx +12 -6
- package/app/(dashboard)/admin/feedback/new/page.tsx +19 -17
- package/app/(dashboard)/admin/layout.tsx +16 -6
- package/app/(dashboard)/layout.tsx +4 -2
- package/app/(dashboard)/settings/api-keys/page.tsx +13 -3
- package/app/(dashboard)/settings/layout.tsx +25 -2
- package/app/(dashboard)/settings/organization/page.tsx +8 -9
- package/app/(public)/[organizationSlug]/roadmap/page.tsx +19 -1
- package/app/api/admin/backup/route.ts +22 -4
- package/app/api/auth/register/handler.ts +1 -2
- package/app/api/feedback/[id]/comments/[commentId]/route.ts +13 -4
- package/app/api/feedback/[id]/reclassify/route.ts +4 -4
- package/app/api/organizations/handler.ts +2 -4
- package/components/settings/settings-sidebar.tsx +4 -4
- package/hooks/use-organization.tsx +116 -0
- package/hooks/use-permissions.ts +24 -11
- package/lib/auth/config.ts +0 -7
- package/lib/auth/organization.ts +20 -0
- package/lib/auth/permissions.ts +10 -0
- package/lib/db/migrations/0000_needy_leech.sql +335 -0
- package/lib/db/migrations/meta/0000_snapshot.json +2186 -1
- package/lib/db/migrations/meta/_journal.json +2 -135
- package/lib/db/schema/auth.ts +0 -1
- package/lib/db/schema/index.ts +0 -1
- package/lib/portal/public-context.tsx +5 -0
- package/package.json +20 -1
- package/.changeset/README.md +0 -21
- package/.changeset/config.json +0 -11
- package/.changeset/cozy-ghosts-care.md +0 -5
- package/.changeset/sharp-lines-stand.md +0 -5
- package/.changeset/sour-doodles-eat.md +0 -5
- package/.changeset/tender-moose-shop.md +0 -5
- package/.github/pull_request_template.md +0 -13
- package/.github/workflows/ci.yml +0 -41
- package/.github/workflows/publish.yml +0 -44
- package/.github/workflows/release.yml +0 -73
- package/AGENTS.md +0 -92
- package/Dockerfile +0 -57
- package/Makefile +0 -77
- package/bun.lock +0 -2503
- package/components/portal/project-switcher.tsx +0 -20
- package/docker-compose.dev.yml +0 -26
- package/docker-compose.yml +0 -98
- package/docs/architecture.md +0 -259
- package/docs/component-inventory.md +0 -261
- package/docs/database-migrations.md +0 -76
- package/docs/development-guide.md +0 -209
- package/docs/e2e-user-flows.csv +0 -31
- package/docs/er-diagram-feedback.mmd +0 -138
- package/docs/er-diagram.mmd +0 -281
- package/docs/i18n-check-report.md +0 -296
- package/docs/index.md +0 -214
- package/docs/logic-chain.md +0 -94
- package/docs/plans/2026-01-02-database-migration-scripts.md +0 -496
- package/docs/plans/2026-01-02-user-login-design.md +0 -37
- package/docs/plans/2026-01-02-user-login.md +0 -437
- package/docs/plans/2026-01-02-user-registration-design.md +0 -47
- package/docs/plans/2026-01-02-user-registration.md +0 -628
- package/docs/plans/2026-01-03-roles-permissions-design.md +0 -20
- package/docs/plans/2026-01-03-roles-permissions.md +0 -266
- package/docs/plans/2026-01-05-authentication-middleware.md +0 -207
- package/docs/plans/2026-01-05-member-removal.md +0 -186
- package/docs/plans/2026-01-05-organization-creation.md +0 -374
- package/docs/plans/2026-01-05-rbac-middleware.md +0 -112
- package/docs/plans/2026-01-05-role-configuration.md +0 -441
- package/docs/plans/2026-01-06-file-upload-support.md +0 -804
- package/docs/plans/2026-01-06-permission-check-hook.md +0 -155
- package/docs/plans/2026-01-06-resource-ownership-check.md +0 -231
- package/docs/plans/2026-01-07-feedback-tracking-link.md +0 -459
- package/docs/plans/2026-01-09-logout-redirect-design.md +0 -52
- package/docs/plans/2026-01-09-phase2-3-plan.md +0 -654
- package/docs/plans/2026-01-09-portal-execution-plan.md +0 -408
- package/docs/plans/2026-01-09-project-delete-feature-design.md +0 -163
- package/docs/plans/2026-01-09-project-delete-implementation.md +0 -451
- package/docs/plans/2026-01-09-project-edit-delete-design.md +0 -52
- package/docs/plans/2026-01-09-settings-center-design.md +0 -114
- package/docs/plans/2026-01-09-settings-center.md +0 -948
- package/docs/plans/2026-01-10-organization-only-design.md +0 -66
- package/docs/plans/2026-01-10-organization-only-implementation.md +0 -433
- package/docs/plans/2026-01-10-portal-settings-restructure-plan.md +0 -18
- package/docs/plans/2026-01-10-project-settings-tabs-design-implementation.md +0 -296
- package/docs/plans/2026-01-14-e2e-playwright-feedback.md +0 -173
- package/docs/plans/2026-01-15-feedback-management-org-context-design.md +0 -82
- package/docs/plans/2026-01-15-feedback-management-org-context-implementation-plan.md +0 -521
- package/docs/plans/2026-01-16-admin-feedback-filters-design.md +0 -75
- package/docs/plans/2026-01-16-admin-feedback-filters-implementation.md +0 -293
- package/docs/plans/2026-01-16-admin-feedback-route-consolidation.md +0 -180
- package/docs/plans/2026-01-16-e2e-test-fixes.md +0 -158
- package/docs/plans/2026-01-17-admin-feedback-filters.md +0 -214
- package/docs/plans/2026-01-17-admin-feedback-improvements.md +0 -453
- package/docs/plans/2026-01-18-changesets-design.md +0 -40
- package/docs/product_changes.md +0 -37
- package/docs/project-overview.md +0 -159
- package/docs/project-scan-report.json +0 -104
- package/docs/route-role-visibility.md +0 -51
- package/docs/source-tree-analysis.md +0 -150
- package/docs/testing/delete-project-manual-tests.md +0 -18
- package/docs/user-story-tracking.md +0 -191
- package/eslint.config.mjs +0 -19
- package/lib/db/migrations/.gitkeep +0 -0
- package/lib/db/migrations/0000_cynical_gladiator.sql +0 -53
- package/lib/db/migrations/0001_wandering_sunfire.sql +0 -27
- package/lib/db/migrations/0002_shallow_speedball.sql +0 -1
- package/lib/db/migrations/0003_add_org_description.sql +0 -1
- package/lib/db/migrations/0003_boring_wild_pack.sql +0 -13
- package/lib/db/migrations/0004_windy_tyrannus.sql +0 -27
- package/lib/db/migrations/0005_perpetual_doorman.sql +0 -5
- package/lib/db/migrations/0006_aberrant_captain_midlands.sql +0 -13
- package/lib/db/migrations/0007_clever_captain_cross.sql +0 -14
- package/lib/db/migrations/0008_sparkling_pandemic.sql +0 -2
- package/lib/db/migrations/0009_happy_black_tom.sql +0 -29
- package/lib/db/migrations/0010_kind_junta.sql +0 -8
- package/lib/db/migrations/0011_mute_squadron_supreme.sql +0 -25
- package/lib/db/migrations/0012_giant_power_man.sql +0 -24
- package/lib/db/migrations/0013_damp_titanium_man.sql +0 -17
- package/lib/db/migrations/0014_blue_alice.sql +0 -18
- package/lib/db/migrations/0015_webhook_tables.sql +0 -41
- package/lib/db/migrations/0016_github_integration.sql +0 -30
- package/lib/db/migrations/0016_overjoyed_ghost_rider.sql +0 -22
- package/lib/db/migrations/0017_slimy_inhumans.sql +0 -6
- package/lib/db/migrations/0018_same_spitfire.sql +0 -1
- package/lib/db/migrations/0019_jittery_loners.sql +0 -16
- package/lib/db/migrations/0019_remove_projects_add_org_settings.sql +0 -14
- package/lib/db/migrations/meta/0001_snapshot.json +0 -553
- package/lib/db/migrations/meta/0002_snapshot.json +0 -560
- package/lib/db/migrations/meta/0003_snapshot.json +0 -650
- package/lib/db/migrations/meta/0004_snapshot.json +0 -852
- package/lib/db/migrations/meta/0005_snapshot.json +0 -900
- package/lib/db/migrations/meta/0006_snapshot.json +0 -1011
- package/lib/db/migrations/meta/0007_snapshot.json +0 -1125
- package/lib/db/migrations/meta/0008_snapshot.json +0 -1146
- package/lib/db/migrations/meta/0009_snapshot.json +0 -1386
- package/lib/db/migrations/meta/0010_snapshot.json +0 -1419
- package/lib/db/migrations/meta/0011_snapshot.json +0 -1615
- package/lib/db/migrations/meta/0012_snapshot.json +0 -1805
- package/lib/db/migrations/meta/0013_snapshot.json +0 -1948
- package/lib/db/migrations/meta/0014_snapshot.json +0 -2082
- package/lib/db/migrations/meta/0015_snapshot.json +0 -2476
- package/lib/db/migrations/meta/0016_snapshot.json +0 -2633
- package/lib/db/migrations/meta/0017_snapshot.json +0 -2680
- package/lib/db/migrations/meta/0018_snapshot.json +0 -2686
- package/lib/db/migrations/meta/0019_snapshot.json +0 -2741
- package/lib/db/schema/projects.ts +0 -145
- package/lib/db/schema/user-profiles.ts +0 -31
- package/lib/validations/projects.ts +0 -49
- package/next-env.d.ts +0 -6
- package/playwright.config.ts +0 -44
- package/proxy.test.ts +0 -131
- package/proxy.ts +0 -116
- package/scripts/backup-db.sh +0 -57
- package/scripts/backup-db.ts +0 -24
- package/scripts/generate-openapi.ts +0 -22
- package/scripts/migration-helper.ts +0 -39
- package/scripts/pre-deploy.ts +0 -75
- package/scripts/restore-db.sh +0 -60
- package/scripts/rollback.ts +0 -72
- package/scripts/seed-tags.ts +0 -48
- package/tests/api/feedback-bulk.test.ts +0 -47
- package/tests/api/feedback-by-id.test.ts +0 -67
- package/tests/api/feedback-comments-route-import.test.ts +0 -26
- package/tests/api/feedback-create.test.ts +0 -71
- package/tests/api/feedback-delete.test.ts +0 -160
- package/tests/api/feedback-filter.test.ts +0 -250
- package/tests/api/feedback-list.test.ts +0 -234
- package/tests/api/feedback-route-assignee-condition.test.ts +0 -32
- package/tests/api/feedback-similar.test.ts +0 -46
- package/tests/api/feedback-sort.test.ts +0 -261
- package/tests/api/feedback-status-enum.test.ts +0 -49
- package/tests/api/feedback-status-filter.test.ts +0 -117
- package/tests/api/feedback-submit-on-behalf.test.ts +0 -269
- package/tests/api/feedback.test.ts +0 -175
- package/tests/api/identify-jwt.test.ts +0 -25
- package/tests/api/invitation-accept.test.ts +0 -213
- package/tests/api/organization-invitations.test.ts +0 -186
- package/tests/api/organization-members-list.test.ts +0 -79
- package/tests/api/organization-members.test.ts +0 -340
- package/tests/api/organizations.test.ts +0 -149
- package/tests/api/register.test.ts +0 -112
- package/tests/api/upload.test.ts +0 -103
- package/tests/api/vote.test.ts +0 -82
- package/tests/app/admin-feedback-detail-page.test.tsx +0 -25
- package/tests/app/admin-feedback-list-page.test.tsx +0 -25
- package/tests/app/admin-feedback-new-page.test.tsx +0 -25
- package/tests/app/health-route-helpers.test.ts +0 -27
- package/tests/app/login-page.test.ts +0 -26
- package/tests/app/portal-page.test.ts +0 -29
- package/tests/app/project-portal-overview.test.tsx +0 -25
- package/tests/app/widget-page-import.test.ts +0 -25
- package/tests/components/create-post-dialog-defaults.test.ts +0 -43
- package/tests/components/feedback/duplicate-suggestions-inline.test.tsx +0 -27
- package/tests/components/feedback/embedded-feedback-form.test.tsx +0 -96
- package/tests/components/feedback/feedback-detail.test.tsx +0 -25
- package/tests/components/feedback/feedback-stats.test.tsx +0 -49
- package/tests/components/feedback-bulk-actions.test.tsx +0 -39
- package/tests/components/feedback-i18n-keys.test.ts +0 -70
- package/tests/components/feedback-list-controls-compile.test.ts +0 -25
- package/tests/components/feedback-list-controls.test.tsx +0 -204
- package/tests/components/feedback-list-item.test.tsx +0 -67
- package/tests/components/landing/hero.test.tsx +0 -46
- package/tests/components/layout/language-switcher.test.tsx +0 -25
- package/tests/components/layout/sidebar.test.tsx +0 -157
- package/tests/components/login-form.test.ts +0 -25
- package/tests/components/organization-form.test.ts +0 -32
- package/tests/components/organization-switcher.test.ts +0 -25
- package/tests/components/pagination.test.tsx +0 -43
- package/tests/components/portal-overview.test.tsx +0 -25
- package/tests/components/profile-form.test.tsx +0 -139
- package/tests/components/role-selector.test.ts +0 -31
- package/tests/components/status-chart.test.tsx +0 -90
- package/tests/e2e/auth.e2e.ts +0 -323
- package/tests/e2e/feedback-actions.e2e.ts +0 -471
- package/tests/e2e/feedback-attachment.e2e.ts +0 -168
- package/tests/e2e/feedback-customer.e2e.ts +0 -226
- package/tests/e2e/feedback-management.e2e.ts +0 -565
- package/tests/e2e/feedback-submit.e2e.ts +0 -133
- package/tests/e2e/feedback-view.e2e.ts +0 -297
- package/tests/e2e/fixtures/test-data.ts +0 -235
- package/tests/e2e/health-check.e2e.ts +0 -230
- package/tests/e2e/helpers/test-utils-helpers.test.ts +0 -43
- package/tests/e2e/helpers/test-utils.ts +0 -298
- package/tests/e2e/integration-placeholders.e2e.ts +0 -199
- package/tests/e2e/organization.e2e.ts +0 -292
- package/tests/e2e/permissions.e2e.ts +0 -424
- package/tests/e2e/project-widget.e2e.ts +0 -63
- package/tests/feedback/filters.test.ts +0 -29
- package/tests/hooks/use-permissions.test.ts +0 -52
- package/tests/lib/ai/classifier.test.ts +0 -104
- package/tests/lib/ai/duplicate-detector.test.ts +0 -234
- package/tests/lib/attachments-schema.test.ts +0 -30
- package/tests/lib/auth/session.test.ts +0 -49
- package/tests/lib/auth-client.test.ts +0 -37
- package/tests/lib/auth-config.test.ts +0 -26
- package/tests/lib/feedback-prefill.test.ts +0 -52
- package/tests/lib/feedback-processor.test.ts +0 -41
- package/tests/lib/feedback-schema.test.ts +0 -33
- package/tests/lib/file-validator.test.ts +0 -48
- package/tests/lib/get-feedback-by-id.test.ts +0 -37
- package/tests/lib/invitations.test.ts +0 -35
- package/tests/lib/login-schema.test.ts +0 -36
- package/tests/lib/org-context.test.ts +0 -95
- package/tests/lib/organization-access.test.ts +0 -44
- package/tests/lib/organization-member-role-schema.test.ts +0 -41
- package/tests/lib/permissions.test.ts +0 -88
- package/tests/lib/portal-analytics.test.ts +0 -25
- package/tests/lib/portal-contributors.test.ts +0 -25
- package/tests/lib/portal-copy.test.ts +0 -27
- package/tests/lib/portal-i18n.test.ts +0 -30
- package/tests/lib/portal-leaderboard-settings.test.ts +0 -25
- package/tests/lib/portal-modules.test.ts +0 -25
- package/tests/lib/portal-seo.test.ts +0 -25
- package/tests/lib/portal-sharing.test.ts +0 -25
- package/tests/lib/portal-sorting.test.ts +0 -25
- package/tests/lib/portal-theme.test.ts +0 -25
- package/tests/lib/rate-limit.test.ts +0 -142
- package/tests/lib/resolve-locale.test.ts +0 -34
- package/tests/lib/services/backup.test.ts +0 -145
- package/tests/lib/user-organizations.test.ts +0 -42
- package/tests/lib/user-role-schema.test.ts +0 -33
- package/tests/lib/user-schema.test.ts +0 -25
- package/tests/setup.ts +0 -74
- package/vercel.json +0 -4
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
# Project Delete Feature Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
-
|
|
5
|
-
**Goal:** Add ability for admin users to delete projects with a safe confirmation mechanism (typing project name to confirm).
|
|
6
|
-
|
|
7
|
-
**Architecture:** Create a delete confirmation dialog component using shadcn AlertDialog. Add a "danger zone" section to the project settings page with a delete button. Call the existing DELETE API endpoint at `/api/projects/[projectId]`.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:**
|
|
10
|
-
- React 19 (client components)
|
|
11
|
-
- Next.js 16 App Router
|
|
12
|
-
- Shadcn/ui (AlertDialog, Button, Card, Input)
|
|
13
|
-
- Lucide React (icons)
|
|
14
|
-
- TypeScript
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## Task 1: Create Delete Project Dialog Component
|
|
19
|
-
|
|
20
|
-
**Files:**
|
|
21
|
-
- Create: `components/project/delete-project-dialog.tsx`
|
|
22
|
-
|
|
23
|
-
**Step 1: Create the delete dialog component file**
|
|
24
|
-
|
|
25
|
-
Create file `components/project/delete-project-dialog.tsx` with the following content:
|
|
26
|
-
|
|
27
|
-
```tsx
|
|
28
|
-
"use client";
|
|
29
|
-
|
|
30
|
-
import { useState } from "react";
|
|
31
|
-
import { useRouter } from "next/navigation";
|
|
32
|
-
import { AlertTriangle } from "lucide-react";
|
|
33
|
-
import {
|
|
34
|
-
AlertDialog,
|
|
35
|
-
AlertDialogAction,
|
|
36
|
-
AlertDialogCancel,
|
|
37
|
-
AlertDialogContent,
|
|
38
|
-
AlertDialogDescription,
|
|
39
|
-
AlertDialogFooter,
|
|
40
|
-
AlertDialogHeader,
|
|
41
|
-
AlertDialogMedia,
|
|
42
|
-
AlertDialogTitle,
|
|
43
|
-
} from "@/components/ui/alert-dialog";
|
|
44
|
-
import { Input } from "@/components/ui/input";
|
|
45
|
-
import { Label } from "@/components/ui/label";
|
|
46
|
-
|
|
47
|
-
interface DeleteProjectDialogProps {
|
|
48
|
-
projectId: string;
|
|
49
|
-
projectName: string;
|
|
50
|
-
open: boolean;
|
|
51
|
-
onOpenChange: (open: boolean) => void;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function DeleteProjectDialog({
|
|
55
|
-
projectId,
|
|
56
|
-
projectName,
|
|
57
|
-
open,
|
|
58
|
-
onOpenChange,
|
|
59
|
-
}: DeleteProjectDialogProps) {
|
|
60
|
-
const router = useRouter();
|
|
61
|
-
const [confirmText, setConfirmText] = useState("");
|
|
62
|
-
const [isDeleting, setIsDeleting] = useState(false);
|
|
63
|
-
const [error, setError] = useState<string | null>(null);
|
|
64
|
-
|
|
65
|
-
const isConfirmMatch = confirmText === projectName;
|
|
66
|
-
|
|
67
|
-
async function handleDelete() {
|
|
68
|
-
if (!isConfirmMatch) return;
|
|
69
|
-
|
|
70
|
-
setIsDeleting(true);
|
|
71
|
-
setError(null);
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
const response = await fetch(`/api/projects/${projectId}`, {
|
|
75
|
-
method: "DELETE",
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
if (!response.ok) {
|
|
79
|
-
const result = await response.json();
|
|
80
|
-
throw new Error(result.error || "删除失败");
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Success - close dialog and redirect
|
|
84
|
-
onOpenChange(false);
|
|
85
|
-
router.push("/settings/projects");
|
|
86
|
-
router.refresh();
|
|
87
|
-
} catch (err) {
|
|
88
|
-
setError(err instanceof Error ? err.message : "删除失败");
|
|
89
|
-
setIsDeleting(false);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function handleOpenChange(newOpen: boolean) {
|
|
94
|
-
if (!isDeleting) {
|
|
95
|
-
onOpenChange(newOpen);
|
|
96
|
-
// Reset state when closing
|
|
97
|
-
if (!newOpen) {
|
|
98
|
-
setConfirmText("");
|
|
99
|
-
setError(null);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return (
|
|
105
|
-
<AlertDialog open={open} onOpenChange={handleOpenChange}>
|
|
106
|
-
<AlertDialogContent>
|
|
107
|
-
<AlertDialogHeader>
|
|
108
|
-
<AlertDialogMedia>
|
|
109
|
-
<AlertTriangle className="text-destructive" />
|
|
110
|
-
</AlertDialogMedia>
|
|
111
|
-
<AlertDialogTitle>删除项目</AlertDialogTitle>
|
|
112
|
-
<AlertDialogDescription>
|
|
113
|
-
<div className="space-y-3">
|
|
114
|
-
<p>此操作不可撤销。删除项目将会:</p>
|
|
115
|
-
<ul className="list-disc space-y-1 pl-5 text-left">
|
|
116
|
-
<li>永久删除项目的所有配置</li>
|
|
117
|
-
<li>删除所有相关的反馈数据</li>
|
|
118
|
-
<li>删除所有相关的评论和附件</li>
|
|
119
|
-
</ul>
|
|
120
|
-
</div>
|
|
121
|
-
</AlertDialogDescription>
|
|
122
|
-
</AlertDialogHeader>
|
|
123
|
-
|
|
124
|
-
<div className="space-y-2">
|
|
125
|
-
<Label htmlFor="confirm-text">
|
|
126
|
-
请输入项目名称 <span className="font-semibold">{projectName}</span> 以确认删除
|
|
127
|
-
</Label>
|
|
128
|
-
<Input
|
|
129
|
-
id="confirm-text"
|
|
130
|
-
value={confirmText}
|
|
131
|
-
onChange={(e) => setConfirmText(e.target.value)}
|
|
132
|
-
placeholder={projectName}
|
|
133
|
-
disabled={isDeleting}
|
|
134
|
-
autoComplete="off"
|
|
135
|
-
/>
|
|
136
|
-
{error && (
|
|
137
|
-
<p className="text-sm text-destructive">{error}</p>
|
|
138
|
-
)}
|
|
139
|
-
</div>
|
|
140
|
-
|
|
141
|
-
<AlertDialogFooter>
|
|
142
|
-
<AlertDialogCancel disabled={isDeleting}>取消</AlertDialogCancel>
|
|
143
|
-
<AlertDialogAction
|
|
144
|
-
variant="destructive"
|
|
145
|
-
disabled={!isConfirmMatch || isDeleting}
|
|
146
|
-
onClick={(e) => {
|
|
147
|
-
e.preventDefault();
|
|
148
|
-
handleDelete();
|
|
149
|
-
}}
|
|
150
|
-
>
|
|
151
|
-
{isDeleting ? "删除中..." : "删除项目"}
|
|
152
|
-
</AlertDialogAction>
|
|
153
|
-
</AlertDialogFooter>
|
|
154
|
-
</AlertDialogContent>
|
|
155
|
-
</AlertDialog>
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**Step 2: Verify the component compiles**
|
|
161
|
-
|
|
162
|
-
Run TypeScript check:
|
|
163
|
-
```bash
|
|
164
|
-
bun run build --dry-run
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Expected: No TypeScript errors in the new file.
|
|
168
|
-
|
|
169
|
-
**Step 3: Commit the dialog component**
|
|
170
|
-
|
|
171
|
-
```bash
|
|
172
|
-
git add components/project/delete-project-dialog.tsx
|
|
173
|
-
git commit -m "feat: add delete project confirmation dialog component"
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## Task 2: Add Danger Zone to Project Settings
|
|
179
|
-
|
|
180
|
-
**Files:**
|
|
181
|
-
- Modify: `components/project/project-settings.tsx`
|
|
182
|
-
|
|
183
|
-
**Step 1: Import the delete dialog and required icons**
|
|
184
|
-
|
|
185
|
-
At the top of `components/project/project-settings.tsx`, add these imports after the existing imports:
|
|
186
|
-
|
|
187
|
-
```tsx
|
|
188
|
-
import { AlertTriangle } from "lucide-react";
|
|
189
|
-
import { DeleteProjectDialog } from "./delete-project-dialog";
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
**Step 2: Add state for delete dialog**
|
|
193
|
-
|
|
194
|
-
Inside the `ProjectSettings` component, after the existing state declarations (around line 54), add:
|
|
195
|
-
|
|
196
|
-
```tsx
|
|
197
|
-
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
Also add the useState import if not already present:
|
|
201
|
-
|
|
202
|
-
```tsx
|
|
203
|
-
import { useState } from "react";
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
**Step 3: Add danger zone card below the preview card**
|
|
207
|
-
|
|
208
|
-
At the end of the return statement, after the closing `</Card>` for the preview (around line 321), add:
|
|
209
|
-
|
|
210
|
-
```tsx
|
|
211
|
-
<Card className="border-destructive/50 lg:col-span-2">
|
|
212
|
-
<CardHeader>
|
|
213
|
-
<CardTitle className="text-destructive flex items-center gap-2">
|
|
214
|
-
<AlertTriangle className="h-5 w-5" />
|
|
215
|
-
危险区域
|
|
216
|
-
</CardTitle>
|
|
217
|
-
<CardDescription>
|
|
218
|
-
这些操作不可逆,请谨慎操作
|
|
219
|
-
</CardDescription>
|
|
220
|
-
</CardHeader>
|
|
221
|
-
<CardContent>
|
|
222
|
-
<div className="flex items-start justify-between gap-4">
|
|
223
|
-
<div className="flex-1">
|
|
224
|
-
<h4 className="font-medium text-sm">删除项目</h4>
|
|
225
|
-
<p className="text-sm text-muted-foreground mt-1">
|
|
226
|
-
永久删除此项目及其所有相关数据
|
|
227
|
-
</p>
|
|
228
|
-
</div>
|
|
229
|
-
<Button
|
|
230
|
-
variant="destructive"
|
|
231
|
-
onClick={() => setShowDeleteDialog(true)}
|
|
232
|
-
>
|
|
233
|
-
删除项目
|
|
234
|
-
</Button>
|
|
235
|
-
</div>
|
|
236
|
-
</CardContent>
|
|
237
|
-
</Card>
|
|
238
|
-
|
|
239
|
-
<DeleteProjectDialog
|
|
240
|
-
projectId={project.projectId}
|
|
241
|
-
projectName={project.name}
|
|
242
|
-
open={showDeleteDialog}
|
|
243
|
-
onOpenChange={setShowDeleteDialog}
|
|
244
|
-
/>
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
**Step 4: Verify the updated component compiles**
|
|
248
|
-
|
|
249
|
-
Run TypeScript check:
|
|
250
|
-
```bash
|
|
251
|
-
bun run build --dry-run
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Expected: No TypeScript errors.
|
|
255
|
-
|
|
256
|
-
**Step 5: Test in development mode**
|
|
257
|
-
|
|
258
|
-
Start the development server:
|
|
259
|
-
```bash
|
|
260
|
-
bun dev
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
Navigate to: `http://localhost:3000/settings/projects/[any-project-slug]`
|
|
264
|
-
|
|
265
|
-
Expected behavior:
|
|
266
|
-
- See "危险区域" card at the bottom with red border
|
|
267
|
-
- See "删除项目" button in red
|
|
268
|
-
- Clicking the button opens the confirmation dialog
|
|
269
|
-
- Dialog shows warning icon and message
|
|
270
|
-
- Input field requires exact project name
|
|
271
|
-
- Delete button is disabled until text matches
|
|
272
|
-
- Cancel button closes dialog
|
|
273
|
-
|
|
274
|
-
**Step 6: Commit the changes**
|
|
275
|
-
|
|
276
|
-
```bash
|
|
277
|
-
git add components/project/project-settings.tsx
|
|
278
|
-
git commit -m "feat: add danger zone with delete button to project settings"
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
## Task 3: Test Delete Functionality
|
|
284
|
-
|
|
285
|
-
**Step 1: Manual testing checklist**
|
|
286
|
-
|
|
287
|
-
Test the following scenarios:
|
|
288
|
-
|
|
289
|
-
1. **Permission check**: Log in as non-admin user
|
|
290
|
-
- Navigate to project settings
|
|
291
|
-
- Verify delete button is visible (backend will reject)
|
|
292
|
-
|
|
293
|
-
2. **Dialog behavior**:
|
|
294
|
-
- Click "删除项目" button
|
|
295
|
-
- Verify dialog opens
|
|
296
|
-
- Verify warning icon and message are displayed
|
|
297
|
-
- Type incorrect project name
|
|
298
|
-
- Verify "删除项目" button stays disabled
|
|
299
|
-
- Type correct project name
|
|
300
|
-
- Verify "删除项目" button becomes enabled
|
|
301
|
-
|
|
302
|
-
3. **Cancel flow**:
|
|
303
|
-
- Open dialog
|
|
304
|
-
- Type partial project name
|
|
305
|
-
- Click "取消"
|
|
306
|
-
- Verify dialog closes
|
|
307
|
-
- Re-open dialog
|
|
308
|
-
- Verify input field is empty (state reset)
|
|
309
|
-
|
|
310
|
-
4. **Successful delete**:
|
|
311
|
-
- Open dialog
|
|
312
|
-
- Type exact project name
|
|
313
|
-
- Click "删除项目"
|
|
314
|
-
- Verify button shows "删除中..." loading state
|
|
315
|
-
- Verify redirect to `/settings/projects`
|
|
316
|
-
- Verify project is removed from list
|
|
317
|
-
|
|
318
|
-
5. **Error handling**:
|
|
319
|
-
- Simulate network error (disconnect internet)
|
|
320
|
-
- Try to delete
|
|
321
|
-
- Verify error message is displayed
|
|
322
|
-
- Verify dialog stays open
|
|
323
|
-
- Verify user can retry
|
|
324
|
-
|
|
325
|
-
**Step 2: Document test results**
|
|
326
|
-
|
|
327
|
-
Create a test results file:
|
|
328
|
-
|
|
329
|
-
```bash
|
|
330
|
-
echo "# Delete Project Feature - Manual Test Results
|
|
331
|
-
|
|
332
|
-
Date: $(date +%Y-%m-%d)
|
|
333
|
-
|
|
334
|
-
## Test Cases
|
|
335
|
-
|
|
336
|
-
- [ ] Dialog opens when delete button clicked
|
|
337
|
-
- [ ] Warning icon and message displayed
|
|
338
|
-
- [ ] Input validation works (exact match required)
|
|
339
|
-
- [ ] Cancel button closes dialog and resets state
|
|
340
|
-
- [ ] Successful delete redirects to project list
|
|
341
|
-
- [ ] Error messages displayed on failure
|
|
342
|
-
- [ ] Loading state shown during delete
|
|
343
|
-
- [ ] Backend permission check works
|
|
344
|
-
|
|
345
|
-
## Notes
|
|
346
|
-
|
|
347
|
-
[Add any observations or issues found]
|
|
348
|
-
" > docs/testing/delete-project-manual-tests.md
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
**Step 3: Commit test documentation**
|
|
352
|
-
|
|
353
|
-
```bash
|
|
354
|
-
git add docs/testing/delete-project-manual-tests.md
|
|
355
|
-
git commit -m "docs: add manual test checklist for project delete feature"
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
---
|
|
359
|
-
|
|
360
|
-
## Task 4: Update Component Exports (Optional)
|
|
361
|
-
|
|
362
|
-
**Files:**
|
|
363
|
-
- Modify: `components/project/index.ts` (if it exists)
|
|
364
|
-
|
|
365
|
-
**Step 1: Check if index file exists**
|
|
366
|
-
|
|
367
|
-
```bash
|
|
368
|
-
ls components/project/index.ts
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
**Step 2: If exists, add export**
|
|
372
|
-
|
|
373
|
-
If the file exists, add:
|
|
374
|
-
|
|
375
|
-
```tsx
|
|
376
|
-
export { DeleteProjectDialog } from "./delete-project-dialog";
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
**Step 3: Commit if modified**
|
|
380
|
-
|
|
381
|
-
```bash
|
|
382
|
-
git add components/project/index.ts
|
|
383
|
-
git commit -m "chore: export DeleteProjectDialog component"
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
If the file doesn't exist, skip this task.
|
|
387
|
-
|
|
388
|
-
---
|
|
389
|
-
|
|
390
|
-
## Task 5: Final Verification
|
|
391
|
-
|
|
392
|
-
**Step 1: Run full build**
|
|
393
|
-
|
|
394
|
-
```bash
|
|
395
|
-
bun run build
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
Expected: Build succeeds with no errors.
|
|
399
|
-
|
|
400
|
-
**Step 2: Run linter**
|
|
401
|
-
|
|
402
|
-
```bash
|
|
403
|
-
bun run lint
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
Expected: No new linting errors in modified/created files.
|
|
407
|
-
|
|
408
|
-
**Step 3: Create final commit if needed**
|
|
409
|
-
|
|
410
|
-
If there are any lint fixes:
|
|
411
|
-
|
|
412
|
-
```bash
|
|
413
|
-
git add .
|
|
414
|
-
git commit -m "style: fix lint issues in delete project feature"
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
---
|
|
418
|
-
|
|
419
|
-
## Completion Checklist
|
|
420
|
-
|
|
421
|
-
- [x] DeleteProjectDialog component created
|
|
422
|
-
- [x] Danger zone added to project settings
|
|
423
|
-
- [x] Delete button triggers confirmation dialog
|
|
424
|
-
- [x] Input validation requires exact project name match
|
|
425
|
-
- [x] Successful delete redirects to project list
|
|
426
|
-
- [x] Error handling displays user-friendly messages
|
|
427
|
-
- [x] Loading states prevent duplicate actions
|
|
428
|
-
- [x] All TypeScript checks pass
|
|
429
|
-
- [x] Manual testing completed
|
|
430
|
-
- [x] Code committed with clear commit messages
|
|
431
|
-
|
|
432
|
-
---
|
|
433
|
-
|
|
434
|
-
## Post-Implementation Notes
|
|
435
|
-
|
|
436
|
-
**Future Enhancements:**
|
|
437
|
-
1. Add toast notification on successful delete
|
|
438
|
-
2. Show feedback count before deleting
|
|
439
|
-
3. Add soft delete capability (deletedAt field)
|
|
440
|
-
4. Allow data export before deletion
|
|
441
|
-
5. Add unit tests for DeleteProjectDialog component
|
|
442
|
-
|
|
443
|
-
**Known Limitations:**
|
|
444
|
-
- No undo functionality (permanent delete)
|
|
445
|
-
- No batch delete capability
|
|
446
|
-
- No feedback count preview in dialog
|
|
447
|
-
|
|
448
|
-
**Related Files:**
|
|
449
|
-
- Backend API: `app/api/projects/[projectId]/route.ts` (already implements DELETE)
|
|
450
|
-
- Database schema: `lib/db/schema/projects.ts` (cascade delete configured)
|
|
451
|
-
- Permissions: Admin-only enforced at API level
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Design: Project Edit and Delete Features
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
Add functionality to edit project details (name, description) and delete projects within the Project Settings page. This completes the project management lifecycle.
|
|
5
|
-
|
|
6
|
-
## Components
|
|
7
|
-
|
|
8
|
-
### 1. `ProjectEditForm`
|
|
9
|
-
A client component for editing basic project information.
|
|
10
|
-
- **Location**: `components/project/project-edit-form.tsx`
|
|
11
|
-
- **Props**: `project: Project`
|
|
12
|
-
- **State**: Uses `react-hook-form` with `zodResolver` and `updateProjectSchema`.
|
|
13
|
-
- **UI**:
|
|
14
|
-
- Card with "Project Details" title.
|
|
15
|
-
- Input for Name.
|
|
16
|
-
- Textarea for Description.
|
|
17
|
-
- Submit button.
|
|
18
|
-
- **Action**: calls `PUT /api/projects/[projectId]`.
|
|
19
|
-
|
|
20
|
-
### 2. `ProjectDeleteSection`
|
|
21
|
-
A client component for the "Danger Zone".
|
|
22
|
-
- **Location**: `components/project/project-delete-section.tsx`
|
|
23
|
-
- **Props**: `project: Project`
|
|
24
|
-
- **UI**:
|
|
25
|
-
- Card with red border/styling to indicate danger.
|
|
26
|
-
- Title "Danger Zone".
|
|
27
|
-
- "Delete Project" button (destructive variant).
|
|
28
|
-
- Confirmation Dialog (`AlertDialog`) requiring user confirmation.
|
|
29
|
-
- **Action**: calls `DELETE /api/projects/[projectId]`.
|
|
30
|
-
- **Post-Action**: Redirects to `/settings/projects` (or dashboard).
|
|
31
|
-
|
|
32
|
-
### 3. `ProjectSettings` (Refactor)
|
|
33
|
-
Update the existing `components/project/project-settings.tsx`.
|
|
34
|
-
- Currently, it contains the entire Widget Config form logic.
|
|
35
|
-
- **Refactoring**:
|
|
36
|
-
- Extract the existing form logic into `components/project/project-widget-form.tsx`.
|
|
37
|
-
- Update `ProjectSettings` to be a layout container that renders:
|
|
38
|
-
1. `<ProjectEditForm />`
|
|
39
|
-
2. `<ProjectWidgetForm />` (The extracted widget config)
|
|
40
|
-
3. `<ProjectDeleteSection />`
|
|
41
|
-
|
|
42
|
-
## API Interactions
|
|
43
|
-
- **Update**: `PUT /api/projects/[projectId]` (Existing)
|
|
44
|
-
- Supports partial updates of `name`, `description`, `widgetConfig`.
|
|
45
|
-
- **Delete**: `DELETE /api/projects/[projectId]` (Existing)
|
|
46
|
-
- Deletes project and cascades (handled by DB schema, verified in previous reads).
|
|
47
|
-
|
|
48
|
-
## Plan
|
|
49
|
-
1. Extract `ProjectWidgetForm` from `project-settings.tsx`.
|
|
50
|
-
2. Create `ProjectEditForm`.
|
|
51
|
-
3. Create `ProjectDeleteSection`.
|
|
52
|
-
4. Reassemble `ProjectSettings`.
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# Settings Center Design
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Consolidate all settings-related features (notifications, profile, organization, etc.) into a unified Settings Center, accessible from the user dropdown menu in the sidebar.
|
|
6
|
-
|
|
7
|
-
## Current Problems
|
|
8
|
-
|
|
9
|
-
1. "Notifications Settings" appears in both navigation area and user section
|
|
10
|
-
2. Missing user Profile page entry
|
|
11
|
-
3. "Organization Settings" link points to `/settings/organizations/new` (create page instead of management page)
|
|
12
|
-
4. Settings features scattered across different locations
|
|
13
|
-
|
|
14
|
-
## Design Decisions
|
|
15
|
-
|
|
16
|
-
- **Settings entry**: User dropdown menu only (not in main navigation)
|
|
17
|
-
- **Layout**: Left-right split layout (sidebar menu + content area)
|
|
18
|
-
- **Categories**: Profile, Notifications, Appearance, Organization (admin), API Keys (admin/pm)
|
|
19
|
-
|
|
20
|
-
## Sidebar Structure
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
Navigation:
|
|
24
|
-
├── Dashboard /dashboard
|
|
25
|
-
└── Feedback /feedback
|
|
26
|
-
|
|
27
|
-
Projects:
|
|
28
|
-
├── + New Project
|
|
29
|
-
└── Project list...
|
|
30
|
-
|
|
31
|
-
User Area (bottom):
|
|
32
|
-
└── [Avatar] Username ▼ ← Dropdown menu
|
|
33
|
-
├── Settings → /settings
|
|
34
|
-
└── Sign Out
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Settings Center Routes
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
/settings
|
|
41
|
-
├── /settings/profile Personal profile (default)
|
|
42
|
-
├── /settings/notifications Notification preferences
|
|
43
|
-
├── /settings/appearance Theme settings
|
|
44
|
-
├── /settings/organization Organization management (admin only)
|
|
45
|
-
└── /settings/api-keys API key management (admin/pm only)
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Page Content
|
|
49
|
-
|
|
50
|
-
### Profile `/settings/profile`
|
|
51
|
-
- Avatar upload/change
|
|
52
|
-
- Name editing
|
|
53
|
-
- Email display (read-only or editable)
|
|
54
|
-
- Change password
|
|
55
|
-
|
|
56
|
-
### Notifications `/settings/notifications`
|
|
57
|
-
- Email notification toggle
|
|
58
|
-
- Notification type preferences (new feedback, status changes, comment replies, etc.)
|
|
59
|
-
|
|
60
|
-
### Appearance `/settings/appearance`
|
|
61
|
-
- Theme toggle (light/dark/system)
|
|
62
|
-
- Language selection (if needed)
|
|
63
|
-
|
|
64
|
-
### Organization `/settings/organization` (admin only)
|
|
65
|
-
- Organization name, description editing
|
|
66
|
-
- Member list and role management
|
|
67
|
-
- Invite new members
|
|
68
|
-
|
|
69
|
-
### API Keys `/settings/api-keys` (admin/pm only)
|
|
70
|
-
- Key list
|
|
71
|
-
- Create/delete keys
|
|
72
|
-
|
|
73
|
-
## File Structure
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
app/(dashboard)/settings/
|
|
77
|
-
├── layout.tsx ← Settings layout (left-right split)
|
|
78
|
-
├── page.tsx ← Redirect to /settings/profile
|
|
79
|
-
├── profile/page.tsx
|
|
80
|
-
├── notifications/page.tsx
|
|
81
|
-
├── appearance/page.tsx
|
|
82
|
-
├── organization/page.tsx
|
|
83
|
-
└── api-keys/page.tsx
|
|
84
|
-
|
|
85
|
-
components/settings/
|
|
86
|
-
├── settings-sidebar.tsx ← Left menu with role-based visibility
|
|
87
|
-
└── index.ts
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Component Changes
|
|
91
|
-
|
|
92
|
-
### Sidebar (`components/layout/sidebar.tsx`)
|
|
93
|
-
- Remove "Notifications Settings" and "Organization Settings" nav items
|
|
94
|
-
- Replace user area with `DropdownMenu` component
|
|
95
|
-
- Dropdown contains: Settings link, Sign Out button
|
|
96
|
-
|
|
97
|
-
### Settings Layout
|
|
98
|
-
```tsx
|
|
99
|
-
// SettingsLayout
|
|
100
|
-
<div className="flex">
|
|
101
|
-
<aside> ← SettingsSidebar (left menu)
|
|
102
|
-
<main> ← Content area {children}
|
|
103
|
-
</div>
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Permission Control
|
|
107
|
-
- `SettingsSidebar`: Conditionally render menu items based on `user.role`
|
|
108
|
-
- Each page: Server-side permission check (prevent direct URL access)
|
|
109
|
-
|
|
110
|
-
## Implementation Notes
|
|
111
|
-
|
|
112
|
-
- Use existing Radix UI `DropdownMenu` component
|
|
113
|
-
- Reuse existing notification settings page content
|
|
114
|
-
- Organization page should use existing organization/member management logic
|