@allbluecn/web-app 0.19.5 → 0.21.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.
Files changed (235) hide show
  1. package/package.json +3 -3
  2. package/src/components/bug/__tests__/board-subgroups.test.tsx +1 -1
  3. package/src/components/bug/__tests__/board-view.test.tsx +1 -1
  4. package/src/components/bug/__tests__/comment-reactions.test.tsx +1 -1
  5. package/src/components/bug/__tests__/create-bug-dialog.test.tsx +2 -2
  6. package/src/components/bug/__tests__/filters-compat.test.tsx +1 -1
  7. package/src/components/bug/__tests__/fix-request-race.test.tsx +1 -1
  8. package/src/components/bug/__tests__/peek-modes.test.tsx +1 -1
  9. package/src/components/bug/__tests__/use-paged-bug-groups.test.tsx +1 -1
  10. package/src/components/bug/__tests__/view-type.test.tsx +1 -1
  11. package/src/components/bug/bug-list-view.tsx +2 -2
  12. package/src/components/bug/bug-toolbar.tsx +1 -1
  13. package/src/components/bug/create-bug-dialog.tsx +3 -3
  14. package/src/components/bug/detail/__tests__/activity-timeline.test.tsx +1 -1
  15. package/src/components/bug/detail/__tests__/bug-detail-collab.test.tsx +1 -1
  16. package/src/components/bug/detail/__tests__/repro-report-card.test.tsx +1 -1
  17. package/src/components/bug/detail/activity-tabs.tsx +34 -3
  18. package/src/components/bug/detail/activity-timeline.tsx +1 -1
  19. package/src/components/bug/detail/bug-detail-body.tsx +3 -3
  20. package/src/components/bug/detail/comment-input.tsx +1 -1
  21. package/src/components/bug/detail/comment-item.tsx +1 -1
  22. package/src/components/bug/detail/comment-reactions.tsx +1 -1
  23. package/src/components/bug/detail/comment-thread.tsx +1 -1
  24. package/src/components/bug/detail/props-section.tsx +2 -2
  25. package/src/components/bug/detail/repro-report-card.tsx +1 -1
  26. package/src/components/bug/detail/reproduce-steps-view.tsx +1 -1
  27. package/src/components/bug/display/use-paged-bug-groups.ts +2 -2
  28. package/src/components/bug/filters/field-configs.tsx +1 -1
  29. package/src/components/bug/inline-editors/assignee-editor.tsx +1 -1
  30. package/src/components/bug/peek-panel.tsx +2 -2
  31. package/src/components/bug/reproduce-steps-editor.tsx +1 -1
  32. package/src/components/bug/story-bugs-panel.tsx +10 -6
  33. package/src/components/bug/views/board-view.tsx +2 -2
  34. package/src/components/bug/views/bug-list/batch-toolbar.tsx +1 -1
  35. package/src/components/bug/views/bug-list/group.tsx +1 -1
  36. package/src/components/bug/views/bug-list/index.tsx +1 -1
  37. package/src/components/bug/views/bug-list/inline-bug-creator.tsx +1 -1
  38. package/src/components/bug/views/bug-list/row.tsx +2 -2
  39. package/src/components/bug/views/create-view-dialog.tsx +1 -1
  40. package/src/components/design/editor/versions/hooks/use-design-versions.ts +11 -4
  41. package/src/components/design/editor/versions/page-version-panel.tsx +30 -11
  42. package/src/components/harness/code/workspace-context.tsx +5 -1
  43. package/src/components/harness/code/workspace-picker.tsx +19 -6
  44. package/src/components/harness/composer/harness-composer.tsx +25 -3
  45. package/src/components/harness/composer/mention/mention-resolvers.ts +2 -0
  46. package/src/components/harness/composer/mention/mention-suggestion-menu.tsx +6 -3
  47. package/src/components/harness/composer/mention/use-mention-sources.ts +1 -1
  48. package/src/components/iteration/iteration-progress-bar.tsx +2 -2
  49. package/src/components/knowledge/public/legal-compliance-editor.tsx +1 -1
  50. package/src/components/layout/sidebar-03/nav-knowledge.tsx +1 -1
  51. package/src/components/layout/sidebar-03/nav-workspace.tsx +1 -1
  52. package/src/components/project/invite-member-dialog.tsx +2 -2
  53. package/src/components/project/project-member-manager.tsx +0 -3
  54. package/src/components/shared-kit/list-kit/kanban/__tests__/instance-key.test.ts +1 -1
  55. package/src/components/story/__tests__/constants.test.ts +1 -1
  56. package/src/components/story/__tests__/dependency-type-badge.test.ts +1 -1
  57. package/src/components/story/__tests__/peek-panel-patch-sync.test.tsx +1 -1
  58. package/src/components/story/__tests__/story-list-view-peek-sync.test.tsx +1 -1
  59. package/src/components/story/ai/story-ai-panel.tsx +1 -1
  60. package/src/components/story/ai/story-ai-preview-list.tsx +2 -2
  61. package/src/components/story/ai/use-story-ai-model.ts +17 -4
  62. package/src/components/story/columns.tsx +2 -2
  63. package/src/components/story/create-story-dialog.tsx +4 -4
  64. package/src/components/story/detail/__tests__/activity-timeline.test.tsx +1 -1
  65. package/src/components/story/detail/__tests__/associated-attachments-panel.test.tsx +1 -1
  66. package/src/components/story/detail/__tests__/story-collab.test.tsx +1 -1
  67. package/src/components/story/detail/activity-tabs.tsx +1 -1
  68. package/src/components/story/detail/activity-timeline.tsx +36 -17
  69. package/src/components/story/detail/comment-input.tsx +1 -1
  70. package/src/components/story/detail/comment-item.tsx +1 -1
  71. package/src/components/story/detail/comment-thread.tsx +1 -1
  72. package/src/components/story/detail/reaction-bar.tsx +1 -1
  73. package/src/components/story/detail/story-detail-body.tsx +4 -4
  74. package/src/components/story/detail/story-detail-toolbar/__tests__/attachment-cache.test.ts +83 -0
  75. package/src/components/story/detail/story-detail-toolbar/associated-attachments-panel.tsx +50 -9
  76. package/src/components/story/detail/story-detail-toolbar/children.tsx +3 -3
  77. package/src/components/story/detail/story-detail-toolbar/dependency-panel.tsx +9 -8
  78. package/src/components/story/detail/story-detail-toolbar/index.tsx +8 -8
  79. package/src/components/story/detail/story-detail-toolbar/related-test-cases.tsx +2 -2
  80. package/src/components/story/detail/story-properties.tsx +2 -2
  81. package/src/components/story/display/__tests__/flatten-story-groups.test.ts +1 -1
  82. package/src/components/story/display/__tests__/group-fields.test.ts +1 -1
  83. package/src/components/story/display/__tests__/group-resolver.test.ts +2 -2
  84. package/src/components/story/display/__tests__/order-resolver.test.ts +1 -1
  85. package/src/components/story/display/__tests__/use-grouped-stories.test.ts +1 -1
  86. package/src/components/story/display/__tests__/use-paged-story-groups.test.ts +1 -1
  87. package/src/components/story/display/flatten-story-groups.ts +1 -1
  88. package/src/components/story/display/group-fields.ts +2 -2
  89. package/src/components/story/display/group-resolver.tsx +4 -4
  90. package/src/components/story/display/order-resolver.ts +3 -3
  91. package/src/components/story/display/types.ts +5 -4
  92. package/src/components/story/display/use-grouped-stories.ts +5 -5
  93. package/src/components/story/display/use-paged-story-groups.ts +11 -4
  94. package/src/components/story/entity-overlay.ts +24 -0
  95. package/src/components/story/filters/field-configs.tsx +2 -2
  96. package/src/components/story/inline-editors/assignee-editor.tsx +1 -1
  97. package/src/components/story/inline-editors/dependency-type-select.tsx +1 -1
  98. package/src/components/story/inline-editors/parent-story-editor.tsx +2 -2
  99. package/src/components/story/inline-editors/priority-editor.tsx +2 -2
  100. package/src/components/story/inline-editors/state-editor.tsx +2 -2
  101. package/src/components/story/inline-editors/story-select-dialog.tsx +2 -2
  102. package/src/components/story/peek-panel.tsx +6 -5
  103. package/src/components/story/priority-icon.tsx +2 -2
  104. package/src/components/story/relations/__tests__/attachment-manage-dialog.test.tsx +1 -1
  105. package/src/components/story/relations/__tests__/design-select-dialog.test.tsx +1 -1
  106. package/src/components/story/relations/__tests__/knowledge-select-dialog.test.tsx +1 -1
  107. package/src/components/story/relations/__tests__/link-manage-dialog.test.tsx +1 -1
  108. package/src/components/story/relations/attachment-manage-dialog.tsx +4 -4
  109. package/src/components/story/relations/design-select-dialog.tsx +2 -2
  110. package/src/components/story/relations/knowledge-select-dialog.tsx +2 -2
  111. package/src/components/story/relations/link-manage-dialog.tsx +2 -2
  112. package/src/components/story/relations/story-ref-row.tsx +3 -3
  113. package/src/components/story/story-list-table.tsx +1 -1
  114. package/src/components/story/story-list-view.tsx +1 -1
  115. package/src/components/story/story-toolbar.tsx +1 -1
  116. package/src/components/story/transfer-story-popover.tsx +3 -2
  117. package/src/components/story/views/__tests__/calendar-view.test.tsx +1 -1
  118. package/src/components/story/views/__tests__/kanban-drop-subgroup.test.ts +1 -1
  119. package/src/components/story/views/__tests__/kanban-peek-sync.test.tsx +2 -2
  120. package/src/components/story/views/__tests__/kanban-view-membership-sync.test.tsx +1 -1
  121. package/src/components/story/views/__tests__/timeline-view.test.tsx +1 -1
  122. package/src/components/story/views/calendar/__tests__/mappers.test.ts +1 -1
  123. package/src/components/story/views/calendar/mappers.ts +1 -1
  124. package/src/components/story/views/calendar-view.tsx +1 -1
  125. package/src/components/story/views/create-view-dialog.tsx +1 -1
  126. package/src/components/story/views/kanban-view.tsx +2 -2
  127. package/src/components/story/views/story-list/batch-preview-dialog.tsx +2 -2
  128. package/src/components/story/views/story-list/batch-toolbar.tsx +3 -3
  129. package/src/components/story/views/story-list/group.tsx +18 -5
  130. package/src/components/story/views/story-list/index.tsx +4 -2
  131. package/src/components/story/views/story-list/inline-story-creator.tsx +2 -2
  132. package/src/components/story/views/story-list/row.tsx +2 -2
  133. package/src/components/story/views/story-list/use-flat-rows.ts +1 -1
  134. package/src/components/story/views/timeline/__tests__/mappers.test.ts +2 -2
  135. package/src/components/story/views/timeline/mappers.ts +2 -2
  136. package/src/components/story/views/timeline/use-date-commit.ts +1 -1
  137. package/src/components/story/views/timeline-view.tsx +2 -2
  138. package/src/components/testcase/__tests__/case-row.test.tsx +1 -1
  139. package/src/components/testcase/__tests__/create-dialog-scope.test.tsx +1 -1
  140. package/src/components/testcase/__tests__/display-options.test.tsx +1 -1
  141. package/src/components/testcase/__tests__/export-entry.test.tsx +1 -1
  142. package/src/components/testcase/__tests__/list-view.test.tsx +1 -1
  143. package/src/components/testcase/__tests__/step-editor.test.tsx +4 -2
  144. package/src/components/testcase/__tests__/toolbar.test.tsx +1 -1
  145. package/src/components/testcase/create-testcase-dialog.tsx +6 -5
  146. package/src/components/testcase/detail/case-detail-body.tsx +1 -1
  147. package/src/components/testcase/detail/properties.tsx +1 -1
  148. package/src/components/testcase/display/display-dropdown.tsx +2 -2
  149. package/src/components/testcase/display/use-testcase-display-options.ts +1 -1
  150. package/src/components/testcase/filters/field-configs.tsx +1 -1
  151. package/src/components/testcase/generation/draft-card.tsx +2 -2
  152. package/src/components/testcase/inline-editors/assignee-editor.tsx +1 -1
  153. package/src/components/testcase/list/case-row.tsx +1 -1
  154. package/src/components/testcase/list/grouped-list.tsx +1 -1
  155. package/src/components/testcase/list-view.tsx +2 -2
  156. package/src/components/testcase/runs/convert-bug-button.tsx +2 -2
  157. package/src/components/testcase/step-editor.tsx +13 -2
  158. package/src/components/testcase/testcase-toolbar.tsx +2 -2
  159. package/src/components/testcase/views/batch-toolbar.tsx +1 -1
  160. package/src/components/testcase/views/board-view.tsx +2 -2
  161. package/src/lib/changelog/sdk-versions.ts +2 -2
  162. package/src/lib/collections/knowledge/knowledge-bases-collection.ts +2 -1
  163. package/src/lib/collections/query-keys.ts +18 -0
  164. package/src/lib/collections/reference/users-brief-collection.ts +2 -1
  165. package/src/lib/collections/reference/workspaces-collection.ts +2 -1
  166. package/src/lib/story/__tests__/activity-grouper.test.ts +1 -1
  167. package/src/lib/story/activity-grouper.ts +1 -1
  168. package/src/paraglide/messages/_index.d.ts +2 -0
  169. package/src/paraglide/messages/_index.js +88269 -5642
  170. package/src/paraglide/messages/en.js +28255 -0
  171. package/src/paraglide/messages/story_group_loadfailed1.d.ts +17 -0
  172. package/src/paraglide/messages/story_group_loadfailed1.js +30 -0
  173. package/src/paraglide/messages/story_group_retry.d.ts +16 -0
  174. package/src/paraglide/messages/story_group_retry.js +29 -0
  175. package/src/paraglide/messages/zh.js +28253 -0
  176. package/src/routes/_nav/bugs/$bugId/route.lazy.tsx +2 -2
  177. package/src/routes/_nav/projects/$projectId/iterations/$iterationId/route.lazy.tsx +1 -1
  178. package/src/routes/_nav/route.tsx +1 -2
  179. package/src/routes/_nav/stories/$storyId/route.lazy.tsx +2 -2
  180. package/src/routes/_nav/stories/$storyId/route.tsx +1 -1
  181. package/src/routes/api/design/prototype/__tests__/route.test.ts +4 -1
  182. package/src/server/__tests__/task-executor.test.ts +7 -0
  183. package/src/server/ai-gateway/__tests__/ai-output-guard.test.ts +4 -4
  184. package/src/server/ai-gateway/__tests__/tools-authorization.test.ts +25 -0
  185. package/src/server/ai-gateway/tools/server.ts +24 -15
  186. package/src/server/knowledge/reindex-guard.ts +35 -0
  187. package/src/server/lib/__tests__/cron-auth.test.ts +1 -1
  188. package/src/server/serverFns/__tests__/legal-code-canonical.test.ts +169 -0
  189. package/src/server/serverFns/__tests__/story-tree.test.ts +0 -1
  190. package/src/server/serverFns/__tests__/story-types.test.ts +2 -1
  191. package/src/server/serverFns/__tests__/update-bug-guard.test.ts +1 -1
  192. package/src/server/serverFns/bug/__tests__/bug-comments.test.ts +95 -44
  193. package/src/server/serverFns/bug/__tests__/bug-crud.test.ts +46 -18
  194. package/src/server/serverFns/bug/__tests__/bug-groups.test.ts +1 -1
  195. package/src/server/serverFns/bug/bug-activities.ts +2 -2
  196. package/src/server/serverFns/bug/bug-comments.ts +44 -19
  197. package/src/server/serverFns/bug/bug-crud/detail-select.ts +1 -1
  198. package/src/server/serverFns/bug/bug-crud/detail.ts +2 -2
  199. package/src/server/serverFns/bug/bug-crud.ts +142 -110
  200. package/src/server/serverFns/bug/bug-group-query.ts +1 -1
  201. package/src/server/serverFns/bug/bug-groups.ts +2 -2
  202. package/src/server/serverFns/bug/bug-story-utils.ts +1 -1
  203. package/src/server/serverFns/chat/conversations.ts +27 -13
  204. package/src/server/serverFns/harness/github-workspace.ts +32 -25
  205. package/src/server/serverFns/harness/search-mention-candidates.ts +3 -1
  206. package/src/server/serverFns/iteration/iteration-crud.ts +1 -1
  207. package/src/server/serverFns/knowledge/public/legal/create.ts +3 -0
  208. package/src/server/serverFns/knowledge/public/legal/update.ts +8 -8
  209. package/src/server/serverFns/knowledge-index.ts +12 -5
  210. package/src/server/serverFns/project.ts +5 -11
  211. package/src/server/serverFns/story/__tests__/story-dependencies.test.ts +15 -4
  212. package/src/server/serverFns/story/__tests__/story-transfer.test.ts +20 -0
  213. package/src/server/serverFns/story/link-preview.ts +3 -2
  214. package/src/server/serverFns/story/story-children.ts +1 -1
  215. package/src/server/serverFns/story/story-comments.ts +1 -1
  216. package/src/server/serverFns/story/story-crud/bulk.ts +1 -1
  217. package/src/server/serverFns/story/story-crud.ts +1 -1
  218. package/src/server/serverFns/story/story-dependencies.ts +61 -69
  219. package/src/server/serverFns/story/story-groups.ts +1 -1
  220. package/src/server/serverFns/story/story-transfer.ts +8 -20
  221. package/src/server/serverFns/testcase/__tests__/automation.test.ts +21 -0
  222. package/src/server/serverFns/testcase/__tests__/testcase-groups.test.ts +1 -1
  223. package/src/server/serverFns/testcase/automation.ts +24 -1
  224. package/src/server/serverFns/testcase/testcase-board.ts +1 -1
  225. package/src/server/serverFns/testcase/testcase-crud.ts +1 -1
  226. package/src/server/serverFns/testcase/testcase-display-options.ts +1 -1
  227. package/src/server/serverFns/testcase/testcase-filter-views.ts +1 -1
  228. package/src/server/serverFns/testcase/types.ts +1 -1
  229. package/src/server/story/types.ts +7 -3
  230. package/src/shared/bug/__tests__/constants.test.ts +1 -1
  231. package/src/{components → shared}/bug/types.ts +4 -3
  232. package/src/{components → shared}/story/constants.ts +1 -1
  233. package/src/{components → shared}/story/types.ts +1 -7
  234. package/src/types/project.ts +1 -2
  235. /package/src/{components/testcase/display → shared/testcase}/field-configs.ts +0 -0
@@ -15,11 +15,11 @@
15
15
  // You should have received a copy of the GNU Affero General Public License
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
- import type { StoryListItem } from "../types";
18
+ import type { StoryListItem } from "@/shared/story/types";
19
19
  import type { OrderKey, OrderDirection } from "./types";
20
- import { PRIORITY_RANK } from "../constants";
20
+ import { PRIORITY_RANK } from "@/shared/story/constants";
21
21
 
22
- export function applyOrder(items: StoryListItem[], order: OrderKey, dir: OrderDirection = "asc"): StoryListItem[] {
22
+ export function applyOrder<T extends StoryListItem = StoryListItem>(items: T[], order: OrderKey, dir: OrderDirection = "asc"): T[] {
23
23
  const sorted = [...items];
24
24
  const mult = dir === "desc" ? -1 : 1;
25
25
  switch (order) {
@@ -20,7 +20,7 @@
20
20
  // 与运行时常量为 story 规范口径落共享层 values.ts,此处仅透传保持消费方
21
21
  // import 不变)。story 专属的 GroupNode/GroupContext 留本文件。
22
22
 
23
- import type { StoryListItem, UserBrief } from "../types";
23
+ import type { StoryListItem, UserBrief } from "@/shared/story/types";
24
24
 
25
25
  export {
26
26
  GROUP_KEYS,
@@ -42,13 +42,14 @@ export type {
42
42
  PageSize,
43
43
  } from "@/shared/list-kit/display-types";
44
44
 
45
- export interface GroupNode {
45
+ // T=行类型(S14):DependencyRow 等公共行扩展可复用同一分组栈,消费方免 as 强转。
46
+ export interface GroupNode<T = StoryListItem> {
46
47
  key: string;
47
48
  label: string;
48
49
  icon?: React.ComponentType<{ className?: string }>;
49
50
  color?: string;
50
- items: StoryListItem[];
51
- subGroups?: GroupNode[];
51
+ items: T[];
52
+ subGroups?: GroupNode<T>[];
52
53
  /** 服务端分页:该组总数 */
53
54
  total?: number;
54
55
  /** 服务端分页:是否还有下一页 */
@@ -17,23 +17,23 @@
17
17
 
18
18
  import { useMemo } from "react";
19
19
  import type { DisplayOptions, GroupContext, GroupNode } from "./types";
20
- import type { StoryListItem } from "../types";
20
+ import type { StoryListItem } from "@/shared/story/types";
21
21
  import { applyOrder } from "./order-resolver";
22
22
  import { groupBy } from "./group-resolver";
23
23
 
24
- interface UseGroupedArgs extends GroupContext {
25
- stories: StoryListItem[];
24
+ interface UseGroupedArgs<T extends StoryListItem> extends GroupContext {
25
+ stories: T[];
26
26
  filters: DisplayOptions;
27
27
  }
28
28
 
29
- export function useGroupedStories({ stories, filters, users, labels, projects }: UseGroupedArgs): GroupNode[] {
29
+ export function useGroupedStories<T extends StoryListItem = StoryListItem>({ stories, filters, users, labels, projects }: UseGroupedArgs<T>): GroupNode<T>[] {
30
30
  return useMemo(() => {
31
31
  const ctx: GroupContext = { users, labels, projects };
32
32
  const ordered = applyOrder(stories, filters.orderBy, filters.orderDir);
33
33
  const groups = groupBy(ordered, filters.groupBy, ctx, filters.showEmptyGroups);
34
34
  if (filters.subGroupBy !== "none") {
35
35
  groups.forEach(g => {
36
- g.subGroups = groupBy(g.items, filters.subGroupBy, ctx, false);
36
+ g.subGroups = groupBy<T>(g.items, filters.subGroupBy, ctx, false);
37
37
  });
38
38
  }
39
39
  return groups;
@@ -17,7 +17,7 @@
17
17
 
18
18
  import { useCallback, useMemo } from "react";
19
19
  import { usePagedGroupsCore } from "@/hooks/use-paged-groups";
20
- import type { StoryListItem, UserBrief } from "../types";
20
+ import type { StoryListItem, UserBrief } from "@/shared/story/types";
21
21
  import type { StoryFilters } from "../story-toolbar";
22
22
  import type { FilterCondition } from "../filters";
23
23
  import { serializeFilters } from "../filters";
@@ -25,7 +25,7 @@ import { listStoriesInGroupFn, listStoryGroupsFn, listAllGroupsItemsFn } from "@
25
25
  import { resolveGroupLabel, resolveGroupIcon, resolveGroupColor } from "./group-resolver";
26
26
  import type { DisplayOptions, GroupContext, GroupKey, GroupNode } from "./types";
27
27
  import { applyStoryPatchToItem, type StoryPatch } from "./group-fields";
28
- import { PRIORITY_RANK, STORY_PRIORITIES, STORY_STATES } from "../constants";
28
+ import { PRIORITY_RANK, STORY_PRIORITIES, STORY_STATES } from "@/shared/story/constants";
29
29
  import { m } from "@/paraglide/messages.js";
30
30
 
31
31
  /** 服务端按组分页的组节点:在 GroupNode 上标记 total/hasMore/loading */
@@ -35,6 +35,8 @@ export interface PagedGroupNode extends GroupNode {
35
35
  total?: number;
36
36
  hasMore?: boolean;
37
37
  loading?: boolean;
38
+ /** S11:组首屏拉取失败显式标记(此前静默降级为空组,用户无从重试) */
39
+ error?: boolean;
38
40
  }
39
41
 
40
42
  export interface PagedStoriesArgs {
@@ -494,6 +496,8 @@ export function usePagedStoryGroups(args: PagedStoriesArgs): {
494
496
  refresh: () => void;
495
497
  /** 行内编辑乐观更新:未触发分组/排序规则时保持位置原地替换,仅触发排序时组内重插,触发分组时回退全量 refresh */
496
498
  patchStory: (storyId: string, patch: StoryPatch) => void;
499
+ /** S11:组首屏失败后的重试入口(当前实现为全量刷新;组级精确重试需 core 支持) */
500
+ retry: () => void;
497
501
  } {
498
502
  const { filters, conditions, display, users, labels, projects, enabled = true } = args;
499
503
  // iteration 为甘特专属维度:分页分组仅 list/board 消费(groupBy 运行时已被
@@ -616,13 +620,14 @@ export function usePagedStoryGroups(args: PagedStoriesArgs): {
616
620
  skip: 0,
617
621
  take: pageSize,
618
622
  },
619
- }).catch(() => ({ items: [] as StoryListItem[], total: sg.total ?? 0, hasMore: false })),
623
+ }).catch(() => ({ items: [] as StoryListItem[], total: sg.total ?? 0, hasMore: false, failed: true as const })),
620
624
  ),
621
625
  );
622
626
  subLoaded.forEach((res, i: number) => {
623
627
  subScaffolds[i].items = res.items;
624
628
  subScaffolds[i].total = res.total;
625
629
  subScaffolds[i].hasMore = res.hasMore;
630
+ subScaffolds[i].error = (res as { failed?: boolean }).failed === true;
626
631
  });
627
632
  g.subGroups = subScaffolds;
628
633
  g.totalCount = subScaffolds.reduce((sum, sg) => sum + (sg.total ?? sg.items.length), 0);
@@ -634,13 +639,14 @@ export function usePagedStoryGroups(args: PagedStoriesArgs): {
634
639
  scaffolds.map((g) =>
635
640
  listStoriesInGroupFn({
636
641
  data: { ...base, groupBy, groupKey: g.key, orderBy: display.orderBy, orderDir: display.orderDir, skip: 0, take: pageSize },
637
- }).catch(() => ({ items: [] as StoryListItem[], total: g.total ?? 0, hasMore: false })),
642
+ }).catch(() => ({ items: [] as StoryListItem[], total: g.total ?? 0, hasMore: false, failed: true as const })),
638
643
  ),
639
644
  );
640
645
  loaded.forEach((res, i: number) => {
641
646
  scaffolds[i].items = res.items;
642
647
  scaffolds[i].total = res.total;
643
648
  scaffolds[i].hasMore = res.hasMore;
649
+ scaffolds[i].error = (res as { failed?: boolean }).failed === true;
644
650
  });
645
651
  }
646
652
 
@@ -734,5 +740,6 @@ export function usePagedStoryGroups(args: PagedStoriesArgs): {
734
740
  loadMore,
735
741
  refresh: core.refresh,
736
742
  patchStory,
743
+ retry: core.refresh,
737
744
  };
738
745
  }
@@ -0,0 +1,24 @@
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
+ // Peek 面板内实体叠加层(用例/BUG 行的面板内打开)。纯 UI 状态形状,留在
19
+ // components 层:case 分支引用 server serverFns 类型与 folder-tree 组件类型
20
+ // (均 type-only,编译期擦除),不放 src/shared 以免 shared 反向依赖 server。
21
+ // bug 由实体 peek 面板按 id 自取详情。
22
+ export type StoryEntityOverlay =
23
+ | { kind: "case"; item: import("@/server/serverFns/testcase/types").TestCaseSummary; folders: import("@/components/testcase/folder-tree").FolderNodeDto[] }
24
+ | { kind: "bug"; id: string };
@@ -41,13 +41,13 @@ import type {
41
41
  } from "@/components/shared-kit/list-kit/filters/types";
42
42
  import { cn } from "@/lib/utils";
43
43
  import { PriorityIcon } from "../priority-icon";
44
- import { STORY_STATES, STATE_ICON, PRIORITY_LABEL, type StoryPriority, type StoryState } from "../constants";
44
+ import { STORY_STATES, STATE_ICON, PRIORITY_LABEL, type StoryPriority, type StoryState } from "@/shared/story/constants";
45
45
  import { StateEditor } from "../inline-editors/state-editor";
46
46
  import { PriorityEditor } from "../inline-editors/priority-editor";
47
47
  import { AssigneeEditor } from "../inline-editors/assignee-editor";
48
48
  import { LabelsEditor } from "../inline-editors/labels-editor";
49
49
  import { TitleEditor } from "../inline-editors/title-editor";
50
- import type { UserBrief } from "../types";
50
+ import type { UserBrief } from "@/shared/story/types";
51
51
 
52
52
  export { serializeFilters, deserializeFilters, OPERATOR_LABELS, generateConditionId } from "@/components/shared-kit/list-kit/filters";
53
53
  export type { FilterOperator, FilterFieldType };
@@ -20,7 +20,7 @@ import { CircleUser, Search, Check, ArrowDownUp } from "lucide-react";
20
20
  import { Input } from "@/components/ui/input";
21
21
  import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
22
22
  import { UserAvatar } from "@/components/shared-kit";
23
- import type { UserBrief } from "../types";
23
+ import type { UserBrief } from "@/shared/story/types";
24
24
  import { cn } from "@/lib/utils";
25
25
  import { InlineTrigger } from "./inline-trigger";
26
26
  import { m } from "@/paraglide/messages.js";
@@ -20,7 +20,7 @@ import { Check, Waypoints } from "lucide-react";
20
20
  import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
21
21
  import { Button, buttonVariants } from "@/components/ui/button";
22
22
  import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
23
- import { DEPENDENCY_TYPE_OPTIONS, type DependencyTypeOption } from "../constants";
23
+ import { DEPENDENCY_TYPE_OPTIONS, type DependencyTypeOption } from "@/shared/story/constants";
24
24
  import { cn } from "@/lib/utils";
25
25
  import { m } from "@/paraglide/messages.js";
26
26
 
@@ -20,8 +20,8 @@ import { GitPullRequestCreateArrow, ExternalLink, X, GitPullRequestArrow } from
20
20
  import { Button } from "@/components/ui/button";
21
21
  import { cn } from "@/lib/utils";
22
22
  import { StorySelectDialog } from "./story-select-dialog";
23
- import type { StoryState } from "../constants";
24
- import type { ActivityItem } from "../types";
23
+ import type { StoryState } from "@/shared/story/constants";
24
+ import type { ActivityItem } from "@/shared/story/types";
25
25
  import { m } from "@/paraglide/messages.js";
26
26
 
27
27
  interface ParentStoryEditorProps {
@@ -18,8 +18,8 @@
18
18
  import { useState } from "react";
19
19
  import { Check } from "lucide-react";
20
20
  import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
21
- import { PRIORITY_LABEL } from "../constants";
22
- import type { StoryPriority } from "../constants";
21
+ import { PRIORITY_LABEL } from "@/shared/story/constants";
22
+ import type { StoryPriority } from "@/shared/story/constants";
23
23
  import { PriorityIcon } from "../priority-icon";
24
24
  import { cn } from "@/lib/utils";
25
25
  import { InlineTrigger } from "./inline-trigger";
@@ -18,8 +18,8 @@
18
18
  import { useState } from "react";
19
19
  import { Check } from "lucide-react";
20
20
  import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
21
- import { STORY_STATES, STATE_LABEL, STATE_COLOR, STATE_ICON } from "../constants";
22
- import type { StoryState } from "../constants";
21
+ import { STORY_STATES, STATE_LABEL, STATE_COLOR, STATE_ICON } from "@/shared/story/constants";
22
+ import type { StoryState } from "@/shared/story/constants";
23
23
  import { cn } from "@/lib/utils";
24
24
  import { InlineTrigger } from "./inline-trigger";
25
25
  import { m } from "@/paraglide/messages.js";
@@ -37,7 +37,7 @@ import {
37
37
  DialogTitle,
38
38
  } from "@/components/ui/dialog";
39
39
  import { toast } from "@/components/ui/toast";
40
- import type { ActivityItem } from "../types";
40
+ import type { ActivityItem } from "@/shared/story/types";
41
41
  import {
42
42
  listProjectStoriesFn,
43
43
  transferStoryAsChildFn,
@@ -51,7 +51,7 @@ import {
51
51
  STORY_PRIORITIES,
52
52
  type StoryState,
53
53
  type DependencyTypeOption,
54
- } from "../constants";
54
+ } from "@/shared/story/constants";
55
55
  import { FilterCheckPopover } from "../filters/filter-check-popover";
56
56
  import { PriorityIcon } from "../priority-icon";
57
57
  import { DependencyTypeSelect } from "./dependency-type-select";
@@ -35,13 +35,13 @@ import {
35
35
  getLinkedDocsFn,
36
36
  } from "@/server/serverFns/story";
37
37
  import { listIterationsFn } from "@/server/serverFns/iteration";
38
- import type { StoryDetail, UserBrief, CommentWithReplies, ActivityItem, RelationsData } from "./types";
38
+ import type { StoryDetail, UserBrief, CommentWithReplies, ActivityItem, RelationsData } from "@/shared/story/types";
39
39
  import { applyStoryPatchToItem, type StoryPatch } from "./display/group-fields";
40
- import type { StoryState } from "./constants";
40
+ import type { StoryState } from "@/shared/story/constants";
41
41
  import { StoryDetailBody } from "./detail/story-detail-body";
42
42
  import { TestCasePeekPanel } from "@/components/testcase/peek-panel";
43
43
  import { BugPeekPanel } from "@/components/bug/peek-panel";
44
- import type { StoryEntityOverlay } from "./types";
44
+ import type { StoryEntityOverlay } from "./entity-overlay";
45
45
  import { StoryPanelHeader } from "./story-panel-header";
46
46
  import type { PeekRelationKind, PeekBreadcrumbItem } from "./story-panel-header";
47
47
  import type { PeekMode } from "@/components/shared-kit/peek/peek-mode";
@@ -252,13 +252,14 @@ export function StoryPeekPanel({
252
252
  await Promise.all([detailP, restP]);
253
253
  if (historyRef.current.length === 0) {
254
254
  setRootIdentifier(story.identifier);
255
- setRootProjectId(story.projectId);
255
+ // StoryDetail.projectId 为 string|null,PeekLocation 以 undefined 表无项目
256
+ setRootProjectId(story.projectId ?? undefined);
256
257
  } else {
257
258
  // 回填当前层 projectId:跨项目父子/依赖跳转时,面包屑各级需显示各自项目图标
258
259
  setHistory((prev) => {
259
260
  const last = prev[prev.length - 1];
260
261
  if (!last || last.projectId === story.projectId) return prev;
261
- return prev.map((h, i) => (i === prev.length - 1 ? { ...h, projectId: story.projectId } : h));
262
+ return prev.map((h, i) => (i === prev.length - 1 ? { ...h, projectId: story.projectId ?? undefined } : h));
262
263
  });
263
264
  }
264
265
  const relationsData: RelationsData = {
@@ -16,8 +16,8 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { cn } from "@/lib/utils";
19
- import { PRIORITY_ICON } from "./constants";
20
- import type { StoryPriority } from "./constants";
19
+ import { PRIORITY_ICON } from "@/shared/story/constants";
20
+ import type { StoryPriority } from "@/shared/story/constants";
21
21
 
22
22
  export const PRIORITY_COLOR: Record<StoryPriority, string> = {
23
23
  urgent: "text-red-600 dark:text-red-400",
@@ -46,7 +46,7 @@ function uploadResponse(body: Record<string, unknown>) {
46
46
  }
47
47
 
48
48
  import { AttachmentManageDialog } from "../attachment-manage-dialog";
49
- import type { StoryAttachmentItem } from "../../types";
49
+ import type { StoryAttachmentItem } from "@/shared/story/types";
50
50
 
51
51
  const ATTS: StoryAttachmentItem[] = [
52
52
  { id: "a1", fileName: "设计稿.png", fileSize: 2048, mimeType: "image/png", storageUrl: "/mock-storage/1" },
@@ -41,7 +41,7 @@ vi.mock("@/components/ui/toast", () => ({
41
41
  ;
42
42
 
43
43
  import { DesignSelectDialog } from "../design-select-dialog";
44
- import type { DesignBrief } from "../../types";
44
+ import type { DesignBrief } from "@/shared/story/types";
45
45
 
46
46
  const design = (id: string, title: string, icon = "file"): DesignBrief => ({ id, title, icon });
47
47
 
@@ -43,7 +43,7 @@ vi.mock("@/components/ui/toast", () => ({
43
43
  ;
44
44
 
45
45
  import { KnowledgeSelectDialog } from "../knowledge-select-dialog";
46
- import type { DocBrief } from "../../types";
46
+ import type { DocBrief } from "@/shared/story/types";
47
47
 
48
48
  const doc = (id: string, title: string, parentId: string | null = null): DocBrief => ({
49
49
  id,
@@ -41,7 +41,7 @@ vi.mock("@/components/ui/toast", () => ({
41
41
  ;
42
42
 
43
43
  import { LinkManageDialog } from "../link-manage-dialog";
44
- import type { StoryLinkItem } from "../../types";
44
+ import type { StoryLinkItem } from "@/shared/story/types";
45
45
 
46
46
  const LINKS: StoryLinkItem[] = [
47
47
  { id: "l1", url: "https://a.com", title: "站点A", description: null },
@@ -28,7 +28,7 @@ import {
28
28
  import { Textarea } from "@/components/ui/textarea";
29
29
  import { getFileTypeIcon } from "./format";
30
30
  import { FilePreview } from "./file-preview";
31
- import type { StoryAttachmentItem } from "../types";
31
+ import type { StoryAttachmentItem } from "@/shared/story/types";
32
32
  import { m } from "@/paraglide/messages.js";
33
33
  import { toastError } from "@/lib/toast-error";
34
34
 
@@ -49,7 +49,7 @@ export interface AttachmentManageDialogProps {
49
49
  data: StoryAttachmentItem[];
50
50
  onUpdate: (attachments: StoryAttachmentItem[]) => void;
51
51
  /** 上传附件产生的活动,供时间线即时追加 */
52
- onActivity?: (activity: import("../types").ActivityItem) => void;
52
+ onActivity?: (activity: import("@/shared/story/types").ActivityItem) => void;
53
53
  /** 编辑模式:预填充现有附件,隐藏继续上传按钮和上传区 */
54
54
  editItem?: StoryAttachmentItem | null;
55
55
  }
@@ -242,7 +242,7 @@ export function AttachmentManageDialog({
242
242
  if (staged.length === 0 || uploading) return;
243
243
  setUploading(true);
244
244
  const desc = description.trim();
245
- const added: Array<StoryAttachmentItem & { activity?: import("../types").ActivityItem }> = [];
245
+ const added: Array<StoryAttachmentItem & { activity?: import("@/shared/story/types").ActivityItem }> = [];
246
246
  for (const item of staged) {
247
247
  // 跳过重复文件
248
248
  if (duplicateIndexes.has(staged.indexOf(item))) continue;
@@ -263,7 +263,7 @@ export function AttachmentManageDialog({
263
263
  }
264
264
  const json = await res.json() as Record<string, unknown>;
265
265
  if ((json.duplicated as boolean | undefined) === true) continue;
266
- added.push(json as unknown as StoryAttachmentItem & { activity?: import("../types").ActivityItem });
266
+ added.push(json as unknown as StoryAttachmentItem & { activity?: import("@/shared/story/types").ActivityItem });
267
267
  } catch (err) {
268
268
  toastError(err, m.story_attachmentDialog_removeFailed());
269
269
  }
@@ -41,7 +41,7 @@ import {
41
41
  } from "@/server/serverFns/story";
42
42
  import { LucideIconByName } from "@/components/shared-kit/icons/lucide-icon-picker/lucide-icon-by-name";
43
43
  import { useLinkedSelection } from "./use-linked-selection";
44
- import type { DesignBrief } from "../types";
44
+ import type { DesignBrief } from "@/shared/story/types";
45
45
  import { m } from "@/paraglide/messages.js";
46
46
  import { toastError } from "@/lib/toast-error";
47
47
 
@@ -56,7 +56,7 @@ export interface DesignSelectDialogProps {
56
56
  linkedDesigns: DesignBrief[];
57
57
  onUpdate: (designs: DesignBrief[]) => void;
58
58
  /** 关联/解联产生的活动,供时间线即时追加 */
59
- onActivity?: (activity: import("../types").ActivityItem) => void;
59
+ onActivity?: (activity: import("@/shared/story/types").ActivityItem) => void;
60
60
  }
61
61
 
62
62
  function dialogTitle(mode: DesignSelectMode): string {
@@ -41,7 +41,7 @@ import { GENERAL_GROUPS, type GeneralGroup } from "@/server/serverFns/story/kb-g
41
41
  import { generalGroupLabel } from "./general-groups";
42
42
  import { useLinkedSelection } from "./use-linked-selection";
43
43
  import { KbFilterPopover, type KbFilter } from "@/components/knowledge/kb-filter-popover";
44
- import type { DocBrief } from "../types";
44
+ import type { DocBrief } from "@/shared/story/types";
45
45
  import { m } from "@/paraglide/messages.js";
46
46
  import { toastError } from "@/lib/toast-error";
47
47
 
@@ -65,7 +65,7 @@ export interface KnowledgeSelectDialogProps {
65
65
  linkedDocs: DocBrief[];
66
66
  onUpdate: (docs: DocBrief[]) => void;
67
67
  /** 关联知识库文档产生的活动,供时间线即时追加 */
68
- onActivity?: (activity: import("../types").ActivityItem) => void;
68
+ onActivity?: (activity: import("@/shared/story/types").ActivityItem) => void;
69
69
  }
70
70
 
71
71
  export function KnowledgeSelectDialog({
@@ -28,7 +28,7 @@ import {
28
28
  DialogTitle,
29
29
  } from "@/components/ui/dialog";
30
30
  import { addLinkFn, updateLinkFn } from "@/server/serverFns/story";
31
- import type { StoryLinkItem } from "../types";
31
+ import type { StoryLinkItem } from "@/shared/story/types";
32
32
  import { m } from "@/paraglide/messages.js";
33
33
  import { toastError } from "@/lib/toast-error";
34
34
 
@@ -39,7 +39,7 @@ export interface LinkManageDialogProps {
39
39
  data: StoryLinkItem[];
40
40
  onUpdate: (links: StoryLinkItem[]) => void;
41
41
  /** 添加链接产生的活动,供时间线即时追加 */
42
- onActivity?: (activity: import("../types").ActivityItem) => void;
42
+ onActivity?: (activity: import("@/shared/story/types").ActivityItem) => void;
43
43
  /** 非空时进入编辑态(由合并面板「编辑」触发) */
44
44
  initialEdit?: StoryLinkItem | null;
45
45
  }
@@ -39,7 +39,7 @@ import { PriorityEditor, StateEditor, AssigneeEditor, DateEditor, LabelsEditor,
39
39
  import { NameConfirmDialog } from "@/components/shared-kit/dialogs/name-confirm-dialog";
40
40
  import { cn } from "@/lib/utils";
41
41
  import { LucideIconByName } from "@/components/shared-kit/icons/lucide-icon-picker/lucide-icon-by-name";
42
- import { dependencyTypeOption } from "../constants";
42
+ import { dependencyTypeOption } from "@/shared/story/constants";
43
43
  import type { DisplayProperty } from "../display/types";
44
44
  import type { StoryPatch } from "../display/group-fields";
45
45
  import type {
@@ -47,8 +47,8 @@ import type {
47
47
  UserBrief,
48
48
  DependencyEdgeType,
49
49
  DependencyGroup,
50
- } from "../types";
51
- import type { DependencyTypeOption } from "../constants";
50
+ } from "@/shared/story/types";
51
+ import type { DependencyTypeOption } from "@/shared/story/constants";
52
52
  import { m } from "@/paraglide/messages.js";
53
53
  import { toastError } from "@/lib/toast-error";
54
54
 
@@ -20,7 +20,7 @@ import { flexRender, useTable, type SortingState } from "@tanstack/react-table";
20
20
  import { useVirtualizer } from "@tanstack/react-virtual";
21
21
  import { ArrowDown, ArrowUp, ChevronDown } from "lucide-react";
22
22
  import { createStoryColumns, storyTableFeatures } from "./columns";
23
- import type { StoryListItem } from "./types";
23
+ import type { StoryListItem } from "@/shared/story/types";
24
24
  import { ALL_DISPLAY_PROPERTIES } from "./display/types";
25
25
  import type { DisplayProperty, OrderKey } from "./display/types";
26
26
  import { InfiniteScrollSentinel } from "@/components/infinite-scroll-sentinel";
@@ -36,7 +36,7 @@ import {
36
36
  buildDefaultView, DEFAULT_VIEW_ID, type SavedView,
37
37
  } from "./views/view-types";
38
38
  import { isStoryView, type StoryView } from "./views/view-switcher";
39
- import type { UserBrief, StoryListItem } from "./types";
39
+ import type { UserBrief, StoryListItem } from "@/shared/story/types";
40
40
  import type { DisplayOptions } from "./display/types";
41
41
  import { applyStoryPatchToItem, type StoryPatch } from "./display/group-fields";
42
42
  import { useDisplayOptions } from "./display/use-display-options";
@@ -39,7 +39,7 @@ import type { DisplayOptions } from "./display/types";
39
39
  import { StoryFilterToggle, StoryFilterRow, AppliedFilters, type FilterCondition } from "./filters";
40
40
  import { LucideIconByName } from "@/components/shared-kit/icons/lucide-icon-picker/lucide-icon-by-name";
41
41
  import { CreateProjectDialog } from "@/components/project/create-project-dialog";
42
- import type { UserBrief } from "./types";
42
+ import type { UserBrief } from "@/shared/story/types";
43
43
  import { m } from "@/paraglide/messages.js";
44
44
  import { useToolbarSearch } from "@/hooks/use-toolbar-search";
45
45
  import { cn } from "@/lib/utils";
@@ -41,11 +41,12 @@ interface TransferStoryPopoverProps {
41
41
  storyIds?: string[];
42
42
  currentProjectId?: string | null;
43
43
  projects: { id: string; name: string; displayId?: string | null; icon: string }[];
44
- onTransferred: (updatedStories?: Array<{ id: string; identifier: string; projectId: string; parentId: string | null }>) => void;
44
+ onTransferred: (updatedStories?: Array<{ id: string; identifier: string; projectId: string | null; parentId: string | null }>) => void;
45
45
  trigger?: React.ReactNode;
46
46
  }
47
47
 
48
- type TransferredStory = { id: string; identifier: string; projectId: string; parentId: string | null };
48
+ // projectId 诚实可空(公共行口径);当前消费方仅清选择+刷新,不读载荷
49
+ type TransferredStory = { id: string; identifier: string; projectId: string | null; parentId: string | null };
49
50
 
50
51
  export function TransferStoryPopover({
51
52
  storyId,
@@ -22,7 +22,7 @@ import { CalendarView } from "../calendar-view";
22
22
  import { resolveDragBlockedToast } from "../calendar/drag-blocked";
23
23
  import { formatDateLocal } from "@/lib/datetime";
24
24
  import { m } from "@/paraglide/messages.js";
25
- import type { StoryListItem } from "../../types";
25
+ import type { StoryListItem } from "@/shared/story/types";
26
26
 
27
27
  function story(
28
28
  id: string,
@@ -20,7 +20,7 @@
20
20
  // 原分区」而不发 patch,表现为拖到「已取消-高」却落进「已取消-低」。
21
21
  import { describe, expect, it } from "vitest";
22
22
  import { resolveDropSubKey, resolveSubKeyForDrop } from "../kanban-view";
23
- import type { StoryListItem } from "../../types";
23
+ import type { StoryListItem } from "@/shared/story/types";
24
24
 
25
25
  const card = (id: string) => ({ id }) as StoryListItem;
26
26
 
@@ -35,9 +35,9 @@ import { render, screen, waitFor } from "@testing-library/react";
35
35
  import userEvent from "@testing-library/user-event";
36
36
  import { TooltipProvider } from "@/components/ui/tooltip";
37
37
  import { KanbanView } from "../kanban-view";
38
- import { PRIORITY_LABEL } from "../../constants";
38
+ import { PRIORITY_LABEL } from "@/shared/story/constants";
39
39
  import type { DisplayOptions, GroupNode } from "../../display/types";
40
- import type { StoryListItem } from "../../types";
40
+ import type { StoryListItem } from "@/shared/story/types";
41
41
 
42
42
  vi.mock("@tanstack/react-start", () => ({
43
43
  useServerFn: (fn: unknown) => fn,
@@ -33,7 +33,7 @@ import { act, render } from "@testing-library/react";
33
33
  import { TooltipProvider } from "@/components/ui/tooltip";
34
34
  import { KanbanView } from "../kanban-view";
35
35
  import type { DisplayOptions, GroupNode } from "../../display/types";
36
- import type { StoryListItem } from "../../types";
36
+ import type { StoryListItem } from "@/shared/story/types";
37
37
 
38
38
  vi.mock("@tanstack/react-start", () => ({
39
39
  useServerFn: (fn: unknown) => fn,
@@ -60,7 +60,7 @@ vi.mock("@/server/serverFns/iteration", () => ({
60
60
  import { TimelineView } from "../timeline-view";
61
61
  import { formatDateLocal } from "@/lib/datetime";
62
62
  import type { GroupKey } from "../../display/types";
63
- import type { StoryListItem } from "../../types";
63
+ import type { StoryListItem } from "@/shared/story/types";
64
64
 
65
65
  function story(
66
66
  id: string,
@@ -22,7 +22,7 @@ import {
22
22
  fromGanttRangeToStoryDates,
23
23
  } from "../mappers";
24
24
  import { parseDate } from "@/lib/datetime";
25
- import type { StoryListItem } from "../../../types";
25
+ import type { StoryListItem } from "@/shared/story/types";
26
26
 
27
27
  /** 需求样本工厂:固定 id/identifier/name/state,其余按需覆盖 */
28
28
  const mkStory = (over: Partial<StoryListItem> = {}): StoryListItem => ({
@@ -37,7 +37,7 @@
37
37
  import { addDays, startOfDay } from "date-fns";
38
38
  import { parseDate } from "@/lib/datetime";
39
39
  import type { CalendarEvent } from "@/components/reui/event-calendar/event-calendar-types";
40
- import type { StoryListItem } from "../../types";
40
+ import type { StoryListItem } from "@/shared/story/types";
41
41
  // 甘特导出单一事实源(禁止复制定义——复制即两份漂移)
42
42
  import { STORY_STATE_GANTT_COLOR } from "../timeline/mappers";
43
43
 
@@ -78,7 +78,7 @@ import type {
78
78
  EventCalendarViewSettings,
79
79
  } from "@/components/reui/event-calendar/event-calendar-types";
80
80
  import type { WeekStartsOn } from "@/components/reui/event-calendar/event-calendar-lib";
81
- import type { StoryListItem } from "../types";
81
+ import type { StoryListItem } from "@/shared/story/types";
82
82
  import { applyOrder } from "../display/order-resolver";
83
83
  import type { OrderKey } from "../display/types";
84
84
  import {
@@ -38,7 +38,7 @@ import { StoryFilterRow } from "../filters";
38
38
  import { createDefaultCondition, type FilterCondition } from "../filters/field-configs";
39
39
  import { VIEW_ICONS, type SavedView, type ViewProjectInfo } from "./view-types";
40
40
  import { ViewIcon } from "@/components/shared-kit/views/view-icon";
41
- import type { UserBrief } from "../types";
41
+ import type { UserBrief } from "@/shared/story/types";
42
42
  import { m } from "@/paraglide/messages.js";
43
43
 
44
44
  export interface CreateViewDialogPayload {