@allbluecn/web-app 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +230 -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.1",
|
|
4
4
|
"license": "AGPL-3.0-or-later",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,12 +12,233 @@
|
|
|
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/database": "workspace:*",
|
|
240
|
+
"@allbluecn/kernel": "workspace:*",
|
|
241
|
+
"@allbluecn/shared": "workspace:*",
|
|
21
242
|
"@ariakit/react": "^0.4.28",
|
|
22
243
|
"@auth/core": "^0.41.2",
|
|
23
244
|
"@auth/prisma-adapter": "^2.11.2",
|
|
@@ -103,8 +324,10 @@
|
|
|
103
324
|
"is-hotkey": "^0.2.0",
|
|
104
325
|
"isomorphic-dompurify": "^3.22.0",
|
|
105
326
|
"lowlight": "^3.3.0",
|
|
106
|
-
"lucide
|
|
327
|
+
"lucide": "^1.38.0",
|
|
328
|
+
"lucide-react": "^1.27.0",
|
|
107
329
|
"mind-elixir": "^5.12.2",
|
|
330
|
+
"morphicons": "^1.7.1",
|
|
108
331
|
"motion": "^12.42.2",
|
|
109
332
|
"nanoid": "^5.1.11",
|
|
110
333
|
"next-themes": "^0.4.6",
|
|
@@ -112,6 +335,7 @@
|
|
|
112
335
|
"ogl": "^1.0.11",
|
|
113
336
|
"open-file-viewer-workspace": "github:xushanpei/open-file-viewer",
|
|
114
337
|
"pdfjs-dist": "^6.3.289",
|
|
338
|
+
"pinyin-pro": "^3.29.3",
|
|
115
339
|
"prisma": "^7.8.0",
|
|
116
340
|
"radix-ui": "^1.4.3",
|
|
117
341
|
"react": "19.2.4",
|
|
@@ -130,17 +354,10 @@
|
|
|
130
354
|
"tailwind-merge": "^3.5.0",
|
|
131
355
|
"three": "^0.180.0",
|
|
132
356
|
"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"
|
|
357
|
+
"zod": "^4.4.3"
|
|
142
358
|
},
|
|
143
359
|
"devDependencies": {
|
|
360
|
+
"@allblue/devtools": "workspace:*",
|
|
144
361
|
"@babel/parser": "^8.0.4",
|
|
145
362
|
"@babel/traverse": "^8.0.4",
|
|
146
363
|
"@cloudflare/vite-plugin": "^1.40.1",
|
|
@@ -172,8 +389,7 @@
|
|
|
172
389
|
"typescript": "^7",
|
|
173
390
|
"vite": "^8.1.5",
|
|
174
391
|
"vitest": "^4.1.5",
|
|
175
|
-
"wrangler": "^4.99.0"
|
|
176
|
-
"@allblue/devtools": "0.0.1"
|
|
392
|
+
"wrangler": "^4.99.0"
|
|
177
393
|
},
|
|
178
394
|
"prisma": {
|
|
179
395
|
"version": "7.8.0",
|
|
@@ -181,21 +397,5 @@
|
|
|
181
397
|
},
|
|
182
398
|
"optionalDependencies": {
|
|
183
399
|
"@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
400
|
}
|
|
201
|
-
}
|
|
401
|
+
}
|
|
@@ -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
|
+
};
|