feat(FN-2726): add bulk node override support in dashboard workflows
- Extend batch task update APIs and route handlers to accept nodeId overrides alongside model settings - Update ListView bulk edit UX to load nodes and apply node overrides through batch updates - Add node routing visibility improvements in task detail/settings UI and align related labels/styles - Expand dashboard/API test coverage for node override batch updates and bulk edit behavior
This commit is contained in:
@@ -415,7 +415,16 @@ export function registerTaskWorkflowRoutes(ctx: ApiRoutesContext, deps: TaskWork
|
||||
router.post("/tasks/batch-update-models", async (req, res) => {
|
||||
try {
|
||||
const { store: scopedStore } = await getProjectContext(req);
|
||||
const { taskIds, modelProvider, modelId, validatorModelProvider, validatorModelId, planningModelProvider, planningModelId } = req.body;
|
||||
const {
|
||||
taskIds,
|
||||
modelProvider,
|
||||
modelId,
|
||||
validatorModelProvider,
|
||||
validatorModelId,
|
||||
planningModelProvider,
|
||||
planningModelId,
|
||||
nodeId,
|
||||
} = req.body;
|
||||
|
||||
// Validate taskIds
|
||||
if (!Array.isArray(taskIds)) {
|
||||
@@ -428,12 +437,17 @@ export function registerTaskWorkflowRoutes(ctx: ApiRoutesContext, deps: TaskWork
|
||||
throw badRequest("taskIds must contain non-empty strings");
|
||||
}
|
||||
|
||||
// Validate that at least one model field is being updated
|
||||
// Validate that at least one model field or node override is being updated
|
||||
const hasExecutorModel = modelProvider !== undefined || modelId !== undefined;
|
||||
const hasValidatorModel = validatorModelProvider !== undefined || validatorModelId !== undefined;
|
||||
const hasPlanningModel = planningModelProvider !== undefined || planningModelId !== undefined;
|
||||
if (!hasExecutorModel && !hasValidatorModel && !hasPlanningModel) {
|
||||
throw badRequest("At least one model field must be provided");
|
||||
const hasNodeId = nodeId !== undefined;
|
||||
if (!hasExecutorModel && !hasValidatorModel && !hasPlanningModel && !hasNodeId) {
|
||||
throw badRequest("At least one model field or nodeId must be provided");
|
||||
}
|
||||
|
||||
if (nodeId !== undefined && nodeId !== null && typeof nodeId !== "string") {
|
||||
throw badRequest("nodeId must be a string, null, or undefined");
|
||||
}
|
||||
|
||||
// Validate model field pairs (both provider and modelId must be provided together or neither)
|
||||
@@ -486,7 +500,15 @@ export function registerTaskWorkflowRoutes(ctx: ApiRoutesContext, deps: TaskWork
|
||||
}
|
||||
|
||||
// Build update payload (only include fields that were explicitly provided)
|
||||
const updates: { modelProvider?: string | null; modelId?: string | null; validatorModelProvider?: string | null; validatorModelId?: string | null; planningModelProvider?: string | null; planningModelId?: string | null } = {};
|
||||
const updates: {
|
||||
modelProvider?: string | null;
|
||||
modelId?: string | null;
|
||||
validatorModelProvider?: string | null;
|
||||
validatorModelId?: string | null;
|
||||
planningModelProvider?: string | null;
|
||||
planningModelId?: string | null;
|
||||
nodeId?: string | null;
|
||||
} = {};
|
||||
if (validatedExecutor.provider !== undefined) {
|
||||
updates.modelProvider = validatedExecutor.provider;
|
||||
}
|
||||
@@ -505,6 +527,9 @@ export function registerTaskWorkflowRoutes(ctx: ApiRoutesContext, deps: TaskWork
|
||||
if (validatedPlanning.modelId !== undefined) {
|
||||
updates.planningModelId = validatedPlanning.modelId;
|
||||
}
|
||||
if (nodeId !== undefined) {
|
||||
updates.nodeId = nodeId;
|
||||
}
|
||||
|
||||
// Update all tasks in parallel
|
||||
const updatePromises = taskIds.map(async (taskId) => {
|
||||
|
||||
Reference in New Issue
Block a user