feat: harden agent onboarding and device import flows

This commit is contained in:
kris
2026-03-31 05:18:58 +08:00
parent 4aed93e90c
commit f417fe1955
18 changed files with 975 additions and 132 deletions

View File

@@ -343,6 +343,7 @@ export interface DeviceImportDraft {
status: "pending_candidates" | "pending_selection" | "pending_resolution" | "resolved" | "applied";
candidates: DeviceImportCandidate[];
selectedCandidateIds: string[];
appliedProjectNames: string[];
createdAt: string;
updatedAt: string;
reviewedAt?: string;
@@ -1899,6 +1900,9 @@ function normalizeDeviceImportDraft(
selectedCandidateIds: dedupeStrings(
ensureArray(raw.selectedCandidateIds, fallback?.selectedCandidateIds ?? []),
),
appliedProjectNames: dedupeStrings(
ensureArray(raw.appliedProjectNames, fallback?.appliedProjectNames ?? []),
),
createdAt: raw.createdAt ?? fallback?.createdAt ?? nowIso(),
updatedAt: raw.updatedAt ?? fallback?.updatedAt ?? nowIso(),
reviewedAt: raw.reviewedAt ?? fallback?.reviewedAt,
@@ -5406,6 +5410,10 @@ function upsertDeviceImportDraftFromHeartbeat(
: "pending_selection",
candidates: payload.candidates,
selectedCandidateIds,
appliedProjectNames:
existing?.status === "applied" && selectedCandidateIds.length > 0
? existing.appliedProjectNames
: [],
createdAt: existing?.createdAt ?? nowIso(),
updatedAt: nowIso(),
reviewedAt: existing?.reviewedAt,
@@ -5760,6 +5768,7 @@ function upsertDeviceImportResolutionInState(
draft.reviewedAt = nowIso();
draft.reviewedBy = input.reviewedBy;
draft.resolutionId = resolution.resolutionId;
draft.appliedProjectNames = [];
state.deviceImportResolutions = [
resolution,
@@ -5786,6 +5795,7 @@ export async function selectDeviceImportCandidates(input: {
}
draft.selectedCandidateIds = nextSelected;
draft.status = "pending_resolution";
draft.appliedProjectNames = [];
draft.updatedAt = nowIso();
draft.reviewedBy = input.selectedBy;
draft.reviewedAt = undefined;
@@ -6074,6 +6084,7 @@ function applyDeviceImportResolutionInState(
resolution.appliedAt = nowIso();
resolution.appliedBy = input.appliedBy;
draft.status = "applied";
draft.appliedProjectNames = importedProjects.map((project) => project.name);
draft.updatedAt = nowIso();
return {