@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.
- package/package.json +3 -3
- package/src/components/bug/__tests__/board-subgroups.test.tsx +1 -1
- package/src/components/bug/__tests__/board-view.test.tsx +1 -1
- package/src/components/bug/__tests__/comment-reactions.test.tsx +1 -1
- package/src/components/bug/__tests__/create-bug-dialog.test.tsx +2 -2
- package/src/components/bug/__tests__/filters-compat.test.tsx +1 -1
- package/src/components/bug/__tests__/fix-request-race.test.tsx +1 -1
- package/src/components/bug/__tests__/peek-modes.test.tsx +1 -1
- package/src/components/bug/__tests__/use-paged-bug-groups.test.tsx +1 -1
- package/src/components/bug/__tests__/view-type.test.tsx +1 -1
- package/src/components/bug/bug-list-view.tsx +2 -2
- package/src/components/bug/bug-toolbar.tsx +1 -1
- package/src/components/bug/create-bug-dialog.tsx +3 -3
- package/src/components/bug/detail/__tests__/activity-timeline.test.tsx +1 -1
- package/src/components/bug/detail/__tests__/bug-detail-collab.test.tsx +1 -1
- package/src/components/bug/detail/__tests__/repro-report-card.test.tsx +1 -1
- package/src/components/bug/detail/activity-tabs.tsx +34 -3
- package/src/components/bug/detail/activity-timeline.tsx +1 -1
- package/src/components/bug/detail/bug-detail-body.tsx +3 -3
- package/src/components/bug/detail/comment-input.tsx +1 -1
- package/src/components/bug/detail/comment-item.tsx +1 -1
- package/src/components/bug/detail/comment-reactions.tsx +1 -1
- package/src/components/bug/detail/comment-thread.tsx +1 -1
- package/src/components/bug/detail/props-section.tsx +2 -2
- package/src/components/bug/detail/repro-report-card.tsx +1 -1
- package/src/components/bug/detail/reproduce-steps-view.tsx +1 -1
- package/src/components/bug/display/use-paged-bug-groups.ts +2 -2
- package/src/components/bug/filters/field-configs.tsx +1 -1
- package/src/components/bug/inline-editors/assignee-editor.tsx +1 -1
- package/src/components/bug/peek-panel.tsx +2 -2
- package/src/components/bug/reproduce-steps-editor.tsx +1 -1
- package/src/components/bug/story-bugs-panel.tsx +10 -6
- package/src/components/bug/views/board-view.tsx +2 -2
- package/src/components/bug/views/bug-list/batch-toolbar.tsx +1 -1
- package/src/components/bug/views/bug-list/group.tsx +1 -1
- package/src/components/bug/views/bug-list/index.tsx +1 -1
- package/src/components/bug/views/bug-list/inline-bug-creator.tsx +1 -1
- package/src/components/bug/views/bug-list/row.tsx +2 -2
- package/src/components/bug/views/create-view-dialog.tsx +1 -1
- package/src/components/design/editor/versions/hooks/use-design-versions.ts +11 -4
- package/src/components/design/editor/versions/page-version-panel.tsx +30 -11
- package/src/components/harness/code/workspace-context.tsx +5 -1
- package/src/components/harness/code/workspace-picker.tsx +19 -6
- package/src/components/harness/composer/harness-composer.tsx +25 -3
- package/src/components/harness/composer/mention/mention-resolvers.ts +2 -0
- package/src/components/harness/composer/mention/mention-suggestion-menu.tsx +6 -3
- package/src/components/harness/composer/mention/use-mention-sources.ts +1 -1
- package/src/components/iteration/iteration-progress-bar.tsx +2 -2
- package/src/components/knowledge/public/legal-compliance-editor.tsx +1 -1
- package/src/components/layout/sidebar-03/nav-knowledge.tsx +1 -1
- package/src/components/layout/sidebar-03/nav-workspace.tsx +1 -1
- package/src/components/project/invite-member-dialog.tsx +2 -2
- package/src/components/project/project-member-manager.tsx +0 -3
- package/src/components/shared-kit/list-kit/kanban/__tests__/instance-key.test.ts +1 -1
- package/src/components/story/__tests__/constants.test.ts +1 -1
- package/src/components/story/__tests__/dependency-type-badge.test.ts +1 -1
- package/src/components/story/__tests__/peek-panel-patch-sync.test.tsx +1 -1
- package/src/components/story/__tests__/story-list-view-peek-sync.test.tsx +1 -1
- package/src/components/story/ai/story-ai-panel.tsx +1 -1
- package/src/components/story/ai/story-ai-preview-list.tsx +2 -2
- package/src/components/story/ai/use-story-ai-model.ts +17 -4
- package/src/components/story/columns.tsx +2 -2
- package/src/components/story/create-story-dialog.tsx +4 -4
- package/src/components/story/detail/__tests__/activity-timeline.test.tsx +1 -1
- package/src/components/story/detail/__tests__/associated-attachments-panel.test.tsx +1 -1
- package/src/components/story/detail/__tests__/story-collab.test.tsx +1 -1
- package/src/components/story/detail/activity-tabs.tsx +1 -1
- package/src/components/story/detail/activity-timeline.tsx +36 -17
- package/src/components/story/detail/comment-input.tsx +1 -1
- package/src/components/story/detail/comment-item.tsx +1 -1
- package/src/components/story/detail/comment-thread.tsx +1 -1
- package/src/components/story/detail/reaction-bar.tsx +1 -1
- package/src/components/story/detail/story-detail-body.tsx +4 -4
- package/src/components/story/detail/story-detail-toolbar/__tests__/attachment-cache.test.ts +83 -0
- package/src/components/story/detail/story-detail-toolbar/associated-attachments-panel.tsx +50 -9
- package/src/components/story/detail/story-detail-toolbar/children.tsx +3 -3
- package/src/components/story/detail/story-detail-toolbar/dependency-panel.tsx +9 -8
- package/src/components/story/detail/story-detail-toolbar/index.tsx +8 -8
- package/src/components/story/detail/story-detail-toolbar/related-test-cases.tsx +2 -2
- package/src/components/story/detail/story-properties.tsx +2 -2
- package/src/components/story/display/__tests__/flatten-story-groups.test.ts +1 -1
- package/src/components/story/display/__tests__/group-fields.test.ts +1 -1
- package/src/components/story/display/__tests__/group-resolver.test.ts +2 -2
- package/src/components/story/display/__tests__/order-resolver.test.ts +1 -1
- package/src/components/story/display/__tests__/use-grouped-stories.test.ts +1 -1
- package/src/components/story/display/__tests__/use-paged-story-groups.test.ts +1 -1
- package/src/components/story/display/flatten-story-groups.ts +1 -1
- package/src/components/story/display/group-fields.ts +2 -2
- package/src/components/story/display/group-resolver.tsx +4 -4
- package/src/components/story/display/order-resolver.ts +3 -3
- package/src/components/story/display/types.ts +5 -4
- package/src/components/story/display/use-grouped-stories.ts +5 -5
- package/src/components/story/display/use-paged-story-groups.ts +11 -4
- package/src/components/story/entity-overlay.ts +24 -0
- package/src/components/story/filters/field-configs.tsx +2 -2
- package/src/components/story/inline-editors/assignee-editor.tsx +1 -1
- package/src/components/story/inline-editors/dependency-type-select.tsx +1 -1
- package/src/components/story/inline-editors/parent-story-editor.tsx +2 -2
- package/src/components/story/inline-editors/priority-editor.tsx +2 -2
- package/src/components/story/inline-editors/state-editor.tsx +2 -2
- package/src/components/story/inline-editors/story-select-dialog.tsx +2 -2
- package/src/components/story/peek-panel.tsx +6 -5
- package/src/components/story/priority-icon.tsx +2 -2
- package/src/components/story/relations/__tests__/attachment-manage-dialog.test.tsx +1 -1
- package/src/components/story/relations/__tests__/design-select-dialog.test.tsx +1 -1
- package/src/components/story/relations/__tests__/knowledge-select-dialog.test.tsx +1 -1
- package/src/components/story/relations/__tests__/link-manage-dialog.test.tsx +1 -1
- package/src/components/story/relations/attachment-manage-dialog.tsx +4 -4
- package/src/components/story/relations/design-select-dialog.tsx +2 -2
- package/src/components/story/relations/knowledge-select-dialog.tsx +2 -2
- package/src/components/story/relations/link-manage-dialog.tsx +2 -2
- package/src/components/story/relations/story-ref-row.tsx +3 -3
- package/src/components/story/story-list-table.tsx +1 -1
- package/src/components/story/story-list-view.tsx +1 -1
- package/src/components/story/story-toolbar.tsx +1 -1
- package/src/components/story/transfer-story-popover.tsx +3 -2
- package/src/components/story/views/__tests__/calendar-view.test.tsx +1 -1
- package/src/components/story/views/__tests__/kanban-drop-subgroup.test.ts +1 -1
- package/src/components/story/views/__tests__/kanban-peek-sync.test.tsx +2 -2
- package/src/components/story/views/__tests__/kanban-view-membership-sync.test.tsx +1 -1
- package/src/components/story/views/__tests__/timeline-view.test.tsx +1 -1
- package/src/components/story/views/calendar/__tests__/mappers.test.ts +1 -1
- package/src/components/story/views/calendar/mappers.ts +1 -1
- package/src/components/story/views/calendar-view.tsx +1 -1
- package/src/components/story/views/create-view-dialog.tsx +1 -1
- package/src/components/story/views/kanban-view.tsx +2 -2
- package/src/components/story/views/story-list/batch-preview-dialog.tsx +2 -2
- package/src/components/story/views/story-list/batch-toolbar.tsx +3 -3
- package/src/components/story/views/story-list/group.tsx +18 -5
- package/src/components/story/views/story-list/index.tsx +4 -2
- package/src/components/story/views/story-list/inline-story-creator.tsx +2 -2
- package/src/components/story/views/story-list/row.tsx +2 -2
- package/src/components/story/views/story-list/use-flat-rows.ts +1 -1
- package/src/components/story/views/timeline/__tests__/mappers.test.ts +2 -2
- package/src/components/story/views/timeline/mappers.ts +2 -2
- package/src/components/story/views/timeline/use-date-commit.ts +1 -1
- package/src/components/story/views/timeline-view.tsx +2 -2
- package/src/components/testcase/__tests__/case-row.test.tsx +1 -1
- package/src/components/testcase/__tests__/create-dialog-scope.test.tsx +1 -1
- package/src/components/testcase/__tests__/display-options.test.tsx +1 -1
- package/src/components/testcase/__tests__/export-entry.test.tsx +1 -1
- package/src/components/testcase/__tests__/list-view.test.tsx +1 -1
- package/src/components/testcase/__tests__/step-editor.test.tsx +4 -2
- package/src/components/testcase/__tests__/toolbar.test.tsx +1 -1
- package/src/components/testcase/create-testcase-dialog.tsx +6 -5
- package/src/components/testcase/detail/case-detail-body.tsx +1 -1
- package/src/components/testcase/detail/properties.tsx +1 -1
- package/src/components/testcase/display/display-dropdown.tsx +2 -2
- package/src/components/testcase/display/use-testcase-display-options.ts +1 -1
- package/src/components/testcase/filters/field-configs.tsx +1 -1
- package/src/components/testcase/generation/draft-card.tsx +2 -2
- package/src/components/testcase/inline-editors/assignee-editor.tsx +1 -1
- package/src/components/testcase/list/case-row.tsx +1 -1
- package/src/components/testcase/list/grouped-list.tsx +1 -1
- package/src/components/testcase/list-view.tsx +2 -2
- package/src/components/testcase/runs/convert-bug-button.tsx +2 -2
- package/src/components/testcase/step-editor.tsx +13 -2
- package/src/components/testcase/testcase-toolbar.tsx +2 -2
- package/src/components/testcase/views/batch-toolbar.tsx +1 -1
- package/src/components/testcase/views/board-view.tsx +2 -2
- package/src/lib/changelog/sdk-versions.ts +2 -2
- package/src/lib/collections/knowledge/knowledge-bases-collection.ts +2 -1
- package/src/lib/collections/query-keys.ts +18 -0
- package/src/lib/collections/reference/users-brief-collection.ts +2 -1
- package/src/lib/collections/reference/workspaces-collection.ts +2 -1
- package/src/lib/story/__tests__/activity-grouper.test.ts +1 -1
- package/src/lib/story/activity-grouper.ts +1 -1
- package/src/paraglide/messages/_index.d.ts +2 -0
- package/src/paraglide/messages/_index.js +88269 -5642
- package/src/paraglide/messages/en.js +28255 -0
- package/src/paraglide/messages/story_group_loadfailed1.d.ts +17 -0
- package/src/paraglide/messages/story_group_loadfailed1.js +30 -0
- package/src/paraglide/messages/story_group_retry.d.ts +16 -0
- package/src/paraglide/messages/story_group_retry.js +29 -0
- package/src/paraglide/messages/zh.js +28253 -0
- package/src/routes/_nav/bugs/$bugId/route.lazy.tsx +2 -2
- package/src/routes/_nav/projects/$projectId/iterations/$iterationId/route.lazy.tsx +1 -1
- package/src/routes/_nav/route.tsx +1 -2
- package/src/routes/_nav/stories/$storyId/route.lazy.tsx +2 -2
- package/src/routes/_nav/stories/$storyId/route.tsx +1 -1
- package/src/routes/api/design/prototype/__tests__/route.test.ts +4 -1
- package/src/server/__tests__/task-executor.test.ts +7 -0
- package/src/server/ai-gateway/__tests__/ai-output-guard.test.ts +4 -4
- package/src/server/ai-gateway/__tests__/tools-authorization.test.ts +25 -0
- package/src/server/ai-gateway/tools/server.ts +24 -15
- package/src/server/knowledge/reindex-guard.ts +35 -0
- package/src/server/lib/__tests__/cron-auth.test.ts +1 -1
- package/src/server/serverFns/__tests__/legal-code-canonical.test.ts +169 -0
- package/src/server/serverFns/__tests__/story-tree.test.ts +0 -1
- package/src/server/serverFns/__tests__/story-types.test.ts +2 -1
- package/src/server/serverFns/__tests__/update-bug-guard.test.ts +1 -1
- package/src/server/serverFns/bug/__tests__/bug-comments.test.ts +95 -44
- package/src/server/serverFns/bug/__tests__/bug-crud.test.ts +46 -18
- package/src/server/serverFns/bug/__tests__/bug-groups.test.ts +1 -1
- package/src/server/serverFns/bug/bug-activities.ts +2 -2
- package/src/server/serverFns/bug/bug-comments.ts +44 -19
- package/src/server/serverFns/bug/bug-crud/detail-select.ts +1 -1
- package/src/server/serverFns/bug/bug-crud/detail.ts +2 -2
- package/src/server/serverFns/bug/bug-crud.ts +142 -110
- package/src/server/serverFns/bug/bug-group-query.ts +1 -1
- package/src/server/serverFns/bug/bug-groups.ts +2 -2
- package/src/server/serverFns/bug/bug-story-utils.ts +1 -1
- package/src/server/serverFns/chat/conversations.ts +27 -13
- package/src/server/serverFns/harness/github-workspace.ts +32 -25
- package/src/server/serverFns/harness/search-mention-candidates.ts +3 -1
- package/src/server/serverFns/iteration/iteration-crud.ts +1 -1
- package/src/server/serverFns/knowledge/public/legal/create.ts +3 -0
- package/src/server/serverFns/knowledge/public/legal/update.ts +8 -8
- package/src/server/serverFns/knowledge-index.ts +12 -5
- package/src/server/serverFns/project.ts +5 -11
- package/src/server/serverFns/story/__tests__/story-dependencies.test.ts +15 -4
- package/src/server/serverFns/story/__tests__/story-transfer.test.ts +20 -0
- package/src/server/serverFns/story/link-preview.ts +3 -2
- package/src/server/serverFns/story/story-children.ts +1 -1
- package/src/server/serverFns/story/story-comments.ts +1 -1
- package/src/server/serverFns/story/story-crud/bulk.ts +1 -1
- package/src/server/serverFns/story/story-crud.ts +1 -1
- package/src/server/serverFns/story/story-dependencies.ts +61 -69
- package/src/server/serverFns/story/story-groups.ts +1 -1
- package/src/server/serverFns/story/story-transfer.ts +8 -20
- package/src/server/serverFns/testcase/__tests__/automation.test.ts +21 -0
- package/src/server/serverFns/testcase/__tests__/testcase-groups.test.ts +1 -1
- package/src/server/serverFns/testcase/automation.ts +24 -1
- package/src/server/serverFns/testcase/testcase-board.ts +1 -1
- package/src/server/serverFns/testcase/testcase-crud.ts +1 -1
- package/src/server/serverFns/testcase/testcase-display-options.ts +1 -1
- package/src/server/serverFns/testcase/testcase-filter-views.ts +1 -1
- package/src/server/serverFns/testcase/types.ts +1 -1
- package/src/server/story/types.ts +7 -3
- package/src/shared/bug/__tests__/constants.test.ts +1 -1
- package/src/{components → shared}/bug/types.ts +4 -3
- package/src/{components → shared}/story/constants.ts +1 -1
- package/src/{components → shared}/story/types.ts +1 -7
- package/src/types/project.ts +1 -2
- /package/src/{components/testcase/display → shared/testcase}/field-configs.ts +0 -0
|
@@ -59,13 +59,13 @@ import { toast } from "@/components/ui/toast";
|
|
|
59
59
|
import { toastError } from "@/lib/toast-error";
|
|
60
60
|
import { m } from "@/paraglide/messages.js";
|
|
61
61
|
import { updateStoryFn, reorderStoriesFn } from "@/server/serverFns/story";
|
|
62
|
-
import type { StoryListItem, UserBrief } from "
|
|
62
|
+
import type { StoryListItem, UserBrief } from "@/shared/story/types";
|
|
63
63
|
import { GROUP_FIELD, toGroupFieldPatch, type StoryPatch } from "../display/group-fields";
|
|
64
64
|
import { buildGroupMeta, groupUniverse, resolveColumnTint } from "../display/group-resolver";
|
|
65
65
|
import { COLLAPSED_SUBGROUPS_KEY } from "../display/use-collapsed-subgroups";
|
|
66
66
|
import { useFitCount } from "../display/use-fit-count";
|
|
67
67
|
import { DateEditor, PriorityEditor, StateEditor } from "../inline-editors";
|
|
68
|
-
import { PRIORITY_LABEL, STATE_LABEL, STATE_ICON, STATE_COLOR } from "
|
|
68
|
+
import { PRIORITY_LABEL, STATE_LABEL, STATE_ICON, STATE_COLOR } from "@/shared/story/constants";
|
|
69
69
|
import { PriorityIcon } from "../priority-icon";
|
|
70
70
|
import type {
|
|
71
71
|
DisplayOptions,
|
|
@@ -40,10 +40,10 @@ import {
|
|
|
40
40
|
STORY_STATES,
|
|
41
41
|
STORY_PRIORITIES,
|
|
42
42
|
type StoryState,
|
|
43
|
-
} from "
|
|
43
|
+
} from "@/shared/story/constants";
|
|
44
44
|
import { FilterCheckPopover } from "../../filters/filter-check-popover";
|
|
45
45
|
import { PriorityIcon } from "../../priority-icon";
|
|
46
|
-
import type { StoryListItem } from "
|
|
46
|
+
import type { StoryListItem } from "@/shared/story/types";
|
|
47
47
|
import { m } from "@/paraglide/messages.js";
|
|
48
48
|
|
|
49
49
|
type BatchPreviewMode = "archive" | "delete";
|
|
@@ -28,9 +28,9 @@ import {
|
|
|
28
28
|
DateEditor,
|
|
29
29
|
LabelsEditor,
|
|
30
30
|
} from "../../inline-editors";
|
|
31
|
-
import type { UserBrief } from "
|
|
31
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
32
32
|
import type { StoryPatch } from "../../display/group-fields";
|
|
33
|
-
import type { StoryListItem } from "
|
|
33
|
+
import type { StoryListItem } from "@/shared/story/types";
|
|
34
34
|
import { BatchPreviewDialog } from "./batch-preview-dialog";
|
|
35
35
|
import { TransferStoryPopover } from "../../transfer-story-popover";
|
|
36
36
|
import { m } from "@/paraglide/messages.js";
|
|
@@ -57,7 +57,7 @@ export interface BatchToolbarProps {
|
|
|
57
57
|
onRemoveRelations?: (storyIds: string[]) => void;
|
|
58
58
|
onBulkUpdate: (patch: StoryPatch) => void;
|
|
59
59
|
onClearSelection: () => void;
|
|
60
|
-
onTransfer: (updatedStories?: Array<{ id: string; identifier: string; projectId: string; parentId: string | null }>) => void;
|
|
60
|
+
onTransfer: (updatedStories?: Array<{ id: string; identifier: string; projectId: string | null; parentId: string | null }>) => void;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export function BatchToolbar({
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
18
|
import { memo, useEffect, useState } from "react";
|
|
19
|
-
import { ChevronDown, ChevronRight, Plus, Loader2, ChevronsDown } from "lucide-react";
|
|
19
|
+
import { ChevronDown, ChevronRight, Plus, Loader2, ChevronsDown, AlertCircle } from "lucide-react";
|
|
20
20
|
import { Button } from "@/components/ui/button";
|
|
21
21
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
22
|
-
import type { UserBrief } from "
|
|
23
|
-
import { STORY_STATES, STORY_PRIORITIES, type StoryState, type StoryPriority } from "
|
|
22
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
23
|
+
import { STORY_STATES, STORY_PRIORITIES, type StoryState, type StoryPriority } from "@/shared/story/constants";
|
|
24
24
|
import type { GroupNode, GroupKey } from "../../display/types";
|
|
25
25
|
import { cn } from "@/lib/utils";
|
|
26
26
|
import { InlineStoryCreator } from "./inline-story-creator";
|
|
@@ -35,7 +35,9 @@ const GROUP_DIMENSION_LABEL: Record<Extract<GroupKey, "assignee" | "createdBy">,
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
interface VirtualGroupHeaderProps {
|
|
38
|
-
node: GroupNode;
|
|
38
|
+
node: GroupNode & { error?: boolean };
|
|
39
|
+
/** S11:node.error 时的重试回调(不传则只显示失败态) */
|
|
40
|
+
onRetry?: () => void;
|
|
39
41
|
depth: number;
|
|
40
42
|
collapsed: boolean;
|
|
41
43
|
collapseKey: string;
|
|
@@ -51,7 +53,7 @@ interface VirtualGroupHeaderProps {
|
|
|
51
53
|
showRoleLabel: boolean;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
export const VirtualGroupHeader = memo(function VirtualGroupHeader({ node, depth, collapsed, collapseKey, onToggle, onCreate, sticky, hideCreate, selectState, onToggleSelect, showSelect, groupDimension, showRoleLabel }: VirtualGroupHeaderProps) {
|
|
56
|
+
export const VirtualGroupHeader = memo(function VirtualGroupHeader({ node, depth, collapsed, collapseKey, onToggle, onCreate, onRetry, sticky, hideCreate, selectState, onToggleSelect, showSelect, groupDimension, showRoleLabel }: VirtualGroupHeaderProps) {
|
|
55
57
|
const textColor =
|
|
56
58
|
node.color?.split(" ").find((c) => c.startsWith("text")) ?? "text-muted-foreground";
|
|
57
59
|
const Icon = node.icon;
|
|
@@ -87,6 +89,17 @@ export const VirtualGroupHeader = memo(function VirtualGroupHeader({ node, depth
|
|
|
87
89
|
</span>
|
|
88
90
|
)}
|
|
89
91
|
<span className="text-xs text-muted-foreground">{node.totalCount ?? node.items.length}</span>
|
|
92
|
+
{node.error && (
|
|
93
|
+
<button
|
|
94
|
+
type="button"
|
|
95
|
+
onClick={(e) => { e.stopPropagation(); onRetry?.(); }}
|
|
96
|
+
className="inline-flex h-4 shrink-0 items-center gap-0.5 rounded border border-destructive/30 px-1 text-[10px] font-normal text-destructive hover:bg-destructive/10"
|
|
97
|
+
title={m.story_group_loadFailed()}
|
|
98
|
+
>
|
|
99
|
+
<AlertCircle className="size-2.5" />
|
|
100
|
+
{m.story_group_retry()}
|
|
101
|
+
</button>
|
|
102
|
+
)}
|
|
90
103
|
</button>
|
|
91
104
|
{depth === 0 && onCreate && !hideCreate && (
|
|
92
105
|
<button
|
|
@@ -26,8 +26,8 @@ import {
|
|
|
26
26
|
reorderStoriesFn,
|
|
27
27
|
} from "@/server/serverFns/story";
|
|
28
28
|
import { toast } from "@/components/ui/toast";
|
|
29
|
-
import type { UserBrief } from "
|
|
30
|
-
import type { StoryState, StoryPriority } from "
|
|
29
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
30
|
+
import type { StoryState, StoryPriority } from "@/shared/story/constants";
|
|
31
31
|
import type { DisplayOptions } from "../../display/types";
|
|
32
32
|
import type { PagedGroupNode } from "../../display/use-paged-story-groups";
|
|
33
33
|
import { BUTTON_ROW_HEIGHT, useFlatRows } from "./use-flat-rows";
|
|
@@ -484,6 +484,7 @@ export function StoryList({ groups, isLoading = false, displayFilters, users, la
|
|
|
484
484
|
showSelect={selectedIds.size > 0}
|
|
485
485
|
groupDimension={row.depth === 0 ? groupBy : subGroupBy}
|
|
486
486
|
showRoleLabel={showRoleLabel}
|
|
487
|
+
onRetry={onRefresh}
|
|
487
488
|
/>
|
|
488
489
|
</div>
|
|
489
490
|
{create && (
|
|
@@ -556,6 +557,7 @@ export function StoryList({ groups, isLoading = false, displayFilters, users, la
|
|
|
556
557
|
>
|
|
557
558
|
<VirtualGroupHeader
|
|
558
559
|
node={row.node}
|
|
560
|
+
onRetry={onRefresh}
|
|
559
561
|
depth={row.depth}
|
|
560
562
|
collapsed={row.isCollapsed}
|
|
561
563
|
collapseKey={row.key}
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
import { memo, useEffect, useRef, useMemo } from "react";
|
|
19
19
|
import { Loader2, CalendarCheck, CalendarPlus2, Check, X, Trees } from "lucide-react";
|
|
20
20
|
import { LucideIconByName } from "@/components/shared-kit/icons/lucide-icon-picker/lucide-icon-by-name";
|
|
21
|
-
import type { UserBrief } from "
|
|
22
|
-
import type { StoryState, StoryPriority } from "
|
|
21
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
22
|
+
import type { StoryState, StoryPriority } from "@/shared/story/constants";
|
|
23
23
|
import { PriorityEditor, StateEditor, AssigneeEditor, DateEditor, LabelsEditor } from "../../inline-editors";
|
|
24
24
|
import { m } from "@/paraglide/messages.js";
|
|
25
25
|
|
|
@@ -20,8 +20,8 @@ import { useServerFn } from "@tanstack/react-start";
|
|
|
20
20
|
import { CalendarCheck, CalendarPlus2 } from "lucide-react";
|
|
21
21
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
22
22
|
import { updateStoryFn } from "@/server/serverFns/story";
|
|
23
|
-
import type { StoryListItem, UserBrief } from "
|
|
24
|
-
import type { StoryState, StoryPriority } from "
|
|
23
|
+
import type { StoryListItem, UserBrief } from "@/shared/story/types";
|
|
24
|
+
import type { StoryState, StoryPriority } from "@/shared/story/constants";
|
|
25
25
|
import type { DisplayProperty } from "../../display/types";
|
|
26
26
|
import { PriorityEditor, StateEditor, AssigneeEditor, DateEditor, LabelsEditor } from "../../inline-editors";
|
|
27
27
|
import { cn } from "@/lib/utils";
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
18
|
import { useMemo } from "react";
|
|
19
|
-
import type { StoryListItem } from "
|
|
19
|
+
import type { StoryListItem } from "@/shared/story/types";
|
|
20
20
|
import type { GroupNode } from "../../display/types";
|
|
21
21
|
|
|
22
22
|
/** 组尾「显示更多」/「添加需求」组合行高 */
|
|
@@ -30,9 +30,9 @@ import {
|
|
|
30
30
|
type IterationBaseline,
|
|
31
31
|
} from "../mappers";
|
|
32
32
|
import { STATE_COLUMN_TINT, PRIORITY_COLUMN_TINT, resolveGroupColor } from "../../../display/group-resolver";
|
|
33
|
-
import { STORY_STATES, STATE_LABEL, PRIORITY_LABEL, type StoryState } from "
|
|
33
|
+
import { STORY_STATES, STATE_LABEL, PRIORITY_LABEL, type StoryState } from "@/shared/story/constants";
|
|
34
34
|
import { parseDate } from "@/lib/datetime";
|
|
35
|
-
import type { StoryListItem } from "
|
|
35
|
+
import type { StoryListItem } from "@/shared/story/types";
|
|
36
36
|
import type { GroupContext } from "../../../display/types";
|
|
37
37
|
import type { GanttEvent, GanttResource } from "@/components/reui/gantt/gantt-types";
|
|
38
38
|
import { m } from "@/paraglide/messages.js";
|
|
@@ -35,8 +35,8 @@ import type {
|
|
|
35
35
|
GanttEvent,
|
|
36
36
|
GanttResource,
|
|
37
37
|
} from "@/components/reui/gantt/gantt-types";
|
|
38
|
-
import { STORY_STATES, type StoryState, type StoryPriority } from "
|
|
39
|
-
import type { StoryListItem } from "
|
|
38
|
+
import { STORY_STATES, type StoryState, type StoryPriority } from "@/shared/story/constants";
|
|
39
|
+
import type { StoryListItem } from "@/shared/story/types";
|
|
40
40
|
import type { GroupContext, GroupKey, GroupNode } from "../../display/types";
|
|
41
41
|
// 分组语义单一来源:priority/assignee/labels/createdBy/project 的桶划分与
|
|
42
42
|
// 标签/颜色解析全部复用 display/group-resolver(禁止重写分组语义)。
|
|
@@ -36,7 +36,7 @@ import { toast } from "@/components/ui/toast";
|
|
|
36
36
|
import { toastError } from "@/lib/toast-error";
|
|
37
37
|
import { m } from "@/paraglide/messages.js";
|
|
38
38
|
import { fromGanttRangeToStoryDates } from "./mappers";
|
|
39
|
-
import type { StoryState } from "
|
|
39
|
+
import type { StoryState } from "@/shared/story/constants";
|
|
40
40
|
|
|
41
41
|
/** 乐观覆盖:storyId → 覆盖后的两个日期(targetDate null = 保持无截止) */
|
|
42
42
|
export interface StoryDateOverride {
|
|
@@ -70,12 +70,12 @@ import type {
|
|
|
70
70
|
GanttResource,
|
|
71
71
|
GanttScale,
|
|
72
72
|
} from "@/components/reui/gantt/gantt-types";
|
|
73
|
-
import { STATE_COLOR, STATE_LABEL } from "
|
|
73
|
+
import { STATE_COLOR, STATE_LABEL } from "@/shared/story/constants";
|
|
74
74
|
import {
|
|
75
75
|
TIMELINE_GROUP_KEYS,
|
|
76
76
|
type TimelineGroupKey,
|
|
77
77
|
} from "../display/constants";
|
|
78
|
-
import type { StoryListItem, UserBrief } from "
|
|
78
|
+
import type { StoryListItem, UserBrief } from "@/shared/story/types";
|
|
79
79
|
import { applyOrder } from "../display/order-resolver";
|
|
80
80
|
import type { GroupContext, GroupKey, OrderKey } from "../display/types";
|
|
81
81
|
import {
|
|
@@ -84,7 +84,7 @@ class MockIntersectionObserver {
|
|
|
84
84
|
import { CaseRow } from "../list/case-row";
|
|
85
85
|
import { GroupedList, type TestCaseGroupBy, type TestCaseGroupInfo } from "../list/grouped-list";
|
|
86
86
|
import type { TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
87
|
-
import type { UserBrief } from "@/
|
|
87
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
88
88
|
import type { FolderNodeDto } from "../folder-tree";
|
|
89
89
|
|
|
90
90
|
const makeUser = (id: string, username: string): UserBrief => ({
|
|
@@ -50,7 +50,7 @@ vi.mock("@/components/story/inline-editors/story-select-dialog", () => ({
|
|
|
50
50
|
|
|
51
51
|
import { CreateTestCaseDialog } from "../create-testcase-dialog";
|
|
52
52
|
import type { TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
53
|
-
import type { UserBrief } from "@/
|
|
53
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
54
54
|
import type { FolderNodeDto } from "../folder-tree";
|
|
55
55
|
|
|
56
56
|
const makeUser = (id: string, username: string): UserBrief => ({
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
DEFAULT_TESTCASE_DISPLAY_OPTIONS,
|
|
37
37
|
TESTCASE_DISPLAY_PROPERTIES,
|
|
38
38
|
type TestCaseDisplayOptions,
|
|
39
|
-
} from "
|
|
39
|
+
} from "@/shared/testcase/field-configs";
|
|
40
40
|
|
|
41
41
|
const OPTIONS: TestCaseDisplayOptions = {
|
|
42
42
|
...DEFAULT_TESTCASE_DISPLAY_OPTIONS,
|
|
@@ -64,7 +64,7 @@ vi.mock("@/components/ui/toast", () => ({
|
|
|
64
64
|
vi.mock("@/lib/toast-error", () => ({ toastError: H.toastErrorFn }));
|
|
65
65
|
|
|
66
66
|
import { TestCaseToolbar } from "../testcase-toolbar";
|
|
67
|
-
import type { TestCaseDisplayOptions } from "
|
|
67
|
+
import type { TestCaseDisplayOptions } from "@/shared/testcase/field-configs";
|
|
68
68
|
import type { TestcaseFilterCondition } from "../filters";
|
|
69
69
|
|
|
70
70
|
const CSV = "\uFEFF编号,标题,类型,优先级,状态,负责人\r\nWEB-TC1,登录成功,functional,p1,approved,";
|
|
@@ -180,7 +180,7 @@ class MockIntersectionObserver {
|
|
|
180
180
|
import { TestCaseListView } from "../list-view";
|
|
181
181
|
import type { TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
182
182
|
import type { TestCaseFilterViewDTO } from "@/server/serverFns/testcase/testcase-filter-views";
|
|
183
|
-
import { DEFAULT_TESTCASE_DISPLAY_OPTIONS, type TestCaseDisplayOptions } from "
|
|
183
|
+
import { DEFAULT_TESTCASE_DISPLAY_OPTIONS, type TestCaseDisplayOptions } from "@/shared/testcase/field-configs";
|
|
184
184
|
import { listTestCaseBoardColumnsFn } from "@/server/serverFns/testcase/testcase-board";
|
|
185
185
|
import { serializeFilters } from "../filters";
|
|
186
186
|
|
|
@@ -71,7 +71,7 @@ import { useState } from "react";
|
|
|
71
71
|
import { StepEditor, type StepDraft } from "../step-editor";
|
|
72
72
|
import { CreateTestCaseDialog } from "../create-testcase-dialog";
|
|
73
73
|
import type { TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
74
|
-
import type { UserBrief } from "@/
|
|
74
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
75
75
|
import type { FolderNodeDto } from "../folder-tree";
|
|
76
76
|
import { toast } from "@/components/ui/toast";
|
|
77
77
|
|
|
@@ -157,7 +157,9 @@ describe("StepEditor", () => {
|
|
|
157
157
|
fireEvent.click(screen.getByTestId("step-add"));
|
|
158
158
|
const last = onChange.mock.calls.at(-1)![0] as StepDraft[];
|
|
159
159
|
expect(last).toHaveLength(3);
|
|
160
|
-
|
|
160
|
+
// S15:新增行携带稳定 id(仅本地草稿键控用)
|
|
161
|
+
expect(last[2]).toMatchObject({ action: "", expected: "" });
|
|
162
|
+
expect(typeof last[2]!.id).toBe("string");
|
|
161
163
|
});
|
|
162
164
|
|
|
163
165
|
it("边界序号:首行上移/末行下移为 no-op(按钮禁用)", () => {
|
|
@@ -60,7 +60,7 @@ vi.mock("@/server/serverFns/testcase/testcase-export", () => ({
|
|
|
60
60
|
}));
|
|
61
61
|
|
|
62
62
|
import { TestCaseToolbar } from "../testcase-toolbar";
|
|
63
|
-
import type { TestCaseDisplayOptions } from "
|
|
63
|
+
import type { TestCaseDisplayOptions } from "@/shared/testcase/field-configs";
|
|
64
64
|
|
|
65
65
|
afterEach(() => {
|
|
66
66
|
cleanup();
|
|
@@ -47,13 +47,13 @@ import { toast } from "@/components/ui/toast";
|
|
|
47
47
|
import { createTestCaseFn } from "@/server/serverFns/testcase/testcase-crud";
|
|
48
48
|
import type { TestCasePriority, TestCaseType } from "@/server/serverFns/testcase/constants";
|
|
49
49
|
import type { TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
50
|
-
import type { UserBrief } from "@/
|
|
50
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
51
51
|
import { StorySelectDialog } from "@/components/story/inline-editors/story-select-dialog";
|
|
52
52
|
import { TypeEditor } from "./inline-editors/type-editor";
|
|
53
53
|
import { PriorityEditor } from "./inline-editors/priority-editor";
|
|
54
54
|
import { FolderEditor } from "./inline-editors/folder-editor";
|
|
55
55
|
import { AssigneeEditor } from "./inline-editors/assignee-editor";
|
|
56
|
-
import { StepEditor, isStepDraftsValid, type StepDraft } from "./step-editor";
|
|
56
|
+
import { StepEditor, isStepDraftsValid, newStepDraftId, type StepDraft } from "./step-editor";
|
|
57
57
|
import type { FolderNodeDto } from "./folder-tree";
|
|
58
58
|
import { m } from "@/paraglide/messages.js";
|
|
59
59
|
|
|
@@ -77,7 +77,8 @@ interface CreateTestCaseDialogProps {
|
|
|
77
77
|
onSuccess?: (testCase: TestCaseSummary) => void;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
// S15:工厂替代模块级常量(每次打开 dialog 生成带稳定 id 的行)
|
|
81
|
+
const makeInitialSteps = (): StepDraft[] => [{ id: newStepDraftId(), action: "", expected: "" }];
|
|
81
82
|
|
|
82
83
|
export function CreateTestCaseDialog({
|
|
83
84
|
open,
|
|
@@ -91,7 +92,7 @@ export function CreateTestCaseDialog({
|
|
|
91
92
|
}: CreateTestCaseDialogProps) {
|
|
92
93
|
const [title, setTitle] = useState("");
|
|
93
94
|
const [precondition, setPrecondition] = useState("");
|
|
94
|
-
const [steps, setSteps] = useState<StepDraft[]>(
|
|
95
|
+
const [steps, setSteps] = useState<StepDraft[]>(makeInitialSteps);
|
|
95
96
|
const [type, setType] = useState<TestCaseType>("functional");
|
|
96
97
|
const [priority, setPriority] = useState<TestCasePriority>("p1");
|
|
97
98
|
const [folderId, setFolderId] = useState<string | null>(null);
|
|
@@ -109,7 +110,7 @@ export function CreateTestCaseDialog({
|
|
|
109
110
|
if (!open) return;
|
|
110
111
|
setTitle("");
|
|
111
112
|
setPrecondition("");
|
|
112
|
-
setSteps(
|
|
113
|
+
setSteps(makeInitialSteps());
|
|
113
114
|
setType("functional");
|
|
114
115
|
setPriority("p1");
|
|
115
116
|
setFolderId(initialFolderId ?? null);
|
|
@@ -39,7 +39,7 @@ import type {
|
|
|
39
39
|
TestCaseDetail,
|
|
40
40
|
TestCaseStoryRef,
|
|
41
41
|
} from "@/server/serverFns/testcase/types";
|
|
42
|
-
import type { UserBrief } from "@/
|
|
42
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
43
43
|
import type { FolderNodeDto } from "../folder-tree";
|
|
44
44
|
import type { TestCaseUpdatePatch } from "../list/case-row";
|
|
45
45
|
import { buildRoomName } from "@allbluecn/collab-core/rooms";
|
|
@@ -24,7 +24,7 @@ import { ExternalLink } from "lucide-react";
|
|
|
24
24
|
import { Badge } from "@/components/ui/badge";
|
|
25
25
|
import type { TestCaseDetail, TestCaseStoryRef } from "@/server/serverFns/testcase/types";
|
|
26
26
|
import type { TestCaseAutomation } from "@/server/serverFns/testcase/constants";
|
|
27
|
-
import type { UserBrief } from "@/
|
|
27
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
28
28
|
import type { FolderNodeDto } from "../folder-tree";
|
|
29
29
|
import type { TestCaseUpdatePatch } from "../list/case-row";
|
|
30
30
|
import { AssigneeEditor } from "../inline-editors/assignee-editor";
|
|
@@ -42,14 +42,14 @@ import type {
|
|
|
42
42
|
TestCaseDisplayProperty,
|
|
43
43
|
TestCaseGroupKey,
|
|
44
44
|
TestCaseOrderKey,
|
|
45
|
-
} from "
|
|
45
|
+
} from "@/shared/testcase/field-configs";
|
|
46
46
|
import {
|
|
47
47
|
DEFAULT_TESTCASE_DISPLAY_OPTIONS,
|
|
48
48
|
TESTCASE_DISPLAY_PROPERTIES,
|
|
49
49
|
TESTCASE_GROUP_KEYS,
|
|
50
50
|
TESTCASE_ORDER_KEYS,
|
|
51
51
|
TESTCASE_PAGE_SIZE_OPTIONS,
|
|
52
|
-
} from "
|
|
52
|
+
} from "@/shared/testcase/field-configs";
|
|
53
53
|
|
|
54
54
|
/** 分组维度标签(testcase_display_ 域文案,照 bug display/constants 裁剪) */
|
|
55
55
|
const GROUP_LABELS: Record<TestCaseGroupKey, () => string> = {
|
|
@@ -69,7 +69,7 @@ import type {
|
|
|
69
69
|
FilterUserLike,
|
|
70
70
|
} from "@/components/shared-kit/list-kit/filters";
|
|
71
71
|
import { cn } from "@/lib/utils";
|
|
72
|
-
import type { UserBrief } from "@/
|
|
72
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
73
73
|
|
|
74
74
|
export { serializeFilters, deserializeFilters, OPERATOR_LABELS, generateConditionId } from "@/components/shared-kit/list-kit/filters";
|
|
75
75
|
export type { FilterOperator, FilterFieldType };
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
} from "@/components/ui/dialog";
|
|
34
34
|
import { Input } from "@/components/ui/input";
|
|
35
35
|
import { Textarea } from "@/components/ui/textarea";
|
|
36
|
-
import { StepEditor, isStepDraftsValid, type StepDraft } from "@/components/testcase/step-editor";
|
|
36
|
+
import { StepEditor, isStepDraftsValid, newStepDraftId, type StepDraft } from "@/components/testcase/step-editor";
|
|
37
37
|
import { stateLabel, typeLabel, priorityLabel } from "@/components/testcase/filters";
|
|
38
38
|
import type {
|
|
39
39
|
TestCasePriority,
|
|
@@ -121,7 +121,7 @@ export function DraftCard({
|
|
|
121
121
|
const [title, setTitle] = useState(draft.title);
|
|
122
122
|
const [precondition, setPrecondition] = useState(draft.precondition ?? "");
|
|
123
123
|
const [steps, setSteps] = useState<StepDraft[]>(() =>
|
|
124
|
-
draft.steps.steps.map((s) => ({ action: s.action, expected: s.expected ?? "" })),
|
|
124
|
+
draft.steps.steps.map((s) => ({ id: newStepDraftId(), action: s.action, expected: s.expected ?? "" })),
|
|
125
125
|
);
|
|
126
126
|
|
|
127
127
|
const openEditDialog = () => {
|
|
@@ -22,7 +22,7 @@ import { Check, CircleUser, Search } from "lucide-react";
|
|
|
22
22
|
import { Input } from "@/components/ui/input";
|
|
23
23
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
24
24
|
import { UserAvatar } from "@/components/shared-kit";
|
|
25
|
-
import type { UserBrief } from "@/
|
|
25
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
26
26
|
import { cn } from "@/lib/utils";
|
|
27
27
|
import { m } from "@/paraglide/messages.js";
|
|
28
28
|
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
import { updateTestCaseFn } from "@/server/serverFns/testcase/testcase-crud";
|
|
41
41
|
import type { TestCaseAutomation, TestCasePriority, TestCaseState, TestCaseType } from "@/server/serverFns/testcase/constants";
|
|
42
42
|
import type { TestCaseSteps, TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
43
|
-
import type { UserBrief } from "@/
|
|
43
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
44
44
|
import type { FolderNodeDto } from "../folder-tree";
|
|
45
45
|
import { PriorityEditor } from "../inline-editors/priority-editor";
|
|
46
46
|
import { StateEditor } from "../inline-editors/state-editor";
|
|
@@ -27,7 +27,7 @@ import { ChevronDown, ChevronRight } from "lucide-react";
|
|
|
27
27
|
import { InfiniteScrollSentinel } from "@/components/infinite-scroll-sentinel";
|
|
28
28
|
import type { TestCaseState, TestCasePriority } from "@/server/serverFns/testcase/constants";
|
|
29
29
|
import type { TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
30
|
-
import type { UserBrief } from "@/
|
|
30
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
31
31
|
import type { FolderNodeDto } from "../folder-tree";
|
|
32
32
|
import { priorityLabel, stateLabel } from "../filters";
|
|
33
33
|
import { CaseRow } from "./case-row";
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
updateFilterViewFn,
|
|
54
54
|
} from "@/server/serverFns/testcase/testcase-filter-views";
|
|
55
55
|
import type { TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
56
|
-
import type { UserBrief } from "@/
|
|
56
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
57
57
|
import { GroupedList, groupKeyOf, type TestCaseGroupInfo } from "./list/grouped-list";
|
|
58
58
|
import { computeMove, canMove } from "@/components/shared-kit/list-kit/move";
|
|
59
59
|
import { TestCaseBoardView } from "./views/board-view";
|
|
@@ -62,7 +62,7 @@ import { manualOrderSwitchPatch } from "@/components/shared-kit/list-kit/kanban/
|
|
|
62
62
|
import { toast } from "@/components/ui/toast";
|
|
63
63
|
import { TestCasePeekPanel, type PeekMode } from "./peek-panel";
|
|
64
64
|
import { useTestcaseDisplayOptions } from "./display/use-testcase-display-options";
|
|
65
|
-
import type { TestCaseGroupKey } from "
|
|
65
|
+
import type { TestCaseGroupKey } from "@/shared/testcase/field-configs";
|
|
66
66
|
import { CreateViewDialog, type CreateViewDialogPayload } from "./views/create-view-dialog";
|
|
67
67
|
import { CreateTestCaseDialog } from "./create-testcase-dialog";
|
|
68
68
|
import { TestCaseBatchToolbar } from "./views/batch-toolbar";
|
|
@@ -26,10 +26,10 @@ import { useCallback, useState } from "react";
|
|
|
26
26
|
import { Bug as BugIcon } from "lucide-react";
|
|
27
27
|
import { Button } from "@/components/ui/button";
|
|
28
28
|
import { CreateBugDialog, type CreateBugDialogDefaults } from "@/components/bug/create-bug-dialog";
|
|
29
|
-
import type { ReproduceSteps } from "@/
|
|
29
|
+
import type { ReproduceSteps } from "@/shared/bug/types";
|
|
30
30
|
import { listUsersBriefFn, listLabelsFn } from "@/server/serverFns/story";
|
|
31
31
|
import { listProjectsBriefFn } from "@/server/serverFns/project";
|
|
32
|
-
import type { UserBrief } from "@/
|
|
32
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
33
33
|
import type {
|
|
34
34
|
RunCaseExecutionDetail,
|
|
35
35
|
RunCaseSummary,
|
|
@@ -31,6 +31,17 @@ import { m } from "@/paraglide/messages.js";
|
|
|
31
31
|
export interface StepDraft {
|
|
32
32
|
action: string;
|
|
33
33
|
expected: string;
|
|
34
|
+
/**
|
|
35
|
+
* 行稳定 id(S15):仅本地草稿模式(create dialog / AI draft)用于 React key,
|
|
36
|
+
* 消除中段插入/删除时的跨行状态串位;granular 协同模式不消费(Y 增量仍按
|
|
37
|
+
* 索引映射,id 不落库——提交侧 order 由索引推导,id 自然剥离)。
|
|
38
|
+
*/
|
|
39
|
+
readonly id?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** 行稳定 id 生成(本地草稿专用,S15) */
|
|
43
|
+
export function newStepDraftId(): string {
|
|
44
|
+
return crypto.randomUUID();
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
interface StepEditorProps {
|
|
@@ -79,7 +90,7 @@ export function StepEditor({ value, onChange, disabled, className, granular }: S
|
|
|
79
90
|
granular.onInsertStep(value.length, { action: "", expected: "" });
|
|
80
91
|
return;
|
|
81
92
|
}
|
|
82
|
-
onChange([...value, { action: "", expected: "" }]);
|
|
93
|
+
onChange([...value, { id: newStepDraftId(), action: "", expected: "" }]);
|
|
83
94
|
};
|
|
84
95
|
|
|
85
96
|
const removeStep = (i: number) => {
|
|
@@ -128,7 +139,7 @@ export function StepEditor({ value, onChange, disabled, className, granular }: S
|
|
|
128
139
|
const showActionError = dirty.has(i) && actionEmpty;
|
|
129
140
|
return (
|
|
130
141
|
<li
|
|
131
|
-
key={i}
|
|
142
|
+
key={step.id ?? `idx-${i}`}
|
|
132
143
|
className="flex items-start gap-2"
|
|
133
144
|
data-testid={`step-row-${i}`}
|
|
134
145
|
>
|
|
@@ -72,11 +72,11 @@ import {
|
|
|
72
72
|
import { toast } from "@/components/ui/toast";
|
|
73
73
|
import { toastError } from "@/lib/toast-error";
|
|
74
74
|
import type { FolderNodeDto } from "./folder-tree";
|
|
75
|
-
import type { UserBrief } from "@/
|
|
75
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
76
76
|
import { ViewSelectorButton } from "./views/view-selector-button";
|
|
77
77
|
import { ViewSwitcher } from "./views/view-switcher";
|
|
78
78
|
import { TestCaseDisplayDropdown } from "./display/display-dropdown";
|
|
79
|
-
import type { TestCaseDisplayOptions } from "
|
|
79
|
+
import type { TestCaseDisplayOptions } from "@/shared/testcase/field-configs";
|
|
80
80
|
import type { TestCaseSavedView, TestCaseViewType } from "./views/view-types";
|
|
81
81
|
import { m } from "@/paraglide/messages.js";
|
|
82
82
|
import { getLocale } from "@/paraglide/runtime.js";
|
|
@@ -37,7 +37,7 @@ import { PriorityEditor } from "../inline-editors/priority-editor";
|
|
|
37
37
|
import { AssigneeEditor } from "../inline-editors/assignee-editor";
|
|
38
38
|
import { FolderEditor } from "../inline-editors/folder-editor";
|
|
39
39
|
import type { FolderNodeDto } from "../folder-tree";
|
|
40
|
-
import type { UserBrief } from "@/
|
|
40
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
41
41
|
import { toastError } from "@/lib/toast-error";
|
|
42
42
|
import { cn } from "@/lib/utils";
|
|
43
43
|
import { m } from "@/paraglide/messages.js";
|
|
@@ -44,7 +44,7 @@ import type {
|
|
|
44
44
|
TestCaseType,
|
|
45
45
|
} from "@/server/serverFns/testcase/constants";
|
|
46
46
|
import type { TestCaseSummary } from "@/server/serverFns/testcase/types";
|
|
47
|
-
import type { UserBrief } from "@/
|
|
47
|
+
import type { UserBrief } from "@/shared/story/types";
|
|
48
48
|
import type { FolderNodeDto } from "../folder-tree";
|
|
49
49
|
import type { TestCaseUpdatePatch } from "../list/case-row";
|
|
50
50
|
import { PriorityEditor } from "../inline-editors/priority-editor";
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
TEST_CASE_TYPE_META,
|
|
57
57
|
} from "../constants";
|
|
58
58
|
import { priorityLabel, stateLabel, typeLabel } from "../filters";
|
|
59
|
-
import type { TestCaseDisplayProperty } from "
|
|
59
|
+
import type { TestCaseDisplayProperty } from "@/shared/testcase/field-configs";
|
|
60
60
|
import {
|
|
61
61
|
KanbanBoardView,
|
|
62
62
|
type ColumnTint,
|
|
@@ -96,14 +96,14 @@ export const SDK_GROUPS: SdkGroup[] = [
|
|
|
96
96
|
"items": [
|
|
97
97
|
{
|
|
98
98
|
"name": "@allbluecn/web-app",
|
|
99
|
-
"version": "v0.
|
|
99
|
+
"version": "v0.21.0",
|
|
100
100
|
"lastUpdate": "Oct 28, 2026",
|
|
101
101
|
"source": "apps/web/package.json",
|
|
102
102
|
"docsUrl": "https://github.com/allbluecn/allblue"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
"name": "@allbluecn/kernel",
|
|
106
|
-
"version": "v0.
|
|
106
|
+
"version": "v0.11.0",
|
|
107
107
|
"lastUpdate": "Oct 28, 2026",
|
|
108
108
|
"source": "packages/kernel/package.json",
|
|
109
109
|
"docsUrl": "https://github.com/allbluecn/allblue"
|
|
@@ -20,7 +20,8 @@ import { queryCollectionOptions } from '@tanstack/query-db-collection'
|
|
|
20
20
|
import { listKnowledgeFn } from '@/server/serverFns/knowledge'
|
|
21
21
|
import { getQueryClient } from '@/lib/query-client-seam'
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
import { KNOWLEDGE_BASES_QUERY_KEY } from "@/lib/collections/query-keys"
|
|
24
|
+
export { KNOWLEDGE_BASES_QUERY_KEY }
|
|
24
25
|
|
|
25
26
|
export const knowledgeBasesCollection = createCollection(
|
|
26
27
|
queryCollectionOptions({
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
|
|
5
|
+
// React Query key 常量(零依赖纯模块)。
|
|
6
|
+
//
|
|
7
|
+
// 为什么单独成文件:collection 模块在**模块作用域**执行
|
|
8
|
+
// `createCollection({ ... queryClient: getQueryClient() })`,而 getQueryClient()
|
|
9
|
+
// 在 SSR 未注入时 fail-fast(防跨请求缓存串染)。路由文件(如 _nav/route.tsx)
|
|
10
|
+
// 只需要 key 常量做 prefetch,却值引入 collection 模块 → SSR 模块初始化阶段
|
|
11
|
+
// 就触发 getQueryClient(),早于 router.tsx 的 setQueryClient,全站 500。
|
|
12
|
+
// 消费方一律从本模块取 key;collection 模块转 re-export 保持兼容。
|
|
13
|
+
export const WORKSPACES_QUERY_KEY = ['workspaces'] as const
|
|
14
|
+
export const KNOWLEDGE_BASES_QUERY_KEY = ['knowledge-bases'] as const
|
|
15
|
+
export const PROJECTS_QUERY_KEY = ['projects'] as const
|
|
16
|
+
export const LABELS_QUERY_KEY = ['labels'] as const
|
|
17
|
+
export const USERS_BRIEF_QUERY_KEY = ['users-brief'] as const
|
|
18
|
+
export const BOOKMARK_CATEGORIES_QUERY_KEY = ['bookmark-categories'] as const
|