Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: workflow step validation #3965

Merged
merged 75 commits into from
Mar 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
60dc9b0
tests: add round-trip test
Kiryous Mar 11, 2025
b34770c
fix: workflow string
Kiryous Mar 11, 2025
9007803
tests: add test for getYamlConditionFromStep
Kiryous Mar 11, 2025
facab71
fix: parser
Kiryous Mar 11, 2025
5576cb5
fix: types
Kiryous Mar 11, 2025
df9c6eb
fix: condition with single step or action
Kiryous Mar 11, 2025
9e9a080
chore: todo comments
Kiryous Mar 11, 2025
b2da217
fix: variable errors
Kiryous Mar 11, 2025
ff35e0a
wip: validation & completions
Kiryous Mar 11, 2025
95841dd
wip: yaml-monaco
Kiryous Mar 12, 2025
fc338c3
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 12, 2025
d35de3a
fix: do not wait for providers to load, show editor right away
Kiryous Mar 12, 2025
b2997a8
chore: note
Kiryous Mar 12, 2025
d310405
fix: frontend tests
Kiryous Mar 12, 2025
9d941ec
fix: ignore type errors in generated schemas
Kiryous Mar 12, 2025
41591f1
fix: types
Kiryous Mar 12, 2025
00cde44
refactor: clean-up
Kiryous Mar 13, 2025
c4621ff
fix: import
Kiryous Mar 13, 2025
f2b5bb7
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 13, 2025
9b2ec84
fix: tests & imports
Kiryous Mar 13, 2025
b82b4c2
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 23, 2025
54ab211
fix: monaco-yaml for webpack
Kiryous Mar 24, 2025
d8cdcc8
refactor: pre-build monaco workers for development with turbopack, or…
Kiryous Mar 24, 2025
7f0a746
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 24, 2025
35f8b31
fix: code review fixes
Kiryous Mar 24, 2025
0288630
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 24, 2025
f4bcb77
fix: validate values of enrich_incident and enrich_alert
Kiryous Mar 24, 2025
3cb9552
Merge branch 'fix/3825-workflow-step-validation' of github.com:keephq…
Kiryous Mar 24, 2025
3d683e6
feature: show list of errors at the bottom of the editor
Kiryous Mar 24, 2025
83786c6
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 24, 2025
489128f
fix: validation and parsing for foreach
Kiryous Mar 25, 2025
8d128fa
refactor: smooth yaml editor experience
Kiryous Mar 25, 2025
a098008
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 25, 2025
64215f6
refactor: types
Kiryous Mar 25, 2025
69c5776
fix: test-ids
Kiryous Mar 25, 2025
80b7254
rm leftover
Kiryous Mar 25, 2025
12aa5eb
test: e2e validation
Kiryous Mar 25, 2025
117a96d
fix: order yaml def
Kiryous Mar 25, 2025
c57e31d
fix: sorting workflow
Kiryous Mar 25, 2025
2234873
fix: tests, sorting, validation
Kiryous Mar 25, 2025
cbcb471
fix: validate secrets variables
Kiryous Mar 25, 2025
e3ebf6f
fix: tests
Kiryous Mar 25, 2025
2be110e
fix: useWorkflowSecrets test
Kiryous Mar 25, 2025
d08861b
fix: rename
Kiryous Mar 25, 2025
ff86d8e
fix: rm leftover
Kiryous Mar 25, 2025
aab8716
fix: do not save invalid yaml / steps or actions validation
Kiryous Mar 25, 2025
41871b4
chore: unify case in YAML components
Kiryous Mar 25, 2025
b6e1113
fix: review comments
Kiryous Mar 25, 2025
ca6cda0
fix: test
Kiryous Mar 25, 2025
2319e24
fix: split workflow e2e tests into a separate file, remove unconfigur…
Kiryous Mar 26, 2025
2a605ed
fix: try to fix tests
Kiryous Mar 26, 2025
c1c8b0f
fix: try fix tests [2]
Kiryous Mar 26, 2025
56af4de
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 26, 2025
da3c180
fix: separate workflow files for each test
Kiryous Mar 26, 2025
25f6743
Merge branch 'fix/3825-workflow-step-validation' of github.com:keephq…
Kiryous Mar 26, 2025
f136c4b
fix: revert workflow-sample.yml changes
Kiryous Mar 26, 2025
9ca448d
chore: log workflow finished execution with time
Kiryous Mar 26, 2025
92e2281
fix: increment revision on workflow updates
Kiryous Mar 26, 2025
521f8ae
refactor: clear naming
Kiryous Mar 26, 2025
815682d
fix: revert wait
Kiryous Mar 26, 2025
cdb846e
cleanup
Kiryous Mar 26, 2025
7eeeb93
fix: cls
Kiryous Mar 26, 2025
fefb458
Revert "cleanup"
Kiryous Mar 26, 2025
4bcfc96
Revert "refactor: clear naming"
Kiryous Mar 26, 2025
71b2188
Revert "fix: increment revision on workflow updates"
Kiryous Mar 26, 2025
63d8289
Revert "fix: cls"
Kiryous Mar 26, 2025
b142728
revert:
Kiryous Mar 26, 2025
c334347
move workflow tests back to end_to_end file
Kiryous Mar 26, 2025
3055e6c
Merge branch 'main' into fix/3825-workflow-step-validation
Kiryous Mar 26, 2025
70331e4
fix: increment revision on workflow updates
Kiryous Mar 26, 2025
aab1ece
refactor: clear naming
Kiryous Mar 26, 2025
0c3df69
cleanup
Kiryous Mar 26, 2025
30a3103
fix: continue cleanup
Kiryous Mar 26, 2025
b761615
fix: var name
Kiryous Mar 26, 2025
f9a8017
fix: unused import
Kiryous Mar 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ scripts/automatic_extraction_rules.py
playwright_dump_*.html
playwright_dump_*.png
playwright_dump_*.txt
playwright_dump_*.json

ee/experimental/ai_temp/*
,e!ee/experimental/ai_temp/.gitkeep
Expand Down
6 changes: 4 additions & 2 deletions examples/workflows/http_example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ workflow:
Alert details: {{ alert }}"
# enrich the incident with the current tier
enrich_incident:
current_tier: 0
- key: current_tier
value: 0
- name: send-slack-message-tier-1
if: "{{ incident.current_tier == 0 && alert.name == 'alert1' }}"
provider:
Expand All @@ -36,4 +37,5 @@ workflow:
Alert: {{ alert.name }} - {{ alert.description }}
Alert details: {{ alert }}"
enrich_incident:
current_tier: 1
- key: current_tier
value: 1
3 changes: 3 additions & 0 deletions keep-ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ app/topology/mock-topology-data.tsx

# Sentry Config File
.env.sentry-build-plugin

# Monaco workers (generated at build time for turbopack dev)
public/monaco-workers/
36 changes: 24 additions & 12 deletions keep-ui/app/(keep)/topology/ui/map/topology-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,15 @@ import { getNodesAndEdgesFromTopologyData } from "@/app/(keep)/topology/ui/map/g
import { useIncidents } from "@/utils/hooks/useIncidents";
import { EdgeBase, Connection } from "@xyflow/system";
import { AddEditNodeSidePanel } from "./AddEditNodeSidePanel";
import { toast } from "react-toastify";
import { useApi } from "@/shared/lib/hooks/useApi";
import { DropdownMenu, EmptyStateCard, ErrorComponent } from "@/shared/ui";
import { downloadFileFromString } from "@/shared/ui/YAMLCodeblock/ui/YAMLCodeblock";
import {
DropdownMenu,
EmptyStateCard,
ErrorComponent,
showErrorToast,
showSuccessToast,
} from "@/shared/ui";
import { downloadFileFromString } from "@/shared/lib/downloadFileFromString";
import { PlusIcon } from "@heroicons/react/20/solid";
import { TbTopologyRing } from "react-icons/tb";

Expand Down Expand Up @@ -176,11 +181,11 @@ export function TopologyMap({
method: "POST",
body: formData,
});
toast.success("Topology imported Successfully!");
showSuccessToast("Topology imported Successfully!");
mutateApplications();
mutateTopologyData();
} catch (error) {
toast.error(`Error uploading file: ${error}`);
showErrorToast(error, "Error uploading file");
}
};

Expand Down Expand Up @@ -209,9 +214,13 @@ export function TopologyMap({
Accept: "application/x-yaml",
},
});
downloadFileFromString(response, "topology-export.yaml");
downloadFileFromString({
data: response,
filename: "topology-export.yaml",
contentType: "application/x-yaml",
});
} catch (error) {
console.log(error);
showErrorToast(error, "Error exporting topology");
}
},
},
Expand Down Expand Up @@ -270,7 +279,8 @@ export function TopologyMap({
} catch (error) {
const edgeIdToRevert = `xy-edge__${sourceService.id}right-${targetService.id}left`;
setEdges((eds) => eds.filter((e) => e.id !== edgeIdToRevert));
toast.error(
showErrorToast(
error,
`Error while adding connection from ${params.source} to ${params.target}: ${error}`
);
}
Expand Down Expand Up @@ -311,8 +321,9 @@ export function TopologyMap({
} catch (error) {
setEdges((eds) => eds.filter((e) => e.id !== oldEdge.id));
setEdges((eds) => addEdge(oldEdge, eds));
toast.error(
`Error while adding (re)connection from ${newConnection.source} to ${newConnection.target}: ${error}`
showErrorToast(
error,
`Error while adding (re)connection from ${newConnection.source} to ${newConnection.target}`
);
}
}
Expand Down Expand Up @@ -349,8 +360,9 @@ export function TopologyMap({
// setEdges((eds) => eds.filter((e) => e.id !== edge.id));
} catch (error) {
setEdges((eds) => addEdge(edge, eds));
toast.error(
`Failed to delete connection from ${edge.source} to ${edge.target}: ${error}`
showErrorToast(
error,
`Failed to delete connection from ${edge.source} to ${edge.target}`
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import WorkflowSecrets from "./workflow-secrets";
import { useConfig } from "utils/hooks/useConfig";
import { AiOutlineSwap } from "react-icons/ai";
import { ErrorComponent, TabNavigationLink } from "@/shared/ui";
import MonacoYAMLEditor from "@/shared/ui/YAMLCodeblock/ui/MonacoYAMLEditor";
import { WorkflowYAMLEditor } from "@/shared/ui";
import Skeleton from "react-loading-skeleton";
import { useRouter, useSearchParams } from "next/navigation";
import { useWorkflowDetail } from "@/utils/hooks/useWorkflowDetail";
import { WorkflowYAMLEditorStandalone } from "@/shared/ui/WorkflowYAMLEditor/ui/WorkflowYAMLEditorStandalone";
import { getOrderedWorkflowYamlString } from "@/entities/workflows/lib/yaml-utils";

export default function WorkflowDetailPage({
params,
Expand Down Expand Up @@ -129,12 +131,12 @@ export default function WorkflowDetailPage({
{!workflow ? (
<Skeleton className="w-full h-full" />
) : (
<Card className="h-[calc(100vh-12rem)] p-0 overflow-hidden">
<MonacoYAMLEditor
key={workflow.workflow_raw!}
workflowRaw={workflow.workflow_raw!}
filename={workflow.id ?? "workflow"}
<Card className="h-[calc(100vh-12rem)] p-0">
<WorkflowYAMLEditorStandalone
workflowId={workflow.id}
yamlString={getOrderedWorkflowYamlString(
workflow.workflow_raw!
)}
data-testid="wf-detail-yaml-editor"
/>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
import { EyeOff, Eye } from "lucide-react";
import { GenericTable } from "@/components/table/GenericTable";
import { DisplayColumnDef } from "@tanstack/react-table";
import { useSecrets } from "@/utils/hooks/useWorkFlowSecrets";
import { useWorkflowSecrets } from "@/utils/hooks/useWorkflowSecrets";
import { Button } from "@/components/ui";
import { Input } from "@/shared/ui";

const WorkflowSecrets = ({ workflowId }: { workflowId: string }) => {
const { getSecrets, error, addOrUpdateSecret, deleteSecret } =
useSecrets(workflowId);
useWorkflowSecrets(workflowId);
const [newSecret, setNewSecret] = useState({ name: "", value: "" });
const [showValues, setShowValues] = useState<Record<string, boolean>>({});
const { data: secrets, mutate: mutateSecrets } = getSecrets;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { useWorkflowStore } from "@/entities/workflows";
import { CloudIcon, ExclamationTriangleIcon } from "@heroicons/react/20/solid";
import { Tooltip } from "@/shared/ui";
import { useEffect } from "react";
import TimeAgo from "react-timeago";
import { useWorkflowEditorChangesSaved } from "@/entities/workflows/model/workflow-store";

export function WorkflowSyncStatus() {
const { isInitialized, lastDeployedAt } = useWorkflowStore();
const isChangesSaved = useWorkflowEditorChangesSaved();
interface WorkflowSyncStatusProps {
isInitialized: boolean;
lastDeployedAt: number | null;
isChangesSaved: boolean;
}

export function WorkflowSyncStatus({
isInitialized,
lastDeployedAt,
isChangesSaved,
}: WorkflowSyncStatusProps) {
useEffect(() => {
const handler = (e: BeforeUnloadEvent) => {
if (!isChangesSaved) {
Expand Down
1 change: 1 addition & 0 deletions keep-ui/entities/workflows/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { useWorkflowActions } from "./model/useWorkflowActions";
export { useWorkflowStore } from "./model/workflow-store";

export * from "./model/types";
export * from "./model/schema";
44 changes: 44 additions & 0 deletions keep-ui/entities/workflows/lib/__tests__/getCurrentPath.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { parseDocument } from "yaml";
import { getCurrentPath } from "../yaml-utils";

const yaml = `
workflow:
steps:
- name: step1
provider:
type: test
`;

describe("getCurrentPath", () => {
const doc = parseDocument(yaml);

it("should get nested path at provider.type field", () => {
// workflow:
// steps:
// - name: step1
// provider:
// type: t<cursor here>est
const path = getCurrentPath(doc, 69);
expect(path).toEqual(["workflow", "steps", 0, "provider", "type"]);
});

it("should get root path", () => {
// w<cursor here>orkflow:
// steps:
// - name: step1
// provider:
// type: test
const path = getCurrentPath(doc, 1);
expect(path).toEqual(["workflow"]);
});

it("should get nested path, at name field", () => {
// workflow:
// steps:
// - name<cursor here>: step1
// provider:
// type: test
const path = getCurrentPath(doc, 30);
expect(path).toEqual(["workflow", "steps", 0, "name"]);
});
});
Loading
Loading