@allbluecn/web-app 0.5.1 → 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/package.json +235 -30
- package/src/components/iteration/auto-schedule-dialog.tsx +150 -0
- package/src/components/iteration/burndown-chart.tsx +63 -0
- package/src/components/iteration/constants.ts +28 -0
- package/src/components/iteration/create-iteration-dialog.tsx +140 -0
- package/src/components/iteration/iteration-card.tsx +60 -0
- package/src/components/iteration/iteration-editor.tsx +116 -0
- package/src/components/iteration/iteration-progress-bar.tsx +44 -0
- package/src/components/iteration/iteration-status-badge.tsx +33 -0
- package/src/components/knowledge/dialog/knowledge-form-dialog.tsx +21 -30
- package/src/components/layout/sidebar-03/__tests__/nav-workspace.test.tsx +2 -2
- package/src/components/layout/sidebar-03/nav-workspace.tsx +2 -2
- package/src/components/project/create-project-dialog.tsx +44 -57
- package/src/components/shared/__tests__/lucide-curated-icons.test.ts +83 -0
- package/src/components/shared/__tests__/lucide-icon-data.test.ts +131 -0
- package/src/components/shared/__tests__/lucide-icon-picker.test.tsx +197 -0
- package/src/components/shared/lucide-icon-picker/curated-icons.ts +478 -0
- package/src/components/shared/lucide-icon-picker/icon-data.ts +109 -0
- package/src/components/shared/lucide-icon-picker/index.tsx +82 -0
- package/src/components/shared/lucide-icon-picker/lucide-icon-by-name.tsx +78 -0
- package/src/components/shared/lucide-icon-picker/panel.tsx +163 -0
- package/src/components/story/__tests__/constants.test.ts +255 -0
- package/src/components/story/ai/story-ai-panel.tsx +23 -15
- package/src/components/story/ai/story-ai-preview-list.tsx +19 -0
- package/src/components/story/constants.ts +33 -1
- package/src/components/story/create-story-dialog.tsx +30 -10
- package/src/components/story/detail/__tests__/categories.test.tsx +62 -0
- package/src/components/story/detail/__tests__/dependencies-button.test.tsx +49 -0
- package/src/components/story/detail/activity-timeline.tsx +11 -4
- package/src/components/story/detail/story-detail-body.tsx +89 -38
- package/src/components/story/detail/story-detail-toolbar/associated-attachments-panel.tsx +118 -9
- package/src/components/story/detail/story-detail-toolbar/children.tsx +7 -4
- package/src/components/story/detail/story-detail-toolbar/dependency-panel.tsx +67 -7
- package/src/components/story/detail/story-detail-toolbar.tsx +6 -1
- package/src/components/story/detail/story-properties.tsx +21 -4
- package/src/components/story/display/__tests__/group-fields.test.ts +107 -0
- package/src/components/story/display/group-resolver.tsx +2 -2
- package/src/components/story/inline-editors/__tests__/dependency-type-select.test.tsx +155 -0
- package/src/components/story/inline-editors/__tests__/labels-editor.test.tsx +155 -0
- package/src/components/story/inline-editors/__tests__/priority-editor.test.tsx +173 -0
- package/src/components/story/inline-editors/__tests__/state-editor.test.tsx +174 -0
- package/src/components/story/inline-editors/dependency-type-select.tsx +180 -0
- package/src/components/story/inline-editors/index.ts +2 -1
- package/src/components/story/inline-editors/labels-editor.tsx +159 -3
- package/src/components/story/inline-editors/story-select-dialog.tsx +22 -59
- package/src/components/story/peek-panel.tsx +121 -21
- package/src/components/story/relations/link-manage-dialog.tsx +2 -1
- package/src/components/story/relations/story-ref-row.tsx +17 -27
- package/src/components/story/story-panel-header.tsx +25 -19
- package/src/components/story/story-toolbar.tsx +3 -3
- package/src/components/story/transfer-story-popover.tsx +2 -2
- package/src/components/story/types.ts +1 -0
- package/src/components/story/views/create-view-dialog.tsx +3 -3
- package/src/components/story/views/story-list/__tests__/group-header.test.tsx +219 -0
- package/src/components/story/views/story-list/group.tsx +1 -1
- package/src/components/story/views/story-list/inline-story-creator.tsx +2 -2
- package/src/components/story/views/story-list/row.tsx +1 -1
- package/src/components/workspace/create-workspace-dialog.tsx +41 -49
- package/src/lib/__tests__/project-display-id.test.ts +8 -5
- package/src/lib/changelog/sdk-versions.ts +20 -20
- package/src/lib/iteration/__tests__/status.test.ts +41 -0
- package/src/lib/iteration/status.ts +28 -0
- package/src/lib/project-display-id.ts +14 -5
- package/src/lib/project-module-meta.ts +77 -0
- package/src/lib/utils.d.ts +1 -1
- package/src/providers/index.tsx +6 -0
- package/src/routeTree.gen.ts +54 -0
- package/src/routes/__root.tsx +0 -8
- package/src/routes/_nav/knowledge/index.lazy.tsx +2 -2
- package/src/routes/_nav/projects/$projectId/$storyId/route.lazy.tsx +52 -25
- package/src/routes/_nav/projects/$projectId/$storyId/route.tsx +6 -3
- package/src/routes/_nav/projects/$projectId/index.lazy.tsx +32 -15
- package/src/routes/_nav/projects/$projectId/iterations/$iterationId/route.lazy.tsx +289 -0
- package/src/routes/_nav/projects/$projectId/iterations/$iterationId/route.tsx +27 -0
- package/src/routes/_nav/projects/$projectId/iterations/index.lazy.tsx +111 -0
- package/src/routes/_nav/projects/$projectId/iterations/index.tsx +24 -0
- package/src/routes/_nav/projects/$projectId/route.tsx +4 -2
- package/src/routes/_nav/projects/$projectId/settings/route.lazy.tsx +4 -4
- package/src/routes/_nav/stories/$storyId/route.lazy.tsx +5 -1
- package/src/routes/_nav/stories/$storyId/route.tsx +4 -0
- package/src/routes/_nav/workspaces/$workspaceId/route.lazy.tsx +3 -3
- package/src/routes/_nav/workspaces/$workspaceId/settings/route.lazy.tsx +4 -4
- package/src/routes/_nav/workspaces/index.lazy.tsx +3 -3
- package/src/server/serverFns/iteration/__tests__/auto-schedule-core.test.ts +62 -0
- package/src/server/serverFns/iteration/__tests__/burndown-core.test.ts +90 -0
- package/src/server/serverFns/iteration/__tests__/iteration-crud.test.ts +211 -0
- package/src/server/serverFns/iteration/__tests__/iteration-stories.test.ts +155 -0
- package/src/server/serverFns/iteration/__tests__/iteration-transfer.test.ts +136 -0
- package/src/server/serverFns/iteration/auto-schedule-core.ts +54 -0
- package/src/server/serverFns/iteration/auto-schedule-internal.ts +88 -0
- package/src/server/serverFns/iteration/burndown-core.ts +60 -0
- package/src/server/serverFns/iteration/index.ts +22 -0
- package/src/server/serverFns/iteration/iteration-auto-schedule.ts +66 -0
- package/src/server/serverFns/iteration/iteration-burndown.ts +70 -0
- package/src/server/serverFns/iteration/iteration-crud.ts +208 -0
- package/src/server/serverFns/iteration/iteration-stories.ts +111 -0
- package/src/server/serverFns/iteration/iteration-transfer.ts +42 -0
- package/src/server/serverFns/iteration/schemas.ts +58 -0
- package/src/server/serverFns/iteration/transfer-internal.ts +62 -0
- package/src/server/serverFns/project/module-overview.ts +109 -0
- package/src/server/serverFns/project.ts +2 -2
- package/src/server/serverFns/story/__tests__/label-suggest-fn.test.ts +100 -0
- package/src/server/serverFns/story/__tests__/labels.test.ts +67 -0
- package/src/server/serverFns/story/__tests__/story-dependencies.test.ts +106 -2
- package/src/server/serverFns/story/index.ts +3 -0
- package/src/server/serverFns/story/story-assoc.ts +36 -4
- package/src/server/serverFns/story/story-attachments.ts +20 -2
- package/src/{components/project/project-icon.tsx → server/serverFns/story/story-crud/label-palette.ts} +16 -19
- package/src/server/serverFns/story/story-crud/label-suggest-core.ts +88 -0
- package/src/server/serverFns/story/story-crud/label-suggest.ts +38 -0
- package/src/{components/knowledge/knowledge-icon.tsx → server/serverFns/story/story-crud/label-upsert.ts} +13 -19
- package/src/server/serverFns/story/story-crud/labels.ts +3 -5
- package/src/server/serverFns/story/story-crud.ts +32 -2
- package/src/server/serverFns/story/story-dependencies.ts +123 -2
- package/src/server/serverFns/story/story-links.ts +30 -6
- package/src/server/serverFns/story/story-transfer.ts +5 -4
- package/src/server/serverFns/story/types.ts +1 -0
- package/src/types/project.ts +5 -5
- package/src/components/project/project-animated-icon.tsx +0 -73
- package/src/components/shared/icon-packs/index.ts +0 -1
- package/src/components/shared/icon-packs/knowledge.ts +0 -1
- package/src/components/shared/icon-packs/prd.ts +0 -1
- package/src/components/shared/icon-packs/project.ts +0 -1
- package/src/components/shared/icon-picker.tsx +0 -1
- package/src/lib/project-mock.ts +0 -156
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allbluecn/web-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"license": "AGPL-3.0-or-later",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,12 +12,238 @@
|
|
|
12
12
|
"./vite.shared": {
|
|
13
13
|
"types": "./vite.shared.ts",
|
|
14
14
|
"default": "./vite.shared.ts"
|
|
15
|
+
},
|
|
16
|
+
"./lucide-icon-picker": {
|
|
17
|
+
"types": "./src/components/shared/lucide-icon-picker/index.tsx",
|
|
18
|
+
"default": "./src/components/shared/lucide-icon-picker/index.tsx"
|
|
19
|
+
},
|
|
20
|
+
"./lucide-icon-picker/panel": {
|
|
21
|
+
"types": "./src/components/shared/lucide-icon-picker/panel.tsx",
|
|
22
|
+
"default": "./src/components/shared/lucide-icon-picker/panel.tsx"
|
|
23
|
+
},
|
|
24
|
+
"./lucide-icon-picker/icon-data": {
|
|
25
|
+
"types": "./src/components/shared/lucide-icon-picker/icon-data.ts",
|
|
26
|
+
"default": "./src/components/shared/lucide-icon-picker/icon-data.ts"
|
|
27
|
+
},
|
|
28
|
+
"./lucide-icon-picker/curated-icons": {
|
|
29
|
+
"types": "./src/components/shared/lucide-icon-picker/curated-icons.ts",
|
|
30
|
+
"default": "./src/components/shared/lucide-icon-picker/curated-icons.ts"
|
|
31
|
+
},
|
|
32
|
+
"./lucide-icon-picker/lucide-icon-by-name": {
|
|
33
|
+
"types": "./src/components/shared/lucide-icon-picker/lucide-icon-by-name.tsx",
|
|
34
|
+
"default": "./src/components/shared/lucide-icon-picker/lucide-icon-by-name.tsx"
|
|
35
|
+
},
|
|
36
|
+
"./ui/safari": {
|
|
37
|
+
"types": "./src/components/ui/safari.tsx",
|
|
38
|
+
"default": "./src/components/ui/safari.tsx"
|
|
39
|
+
},
|
|
40
|
+
"./ui/alert-dialog": {
|
|
41
|
+
"types": "./src/components/ui/alert-dialog.tsx",
|
|
42
|
+
"default": "./src/components/ui/alert-dialog.tsx"
|
|
43
|
+
},
|
|
44
|
+
"./ui/tabs": {
|
|
45
|
+
"types": "./src/components/ui/tabs.tsx",
|
|
46
|
+
"default": "./src/components/ui/tabs.tsx"
|
|
47
|
+
},
|
|
48
|
+
"./ui/button-group": {
|
|
49
|
+
"types": "./src/components/ui/button-group.tsx",
|
|
50
|
+
"default": "./src/components/ui/button-group.tsx"
|
|
51
|
+
},
|
|
52
|
+
"./ui/card": {
|
|
53
|
+
"types": "./src/components/ui/card.tsx",
|
|
54
|
+
"default": "./src/components/ui/card.tsx"
|
|
55
|
+
},
|
|
56
|
+
"./ui/input-group": {
|
|
57
|
+
"types": "./src/components/ui/input-group.tsx",
|
|
58
|
+
"default": "./src/components/ui/input-group.tsx"
|
|
59
|
+
},
|
|
60
|
+
"./ui/popover": {
|
|
61
|
+
"types": "./src/components/ui/popover.tsx",
|
|
62
|
+
"default": "./src/components/ui/popover.tsx"
|
|
63
|
+
},
|
|
64
|
+
"./ui/progress": {
|
|
65
|
+
"types": "./src/components/ui/progress.tsx",
|
|
66
|
+
"default": "./src/components/ui/progress.tsx"
|
|
67
|
+
},
|
|
68
|
+
"./ui/hover-card": {
|
|
69
|
+
"types": "./src/components/ui/hover-card.tsx",
|
|
70
|
+
"default": "./src/components/ui/hover-card.tsx"
|
|
71
|
+
},
|
|
72
|
+
"./ui/sheet": {
|
|
73
|
+
"types": "./src/components/ui/sheet.tsx",
|
|
74
|
+
"default": "./src/components/ui/sheet.tsx"
|
|
75
|
+
},
|
|
76
|
+
"./ui/field": {
|
|
77
|
+
"types": "./src/components/ui/field.tsx",
|
|
78
|
+
"default": "./src/components/ui/field.tsx"
|
|
79
|
+
},
|
|
80
|
+
"./ui/scroll-area": {
|
|
81
|
+
"types": "./src/components/ui/scroll-area.tsx",
|
|
82
|
+
"default": "./src/components/ui/scroll-area.tsx"
|
|
83
|
+
},
|
|
84
|
+
"./ui/resizable": {
|
|
85
|
+
"types": "./src/components/ui/resizable.tsx",
|
|
86
|
+
"default": "./src/components/ui/resizable.tsx"
|
|
87
|
+
},
|
|
88
|
+
"./ui/label": {
|
|
89
|
+
"types": "./src/components/ui/label.tsx",
|
|
90
|
+
"default": "./src/components/ui/label.tsx"
|
|
91
|
+
},
|
|
92
|
+
"./ui/sonner": {
|
|
93
|
+
"types": "./src/components/ui/sonner.tsx",
|
|
94
|
+
"default": "./src/components/ui/sonner.tsx"
|
|
95
|
+
},
|
|
96
|
+
"./ui/navigation-menu": {
|
|
97
|
+
"types": "./src/components/ui/navigation-menu.tsx",
|
|
98
|
+
"default": "./src/components/ui/navigation-menu.tsx"
|
|
99
|
+
},
|
|
100
|
+
"./ui/accordion": {
|
|
101
|
+
"types": "./src/components/ui/accordion.tsx",
|
|
102
|
+
"default": "./src/components/ui/accordion.tsx"
|
|
103
|
+
},
|
|
104
|
+
"./ui/empty": {
|
|
105
|
+
"types": "./src/components/ui/empty.tsx",
|
|
106
|
+
"default": "./src/components/ui/empty.tsx"
|
|
107
|
+
},
|
|
108
|
+
"./ui/tooltip": {
|
|
109
|
+
"types": "./src/components/ui/tooltip.tsx",
|
|
110
|
+
"default": "./src/components/ui/tooltip.tsx"
|
|
111
|
+
},
|
|
112
|
+
"./ui/alert": {
|
|
113
|
+
"types": "./src/components/ui/alert.tsx",
|
|
114
|
+
"default": "./src/components/ui/alert.tsx"
|
|
115
|
+
},
|
|
116
|
+
"./ui/switch": {
|
|
117
|
+
"types": "./src/components/ui/switch.tsx",
|
|
118
|
+
"default": "./src/components/ui/switch.tsx"
|
|
119
|
+
},
|
|
120
|
+
"./ui/calendar": {
|
|
121
|
+
"types": "./src/components/ui/calendar.tsx",
|
|
122
|
+
"default": "./src/components/ui/calendar.tsx"
|
|
123
|
+
},
|
|
124
|
+
"./ui/breadcrumb": {
|
|
125
|
+
"types": "./src/components/ui/breadcrumb.tsx",
|
|
126
|
+
"default": "./src/components/ui/breadcrumb.tsx"
|
|
127
|
+
},
|
|
128
|
+
"./ui/radio-group": {
|
|
129
|
+
"types": "./src/components/ui/radio-group.tsx",
|
|
130
|
+
"default": "./src/components/ui/radio-group.tsx"
|
|
131
|
+
},
|
|
132
|
+
"./ui/command": {
|
|
133
|
+
"types": "./src/components/ui/command.tsx",
|
|
134
|
+
"default": "./src/components/ui/command.tsx"
|
|
135
|
+
},
|
|
136
|
+
"./ui/item": {
|
|
137
|
+
"types": "./src/components/ui/item.tsx",
|
|
138
|
+
"default": "./src/components/ui/item.tsx"
|
|
139
|
+
},
|
|
140
|
+
"./ui/avatar": {
|
|
141
|
+
"types": "./src/components/ui/avatar.tsx",
|
|
142
|
+
"default": "./src/components/ui/avatar.tsx"
|
|
143
|
+
},
|
|
144
|
+
"./ui/kbd": {
|
|
145
|
+
"types": "./src/components/ui/kbd.tsx",
|
|
146
|
+
"default": "./src/components/ui/kbd.tsx"
|
|
147
|
+
},
|
|
148
|
+
"./ui/dialog": {
|
|
149
|
+
"types": "./src/components/ui/dialog.tsx",
|
|
150
|
+
"default": "./src/components/ui/dialog.tsx"
|
|
151
|
+
},
|
|
152
|
+
"./ui/badge": {
|
|
153
|
+
"types": "./src/components/ui/badge.tsx",
|
|
154
|
+
"default": "./src/components/ui/badge.tsx"
|
|
155
|
+
},
|
|
156
|
+
"./ui/sidebar": {
|
|
157
|
+
"types": "./src/components/ui/sidebar.tsx",
|
|
158
|
+
"default": "./src/components/ui/sidebar.tsx"
|
|
159
|
+
},
|
|
160
|
+
"./ui/table": {
|
|
161
|
+
"types": "./src/components/ui/table.tsx",
|
|
162
|
+
"default": "./src/components/ui/table.tsx"
|
|
163
|
+
},
|
|
164
|
+
"./ui/separator": {
|
|
165
|
+
"types": "./src/components/ui/separator.tsx",
|
|
166
|
+
"default": "./src/components/ui/separator.tsx"
|
|
167
|
+
},
|
|
168
|
+
"./ui/button": {
|
|
169
|
+
"types": "./src/components/ui/button.tsx",
|
|
170
|
+
"default": "./src/components/ui/button.tsx"
|
|
171
|
+
},
|
|
172
|
+
"./ui/toggle": {
|
|
173
|
+
"types": "./src/components/ui/toggle.tsx",
|
|
174
|
+
"default": "./src/components/ui/toggle.tsx"
|
|
175
|
+
},
|
|
176
|
+
"./ui/checkbox": {
|
|
177
|
+
"types": "./src/components/ui/checkbox.tsx",
|
|
178
|
+
"default": "./src/components/ui/checkbox.tsx"
|
|
179
|
+
},
|
|
180
|
+
"./ui/spinner": {
|
|
181
|
+
"types": "./src/components/ui/spinner.tsx",
|
|
182
|
+
"default": "./src/components/ui/spinner.tsx"
|
|
183
|
+
},
|
|
184
|
+
"./ui/collapsible": {
|
|
185
|
+
"types": "./src/components/ui/collapsible.tsx",
|
|
186
|
+
"default": "./src/components/ui/collapsible.tsx"
|
|
187
|
+
},
|
|
188
|
+
"./ui/dropdown-menu": {
|
|
189
|
+
"types": "./src/components/ui/dropdown-menu.tsx",
|
|
190
|
+
"default": "./src/components/ui/dropdown-menu.tsx"
|
|
191
|
+
},
|
|
192
|
+
"./ui/select": {
|
|
193
|
+
"types": "./src/components/ui/select.tsx",
|
|
194
|
+
"default": "./src/components/ui/select.tsx"
|
|
195
|
+
},
|
|
196
|
+
"./ui/textarea": {
|
|
197
|
+
"types": "./src/components/ui/textarea.tsx",
|
|
198
|
+
"default": "./src/components/ui/textarea.tsx"
|
|
199
|
+
},
|
|
200
|
+
"./ui/input": {
|
|
201
|
+
"types": "./src/components/ui/input.tsx",
|
|
202
|
+
"default": "./src/components/ui/input.tsx"
|
|
203
|
+
},
|
|
204
|
+
"./ui/skeleton": {
|
|
205
|
+
"types": "./src/components/ui/skeleton.tsx",
|
|
206
|
+
"default": "./src/components/ui/skeleton.tsx"
|
|
207
|
+
},
|
|
208
|
+
"./ui/context-menu": {
|
|
209
|
+
"types": "./src/components/ui/context-menu.tsx",
|
|
210
|
+
"default": "./src/components/ui/context-menu.tsx"
|
|
211
|
+
},
|
|
212
|
+
"./user-avatar": {
|
|
213
|
+
"types": "./src/components/ui/avatar.tsx",
|
|
214
|
+
"default": "./src/components/ui/avatar.tsx"
|
|
15
215
|
}
|
|
16
216
|
},
|
|
17
217
|
"publishConfig": {
|
|
18
218
|
"access": "public"
|
|
19
219
|
},
|
|
220
|
+
"packageManager": "pnpm@11.20.0",
|
|
221
|
+
"scripts": {
|
|
222
|
+
"dev": "vite --port 3000",
|
|
223
|
+
"build": "vite build",
|
|
224
|
+
"start": "vite preview",
|
|
225
|
+
"lint": "eslint",
|
|
226
|
+
"test": "vitest",
|
|
227
|
+
"test:ui": "vitest --ui",
|
|
228
|
+
"test:run": "vitest run",
|
|
229
|
+
"setup": "pnpm --filter @allbluecn/database generate && pnpm --filter @allbluecn/database migrate:dev",
|
|
230
|
+
"check:features": "tsx scripts/check-feature-keys.ts",
|
|
231
|
+
"assemble": "pnpm -w exec tsx packages/kernel/src/bin.ts --profile oss --assemble --app-dir apps/web",
|
|
232
|
+
"predev": "pnpm assemble && node scripts/check-sdk-versions.mjs",
|
|
233
|
+
"prebuild": "pnpm assemble && node scripts/check-sdk-versions.mjs",
|
|
234
|
+
"pretest": "pnpm assemble",
|
|
235
|
+
"pretest:run": "pnpm assemble",
|
|
236
|
+
"prepublishOnly": "node scripts/check-sdk-versions.mjs"
|
|
237
|
+
},
|
|
20
238
|
"dependencies": {
|
|
239
|
+
"@allbluecn/ai-gateway": "workspace:*",
|
|
240
|
+
"@allbluecn/database": "workspace:*",
|
|
241
|
+
"@allbluecn/kernel": "workspace:*",
|
|
242
|
+
"@allbluecn/plugins-core": "workspace:*",
|
|
243
|
+
"@allbluecn/prototype": "workspace:*",
|
|
244
|
+
"@allbluecn/shared": "workspace:*",
|
|
245
|
+
"@allbluecn/tiptap": "workspace:*",
|
|
246
|
+
"@allbluecn/ui": "workspace:*",
|
|
21
247
|
"@ariakit/react": "^0.4.28",
|
|
22
248
|
"@auth/core": "^0.41.2",
|
|
23
249
|
"@auth/prisma-adapter": "^2.11.2",
|
|
@@ -103,8 +329,10 @@
|
|
|
103
329
|
"is-hotkey": "^0.2.0",
|
|
104
330
|
"isomorphic-dompurify": "^3.22.0",
|
|
105
331
|
"lowlight": "^3.3.0",
|
|
106
|
-
"lucide
|
|
332
|
+
"lucide": "^1.38.0",
|
|
333
|
+
"lucide-react": "^1.27.0",
|
|
107
334
|
"mind-elixir": "^5.12.2",
|
|
335
|
+
"morphicons": "^1.7.1",
|
|
108
336
|
"motion": "^12.42.2",
|
|
109
337
|
"nanoid": "^5.1.11",
|
|
110
338
|
"next-themes": "^0.4.6",
|
|
@@ -112,6 +340,7 @@
|
|
|
112
340
|
"ogl": "^1.0.11",
|
|
113
341
|
"open-file-viewer-workspace": "github:xushanpei/open-file-viewer",
|
|
114
342
|
"pdfjs-dist": "^6.3.289",
|
|
343
|
+
"pinyin-pro": "^3.29.3",
|
|
115
344
|
"prisma": "^7.8.0",
|
|
116
345
|
"radix-ui": "^1.4.3",
|
|
117
346
|
"react": "19.2.4",
|
|
@@ -130,17 +359,10 @@
|
|
|
130
359
|
"tailwind-merge": "^3.5.0",
|
|
131
360
|
"three": "^0.180.0",
|
|
132
361
|
"tw-animate-css": "^1.4.0",
|
|
133
|
-
"zod": "^4.4.3"
|
|
134
|
-
"@allbluecn/ai-gateway": "0.4.17",
|
|
135
|
-
"@allbluecn/kernel": "0.3.1",
|
|
136
|
-
"@allbluecn/plugins-core": "0.4.16",
|
|
137
|
-
"@allbluecn/shared": "0.4.17",
|
|
138
|
-
"@allbluecn/ui": "0.4.17",
|
|
139
|
-
"@allbluecn/prototype": "0.1.1",
|
|
140
|
-
"@allbluecn/tiptap": "0.4.17",
|
|
141
|
-
"@allbluecn/database": "0.4.16"
|
|
362
|
+
"zod": "^4.4.3"
|
|
142
363
|
},
|
|
143
364
|
"devDependencies": {
|
|
365
|
+
"@allblue/devtools": "workspace:*",
|
|
144
366
|
"@babel/parser": "^8.0.4",
|
|
145
367
|
"@babel/traverse": "^8.0.4",
|
|
146
368
|
"@cloudflare/vite-plugin": "^1.40.1",
|
|
@@ -172,8 +394,7 @@
|
|
|
172
394
|
"typescript": "^7",
|
|
173
395
|
"vite": "^8.1.5",
|
|
174
396
|
"vitest": "^4.1.5",
|
|
175
|
-
"wrangler": "^4.99.0"
|
|
176
|
-
"@allblue/devtools": "0.0.1"
|
|
397
|
+
"wrangler": "^4.99.0"
|
|
177
398
|
},
|
|
178
399
|
"prisma": {
|
|
179
400
|
"version": "7.8.0",
|
|
@@ -181,21 +402,5 @@
|
|
|
181
402
|
},
|
|
182
403
|
"optionalDependencies": {
|
|
183
404
|
"@tauri-apps/api": "^2.11.1"
|
|
184
|
-
},
|
|
185
|
-
"scripts": {
|
|
186
|
-
"dev": "vite --port 3000",
|
|
187
|
-
"build": "vite build",
|
|
188
|
-
"start": "vite preview",
|
|
189
|
-
"lint": "eslint",
|
|
190
|
-
"test": "vitest",
|
|
191
|
-
"test:ui": "vitest --ui",
|
|
192
|
-
"test:run": "vitest run",
|
|
193
|
-
"setup": "pnpm --filter @allbluecn/database generate && pnpm --filter @allbluecn/database migrate:dev",
|
|
194
|
-
"check:features": "tsx scripts/check-feature-keys.ts",
|
|
195
|
-
"assemble": "pnpm -w exec tsx packages/kernel/src/bin.ts --profile oss --assemble --app-dir apps/web",
|
|
196
|
-
"predev": "pnpm assemble && node scripts/check-sdk-versions.mjs",
|
|
197
|
-
"prebuild": "pnpm assemble && node scripts/check-sdk-versions.mjs",
|
|
198
|
-
"pretest": "pnpm assemble",
|
|
199
|
-
"pretest:run": "pnpm assemble"
|
|
200
405
|
}
|
|
201
|
-
}
|
|
406
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
//
|
|
5
|
+
// This program is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU Affero General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import { useState, useEffect } from "react";
|
|
19
|
+
import { useTranslation } from "react-i18next";
|
|
20
|
+
import { Button } from "@/components/ui/button";
|
|
21
|
+
import { Input } from "@/components/ui/input";
|
|
22
|
+
import { Switch } from "@/components/ui/switch";
|
|
23
|
+
import {
|
|
24
|
+
Dialog,
|
|
25
|
+
DialogContent,
|
|
26
|
+
DialogFooter,
|
|
27
|
+
DialogHeader,
|
|
28
|
+
DialogTitle,
|
|
29
|
+
} from "@/components/ui/dialog";
|
|
30
|
+
import { getAutoScheduleFn, updateAutoScheduleFn } from "@/server/serverFns/iteration";
|
|
31
|
+
import { toast } from "@/components/ui/sonner";
|
|
32
|
+
import { useQuery } from "@tanstack/react-query";
|
|
33
|
+
|
|
34
|
+
interface AutoScheduleDialogProps {
|
|
35
|
+
open: boolean;
|
|
36
|
+
onOpenChange: (open: boolean) => void;
|
|
37
|
+
projectId: string;
|
|
38
|
+
onSaved?: () => void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function AutoScheduleDialog({ open, onOpenChange, projectId, onSaved }: AutoScheduleDialogProps) {
|
|
42
|
+
const { t } = useTranslation("iterations");
|
|
43
|
+
const [enabled, setEnabled] = useState(false);
|
|
44
|
+
const [title, setTitle] = useState("迭代");
|
|
45
|
+
const [durationDays, setDurationDays] = useState(14);
|
|
46
|
+
const [cooldownDays, setCooldownDays] = useState(0);
|
|
47
|
+
const [startsOn, setStartsOn] = useState("");
|
|
48
|
+
const [futureCount, setFutureCount] = useState(2);
|
|
49
|
+
const [autoRollover, setAutoRollover] = useState(false);
|
|
50
|
+
const [loading, setLoading] = useState(false);
|
|
51
|
+
|
|
52
|
+
const { data } = useQuery({
|
|
53
|
+
queryKey: ["auto-schedule", projectId],
|
|
54
|
+
queryFn: () => getAutoScheduleFn({ data: { projectId } }),
|
|
55
|
+
enabled: open,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (open && data?.config) {
|
|
60
|
+
setEnabled(data.config.enabled);
|
|
61
|
+
setTitle(data.config.title);
|
|
62
|
+
setDurationDays(data.config.durationDays);
|
|
63
|
+
setCooldownDays(data.config.cooldownDays);
|
|
64
|
+
setStartsOn(data.config.startsOn);
|
|
65
|
+
setFutureCount(data.config.futureCount);
|
|
66
|
+
setAutoRollover(data.config.autoRollover);
|
|
67
|
+
} else if (open) {
|
|
68
|
+
setEnabled(false);
|
|
69
|
+
setTitle("迭代");
|
|
70
|
+
setDurationDays(14);
|
|
71
|
+
setCooldownDays(0);
|
|
72
|
+
setStartsOn(new Date().toISOString().slice(0, 10));
|
|
73
|
+
setFutureCount(2);
|
|
74
|
+
setAutoRollover(false);
|
|
75
|
+
}
|
|
76
|
+
}, [open, data]);
|
|
77
|
+
|
|
78
|
+
async function handleSave() {
|
|
79
|
+
setLoading(true);
|
|
80
|
+
try {
|
|
81
|
+
await updateAutoScheduleFn({
|
|
82
|
+
data: {
|
|
83
|
+
projectId,
|
|
84
|
+
enabled,
|
|
85
|
+
title,
|
|
86
|
+
durationDays,
|
|
87
|
+
cooldownDays,
|
|
88
|
+
startsOn,
|
|
89
|
+
futureCount,
|
|
90
|
+
autoRollover,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
toast.success(t("autoSchedule.saved"));
|
|
94
|
+
onSaved?.();
|
|
95
|
+
onOpenChange(false);
|
|
96
|
+
} catch (e) {
|
|
97
|
+
toast.error(e instanceof Error ? e.message : "保存失败");
|
|
98
|
+
} finally {
|
|
99
|
+
setLoading(false);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
105
|
+
<DialogContent className="sm:max-w-md">
|
|
106
|
+
<DialogHeader>
|
|
107
|
+
<DialogTitle>{t("autoSchedule.title")}</DialogTitle>
|
|
108
|
+
</DialogHeader>
|
|
109
|
+
<div className="space-y-4 py-4">
|
|
110
|
+
<div className="flex items-center justify-between">
|
|
111
|
+
<label className="text-sm font-medium">{t("autoSchedule.enabled")}</label>
|
|
112
|
+
<Switch checked={enabled} onCheckedChange={setEnabled} />
|
|
113
|
+
</div>
|
|
114
|
+
{enabled && (
|
|
115
|
+
<>
|
|
116
|
+
<div className="space-y-2">
|
|
117
|
+
<label className="text-sm font-medium">{t("autoSchedule.baseTitle")}</label>
|
|
118
|
+
<Input value={title} onChange={(e) => setTitle(e.target.value)} />
|
|
119
|
+
</div>
|
|
120
|
+
<div className="space-y-2">
|
|
121
|
+
<label className="text-sm font-medium">{t("autoSchedule.durationDays")}</label>
|
|
122
|
+
<Input type="number" min={1} max={90} value={durationDays} onChange={(e) => setDurationDays(Number(e.target.value))} />
|
|
123
|
+
</div>
|
|
124
|
+
<div className="space-y-2">
|
|
125
|
+
<label className="text-sm font-medium">{t("autoSchedule.cooldownDays")}</label>
|
|
126
|
+
<Input type="number" min={0} max={30} value={cooldownDays} onChange={(e) => setCooldownDays(Number(e.target.value))} />
|
|
127
|
+
</div>
|
|
128
|
+
<div className="space-y-2">
|
|
129
|
+
<label className="text-sm font-medium">{t("autoSchedule.startsOn")}</label>
|
|
130
|
+
<Input type="date" value={startsOn} onChange={(e) => setStartsOn(e.target.value)} />
|
|
131
|
+
</div>
|
|
132
|
+
<div className="space-y-2">
|
|
133
|
+
<label className="text-sm font-medium">{t("autoSchedule.futureCount")}</label>
|
|
134
|
+
<Input type="number" min={1} max={10} value={futureCount} onChange={(e) => setFutureCount(Number(e.target.value))} />
|
|
135
|
+
</div>
|
|
136
|
+
<div className="flex items-center justify-between">
|
|
137
|
+
<label className="text-sm font-medium">{t("autoSchedule.autoRollover")}</label>
|
|
138
|
+
<Switch checked={autoRollover} onCheckedChange={setAutoRollover} />
|
|
139
|
+
</div>
|
|
140
|
+
</>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
143
|
+
<DialogFooter>
|
|
144
|
+
<Button variant="outline" onClick={() => onOpenChange(false)}>{t("actions.cancel")}</Button>
|
|
145
|
+
<Button onClick={() => void handleSave()} disabled={loading || !enabled}>{loading ? "保存中..." : t("actions.save")}</Button>
|
|
146
|
+
</DialogFooter>
|
|
147
|
+
</DialogContent>
|
|
148
|
+
</Dialog>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
//
|
|
5
|
+
// This program is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU Affero General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import { useTranslation } from "react-i18next";
|
|
19
|
+
import type { BurndownResult } from "@/server/serverFns/iteration/burndown-core";
|
|
20
|
+
|
|
21
|
+
export function BurndownChart({ data }: { data: BurndownResult & { timezone: string } }) {
|
|
22
|
+
const { t } = useTranslation("iterations");
|
|
23
|
+
if (data.points.length === 0) {
|
|
24
|
+
return <div className="flex h-48 items-center justify-center text-xs text-muted-foreground">{t("burndown.noData")}</div>;
|
|
25
|
+
}
|
|
26
|
+
const W = 640, H = 200, PAD = 28;
|
|
27
|
+
const maxVal = Math.max(1, ...data.points.map((p) => Math.max(p.scope, p.pending, p.ideal)));
|
|
28
|
+
const x = (i: number) => PAD + (i * (W - PAD * 2)) / Math.max(1, data.points.length - 1);
|
|
29
|
+
const y = (v: number) => H - PAD - (v * (H - PAD * 2)) / maxVal;
|
|
30
|
+
const line = (key: "pending" | "ideal") => data.points.map((p, i) => `${i === 0 ? "M" : "L"}${x(i)},${y(p[key])}`).join(" ");
|
|
31
|
+
const fill = data.points.map((p, i) => `${i === 0 ? "M" : "L"}${x(i)},${y(p.pending)}`).join(" ")
|
|
32
|
+
+ " " + [...data.points].reverse().map((p, i) => `L${x(data.points.length - 1 - i)},${y(p.ideal)}`).join(" ");
|
|
33
|
+
const leading = data.status === "leading";
|
|
34
|
+
return (
|
|
35
|
+
<div className="space-y-2">
|
|
36
|
+
<div className="flex items-center justify-between text-xs">
|
|
37
|
+
<span className="font-medium">{t("burndown.title")}</span>
|
|
38
|
+
<span className={leading ? "text-green-600 dark:text-green-400" : data.status === "trailing" ? "text-red-600 dark:text-red-400" : "text-muted-foreground"}>
|
|
39
|
+
{t(leading ? "burndown.leading" : data.status === "trailing" ? "burndown.trailing" : "burndown.pending")}
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
<svg viewBox={`0 0 ${W} ${H}`} className="w-full" role="img">
|
|
43
|
+
{[0, 0.25, 0.5, 0.75, 1].map((r) => (
|
|
44
|
+
<line key={r} x1={PAD} x2={W - PAD} y1={y(maxVal * r)} y2={y(maxVal * r)} className="stroke-border" strokeWidth={1} />
|
|
45
|
+
))}
|
|
46
|
+
<path d={fill} className={leading ? "fill-green-500/15" : "fill-red-500/15"} />
|
|
47
|
+
<path d={line("ideal")} className="stroke-muted-foreground" strokeWidth={1.5} strokeDasharray="4 3" fill="none" />
|
|
48
|
+
<path d={line("pending")} className="stroke-primary" strokeWidth={2} fill="none" />
|
|
49
|
+
{data.points.map((p, i) => (
|
|
50
|
+
<circle key={p.date} cx={x(i)} cy={y(p.pending)} r={2.5} className="fill-primary">
|
|
51
|
+
<title>{`${p.date}: ${p.pending}`}</title>
|
|
52
|
+
</circle>
|
|
53
|
+
))}
|
|
54
|
+
<text x={PAD} y={H - 8} className="fill-muted-foreground text-[10px]">{data.points[0].date}</text>
|
|
55
|
+
<text x={W - PAD} y={H - 8} textAnchor="end" className="fill-muted-foreground text-[10px]">{data.points.at(-1)!.date}</text>
|
|
56
|
+
</svg>
|
|
57
|
+
<div className="flex gap-4 text-xs text-muted-foreground">
|
|
58
|
+
<span className="flex items-center gap-1"><span className="inline-block h-0.5 w-4 bg-primary" />{t("burndown.pending")}</span>
|
|
59
|
+
<span className="flex items-center gap-1"><span className="inline-block h-0.5 w-4 bg-muted-foreground" style={{ backgroundImage: "linear-gradient(90deg, currentColor 50%, transparent 50%)", backgroundSize: "4px 2px" }} />{t("burndown.ideal")}</span>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
//
|
|
5
|
+
// This program is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU Affero General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import { Circle, CircleDot, CircleCheckBig } from "lucide-react";
|
|
19
|
+
import type { LucideIcon } from "lucide-react";
|
|
20
|
+
import type { IterationStatus } from "@/lib/iteration/status";
|
|
21
|
+
|
|
22
|
+
export const ITERATION_STATUS_META: Record<IterationStatus, {
|
|
23
|
+
labelKey: string; icon: LucideIcon; className: string;
|
|
24
|
+
}> = {
|
|
25
|
+
upcoming: { labelKey: "status.upcoming", icon: Circle, className: "bg-blue-500/15 text-blue-600 dark:text-blue-400" },
|
|
26
|
+
active: { labelKey: "status.active", icon: CircleDot, className: "bg-amber-500/15 text-amber-600 dark:text-amber-400" },
|
|
27
|
+
completed: { labelKey: "status.completed", icon: CircleCheckBig, className: "bg-green-500/15 text-green-600 dark:text-green-400" },
|
|
28
|
+
};
|