Skip to content

Commit 80b62cb

Browse files
pk-zipstackpre-commit-ci[bot]claudeDeepak-Kesavanhari-kuriakose
authored
UN-3217 [FEAT] Show specific pipeline/API names in workflow deletion error message (#1784)
* Improved workflow deltion error message * improved error message * addressed code rabbit comments * added limit to data fetched while deleting workflows * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Query counts before fetching names to skip unnecessary queries Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix Biome lint warning for unused variable in Workflows.jsx Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Deepak K <89829542+Deepak-Kesavan@users.noreply.github.com> Co-authored-by: Hari John Kuriakose <hari@zipstack.com>
1 parent 45f651b commit 80b62cb

File tree

2 files changed

+110
-32
lines changed

2 files changed

+110
-32
lines changed

backend/workflow_manager/workflow_v2/workflow_helper.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -994,18 +994,48 @@ def make_async_result(obj: AsyncResult) -> dict[str, Any]:
994994
"info": obj.info,
995995
}
996996

997+
USAGE_DISPLAY_LIMIT = 5
998+
997999
@staticmethod
9981000
def can_update_workflow(workflow_id: str) -> dict[str, Any]:
9991001
try:
10001002
workflow: Workflow = Workflow.objects.get(pk=workflow_id)
10011003
if not workflow or workflow is None:
10021004
raise WorkflowDoesNotExistError()
1003-
used_count = Pipeline.objects.filter(workflow=workflow).count()
1004-
if used_count == 0:
1005-
used_count = APIDeployment.objects.filter(workflow=workflow).count()
1006-
return {"can_update": used_count == 0}
1005+
1006+
pipeline_count = Pipeline.objects.filter(workflow=workflow).count()
1007+
api_count = APIDeployment.objects.filter(workflow=workflow).count()
1008+
1009+
if (pipeline_count + api_count) == 0:
1010+
return {
1011+
"can_update": True,
1012+
"pipelines": [],
1013+
"api_names": [],
1014+
"pipeline_count": 0,
1015+
"api_count": 0,
1016+
}
1017+
1018+
limit = WorkflowHelper.USAGE_DISPLAY_LIMIT
1019+
pipelines = list(
1020+
Pipeline.objects.filter(workflow=workflow).values(
1021+
"pipeline_name", "pipeline_type"
1022+
)[:limit]
1023+
)
1024+
api_names = list(
1025+
APIDeployment.objects.filter(workflow=workflow).values_list(
1026+
"display_name", flat=True
1027+
)[:limit]
1028+
)
1029+
1030+
return {
1031+
"can_update": False,
1032+
"pipelines": pipelines,
1033+
"api_names": api_names,
1034+
"pipeline_count": pipeline_count,
1035+
"api_count": api_count,
1036+
}
10071037
except Workflow.DoesNotExist:
1008-
logger.error(f"Error getting workflow: {id}")
1038+
logger.error(f"Error getting workflow: {workflow_id}")
10091039
raise WorkflowDoesNotExistError()
10101040

10111041

frontend/src/components/workflows/workflow/Workflows.jsx

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -149,37 +149,85 @@ function Workflows() {
149149
});
150150
}
151151

152-
const canDeleteProject = async (id) => {
153-
let status = false;
154-
await projectApiService.canUpdate(id).then((res) => {
155-
status = res?.data?.can_update || false;
156-
});
157-
return status;
152+
const checkWorkflowUsage = async (id) => {
153+
const res = await projectApiService.canUpdate(id);
154+
const data = res?.data || {};
155+
return {
156+
canUpdate: data.can_update || false,
157+
pipelines: data.pipelines || [],
158+
apiNames: data.api_names || [],
159+
pipelineCount: data.pipeline_count || 0,
160+
apiCount: data.api_count || 0,
161+
};
162+
};
163+
164+
const getUsageMessage = (workflowName, usage) => {
165+
const { pipelines, apiNames, pipelineCount, apiCount } = usage;
166+
const totalCount = pipelineCount + apiCount;
167+
if (totalCount === 0) {
168+
return `Cannot delete \`${workflowName}\` as it is currently in use.`;
169+
}
170+
171+
const displayLimit = 3;
172+
const lines = [];
173+
174+
if (apiNames.length > 0) {
175+
const shown = apiNames.slice(0, displayLimit);
176+
shown.forEach((name) => {
177+
lines.push(`- \`${name}\` (API Deployment)`);
178+
});
179+
if (apiCount > shown.length) {
180+
lines.push(
181+
`- ...and ${apiCount - shown.length} more API deployment(s)`,
182+
);
183+
}
184+
}
185+
186+
if (pipelines.length > 0) {
187+
const shown = pipelines.slice(0, displayLimit);
188+
shown.forEach((p) => {
189+
const name = p.pipeline_name;
190+
const type = p.pipeline_type;
191+
lines.push(`- \`${name}\` (${type} Pipeline)`);
192+
});
193+
const remaining = pipelineCount - shown.length;
194+
if (remaining > 0) {
195+
lines.push(`- ...and ${remaining} more pipeline(s)`);
196+
}
197+
}
198+
199+
const details = lines.join("\n");
200+
return `Cannot delete \`${workflowName}\` as it is used in:\n${details}`;
158201
};
159202

160203
const deleteProject = async (_evt, project) => {
161-
const canDelete = await canDeleteProject(project.id);
162-
if (canDelete) {
163-
projectApiService
164-
.deleteProject(project.id)
165-
.then(() => {
166-
getProjectList();
167-
setAlertDetails({
168-
type: "success",
169-
content: "Workflow deleted successfully",
204+
try {
205+
const usage = await checkWorkflowUsage(project.id);
206+
if (usage.canUpdate) {
207+
projectApiService
208+
.deleteProject(project.id)
209+
.then(() => {
210+
getProjectList();
211+
setAlertDetails({
212+
type: "success",
213+
content: "Workflow deleted successfully",
214+
});
215+
})
216+
.catch((err) => {
217+
setAlertDetails(
218+
handleException(err, `Unable to delete workflow ${project.id}`),
219+
);
170220
});
171-
})
172-
.catch((err) => {
173-
setAlertDetails(
174-
handleException(err, `Unable to delete workflow ${project.id}`),
175-
);
221+
} else {
222+
setAlertDetails({
223+
type: "error",
224+
content: getUsageMessage(project.workflow_name, usage),
176225
});
177-
} else {
178-
setAlertDetails({
179-
type: "error",
180-
content:
181-
"Cannot delete this Workflow, since it is used in one or many of the API/ETL/Task pipelines",
182-
});
226+
}
227+
} catch (err) {
228+
setAlertDetails(
229+
handleException(err, `Unable to delete workflow ${project.id}`),
230+
);
183231
}
184232
};
185233

@@ -249,7 +297,7 @@ function Workflows() {
249297
setPostHogCustomEvent("intent_new_wf_project", {
250298
info: "Clicked on '+ New Workflow' button",
251299
});
252-
} catch (err) {
300+
} catch (_err) {
253301
// If an error occurs while setting custom posthog event, ignore it and continue
254302
}
255303
};

0 commit comments

Comments
 (0)