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

chore(ux): better handle uploading of workflow #1907

Closed
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e119e52
feat: handle uploading of workflow via upload and show validation err…
rajesh-jonnalagadda Sep 12, 2024
4df4827
refactor: minor changes on workflow menu. add workflow validation error
rajesh-jonnalagadda Sep 12, 2024
242b370
chore: fix lint issues
rajesh-jonnalagadda Sep 12, 2024
7da5b95
chore: fix test case fail issues
rajesh-jonnalagadda Sep 12, 2024
60f3a28
chore:fix typo
rajesh-jonnalagadda Sep 12, 2024
cbd59c0
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 12, 2024
d02bc0e
refactor: minor style change on exection page using grid to make it m…
rajesh-jonnalagadda Sep 12, 2024
421a81a
Merge branch 'feat-1885-workflow-validators-enhance' of github.com:ra…
rajesh-jonnalagadda Sep 12, 2024
719f3d7
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 12, 2024
e634ef9
chore: fix filename typo
rajesh-jonnalagadda Sep 13, 2024
73dcadd
Merge branch 'feat-1885-workflow-validators-enhance' of github.com:ra…
rajesh-jonnalagadda Sep 13, 2024
05c4659
Merge branch 'main' into feat-1885-workflow-validators-enhance
shahargl Sep 14, 2024
7de35a7
refactor: add unit test cases for workflow creation and minor refact…
rajesh-jonnalagadda Sep 14, 2024
21fc1da
chore:minor validation refactor
rajesh-jonnalagadda Sep 14, 2024
eb3e204
Merge branch 'feat-1885-workflow-validators-enhance' of github.com:ra…
rajesh-jonnalagadda Sep 14, 2024
a7db7c9
chore: fix the test case fail issue
rajesh-jonnalagadda Sep 15, 2024
9bbc60f
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 15, 2024
e5d511d
chore;fix breaking test case issues
rajesh-jonnalagadda Sep 15, 2024
5a88ced
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 15, 2024
7f7ba21
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 15, 2024
4953aeb
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 15, 2024
91c90fd
chore:handle cli case while parsing
rajesh-jonnalagadda Sep 15, 2024
e133933
chore:remove unwanted log
rajesh-jonnalagadda Sep 15, 2024
f854343
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 15, 2024
0f811c2
Merge branch 'main' into feat-1885-workflow-validators-enhance
talboren Sep 16, 2024
9a24535
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 16, 2024
533add6
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 17, 2024
f690553
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 17, 2024
8cd6fbe
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 17, 2024
169c609
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 18, 2024
d7274b2
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 19, 2024
e3eacba
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 19, 2024
b86f6c1
chore:fixed the validators style issue
rajesh-jonnalagadda Sep 20, 2024
d3df1a5
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 22, 2024
2d3a4b0
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 22, 2024
ef2cafa
fix: handle feedback changes
rajesh-jonnalagadda Sep 22, 2024
24f4c8d
Merge branch 'feat-1885-workflow-validators-enhance' of github.com:ra…
rajesh-jonnalagadda Sep 22, 2024
121a083
chore:remove unwanted args
rajesh-jonnalagadda Sep 22, 2024
b92101a
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 22, 2024
f7701a3
fix: modified the add_or update logic
rajesh-jonnalagadda Sep 22, 2024
575aa94
Merge branch 'feat-1885-workflow-validators-enhance' of github.com:ra…
rajesh-jonnalagadda Sep 22, 2024
815f11f
Merge branch 'main' into feat-1885-workflow-validators-enhance
rajesh-jonnalagadda Sep 24, 2024
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
2 changes: 1 addition & 1 deletion keep-ui/app/workflows/[workflow_id]/executions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export default function WorkflowDetailPage({
const workflow = { last_executions: data.items } as Partial<Workflow>
return (
<>
<Card className="relative flex p-4 w-full gap-3">
<Card className="relative grid p-4 w-full gap-3 grid-cols-[1fr_4fr]">
shahargl marked this conversation as resolved.
Show resolved Hide resolved
<SideNavBar workflow={data.workflow} />
<div className="relative overflow-auto p-0.5 flex-1 flex-shrink-1">
<div className="sticky top-0 flex justify-between items-end">
Expand Down
2 changes: 1 addition & 1 deletion keep-ui/app/workflows/[workflow_id]/side-nav-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function SideNavBar({ workflow }: { workflow: Workflow }) {
];

return (
<div className="flex flex-col gap-10 pt-6 top-20 p-1 max-w-[270px]">
shahargl marked this conversation as resolved.
Show resolved Hide resolved
<div className="flex flex-col gap-10 pt-6 top-20 p-1">
<div className="h-36">
<h1 className="text-2xl line-clamp-2 font-extrabold">{workflow.name}</h1>
{workflow.description && (
Expand Down
2 changes: 1 addition & 1 deletion keep-ui/app/workflows/builder/builder-validators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function globalValidatorV2(
): boolean {
const workflowName = definition?.properties?.name;
const workflowDescription = definition?.properties?.description;
if(!workflowName) {
if(!workflowName || workflowName == "[No Workflow Name]") {
setGlobalValidationError(null, "Workflow name cannot be empty.");
return false;
}
Expand Down
13 changes: 9 additions & 4 deletions keep-ui/app/workflows/builder/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ export function generateWorkflow(

export function parseWorkflow(
workflowString: string,
providers: Provider[]
providers: Provider[],
isPureRaw: boolean = false
): Definition {
/**
* Parse the alert file and generate the definition
Expand All @@ -255,16 +256,20 @@ export function parseWorkflow(
schema: JSON_SCHEMA,
}) as any;
// This is to support both old and new structure of workflow
const workflow = parsedWorkflowFile.alert
let workflow = parsedWorkflowFile.alert
? parsedWorkflowFile.alert
: parsedWorkflowFile.workflow;

if(isPureRaw) {
workflow = parsedWorkflowFile
}
const steps = [] as V2Step[];
const workflowSteps =
workflow.steps?.map((s: V2Step) => {
workflow?.steps?.map((s: V2Step) => {
s.type = "step";
return s;
}) || [];
const workflowActions = workflow.actions || [];
const workflowActions = workflow?.actions || [];
const conditions = [] as any;
[...workflowSteps, ...workflowActions].forEach((action: any) => {
const stepOrAction = action.type === "step" ? "step" : "action";
Expand Down
92 changes: 56 additions & 36 deletions keep-ui/app/workflows/workflow-tile.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"use client";

import { useSession } from "next-auth/react";
import { Workflow, Filter } from "./models";
import { Workflow, Provider, Trigger } from './models';
import { getApiURL } from "../../utils/apiUrl";
import Image from "next/image";
import React, { useState, useMemo } from "react";
import { useRouter } from "next/navigation";
import WorkflowMenu from "./workflow-menu";
import Loading from "../loading";
import { Trigger, Provider } from "./models";
import {
Button,
Text,
Expand All @@ -21,13 +20,13 @@ import {
AccordionBody,
AccordionHeader,
Badge,
Callout,
} from "@tremor/react";
import ProviderForm from "app/providers/provider-form";
import SlidingPanel from "react-sliding-side-panel";
import { useFetchProviders } from "app/providers/page.client";
import { Provider as FullProvider } from "app/providers/providers";
import "./workflow-tile.css";
import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/outline";
import { CheckCircleIcon, ExclamationCircleIcon, XCircleIcon } from "@heroicons/react/24/outline";
import AlertTriggerModal from "./workflow-run-with-alert-modal";
import { formatDistanceToNowStrict } from "date-fns";
import TimeAgo, { Formatter, Suffix, Unit } from "react-timeago";
Expand All @@ -40,7 +39,9 @@ import {
MdOutlineKeyboardArrowLeft,
} from "react-icons/md";
import { HiBellAlert } from "react-icons/hi2";
import { BiSolidError } from "react-icons/bi";
import { useWorkflowRun } from "utils/hooks/useWorkflowRun";
import useWorkflowValidator from "utils/hooks/useWorkflowValidator";

function WorkflowMenuSection({
onDelete,
Expand Down Expand Up @@ -263,7 +264,7 @@ export const ProvidersCarousel = ({
);
};

function WorkflowTile({ workflow }: { workflow: Workflow }) {
function WorkflowTile({ workflow , providers}: { workflow: Workflow , providers: FullProvider[]}) {
// Create a set to keep track of unique providers
const apiUrl = getApiURL();
const { data: session } = useSession();
Expand All @@ -281,7 +282,7 @@ function WorkflowTile({ workflow }: { workflow: Workflow }) {
?.filters?.find((f) => f.key === "source")?.value;
const [fallBackIcon, setFallBackIcon] = useState(false);

const { providers } = useFetchProviders();

const {
isRunning,
handleRunClick,
Expand All @@ -290,6 +291,9 @@ function WorkflowTile({ workflow }: { workflow: Workflow }) {
message,
} = useWorkflowRun(workflow!);

const { loading, isValid, error } = useWorkflowValidator(workflow, providers || null);


const handleConnectProvider = (provider: FullProvider) => {
setSelectedProvider(provider);
// prepopulate it with the name
Expand Down Expand Up @@ -382,7 +386,7 @@ function WorkflowTile({ workflow }: { workflow: Workflow }) {
)
.map((type) => {
let fullProvider =
providers.find((fp) => fp.type === type) || ({} as FullProvider);
providers?.find((fp) => fp.type === type) || ({} as FullProvider);
let workflowProvider =
workflowProvidersMap.get(type) || ({} as FullProvider);

Expand Down Expand Up @@ -544,14 +548,14 @@ function WorkflowTile({ workflow }: { workflow: Workflow }) {
};

return (
<div className="mt-2.5">
<div className="realtive mt-2.5">
{isRunning && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
<Loading />
</div>
)}
<Card
className="relative flex flex-col justify-between bg-white rounded shadow p-2 h-full hover:border-orange-400 hover:border-2 overflow-hidden"
className="relative flex flex-col justify-between bg-white rounded shadow p-2 h-full hover:border-orange-400 hover:border-2"
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
Expand All @@ -560,23 +564,30 @@ function WorkflowTile({ workflow }: { workflow: Workflow }) {
}
}}
>
{!loading && !isValid && <div className="relative group"><BiSolidError className="absolute top-[-25px] right-[-25px] text-red-500" size={32} />
<Callout
className="mt-2.5 mb-2.5 absolute top-[-90px] right-5 scale-0 rounded bg-gray-800 text-xs text-white group-hover:scale-100"
title="Validation Error"
icon={ExclamationCircleIcon}
>{error}</Callout>

</div>}
<div className="absolute top-0 right-0 mt-2 mr-2 mb-2 flex items-center flex-wrap">
{workflow.provisioned && (
<Badge color="orange" size="xs" className="mr-2 mb-2">
Provisioned
</Badge>
)}
{!!handleRunClick &&
WorkflowMenuSection({
onDelete: handleDeleteClick,
onRun: handleRunClick,
onDownload: handleDownloadClick,
onView: handleViewClick,
onBuilder: handleBuilderClick,
runButtonToolTip: message,
isRunButtonDisabled: !!isRunButtonDisabled,
provisioned: workflow.provisioned,
})}
{!!handleRunClick && WorkflowMenuSection({
onDelete: handleDeleteClick,
onRun: handleRunClick,
onDownload: handleDownloadClick,
onView: handleViewClick,
onBuilder: handleBuilderClick,
runButtonToolTip: message || error || "",
isRunButtonDisabled: !!isRunButtonDisabled || !isValid,
provisioned: workflow.provisioned,
})}
</div>
<div className="m-2 flex flex-col justify-around item-start flex-wrap">
<WorkflowGraph workflow={workflow} />
Expand Down Expand Up @@ -718,7 +729,7 @@ function WorkflowTile({ workflow }: { workflow: Workflow }) {
);
}

export function WorkflowTileOld({ workflow }: { workflow: Workflow }) {
export function WorkflowTileOld({ workflow, providers }: { workflow: Workflow, providers: FullProvider[] }) {
// Create a set to keep track of unique providers
const apiUrl = getApiURL();
const { data: session } = useSession();
Expand All @@ -730,7 +741,7 @@ export function WorkflowTileOld({ workflow }: { workflow: Workflow }) {
const [formValues, setFormValues] = useState<{ [key: string]: string }>({});
const [formErrors, setFormErrors] = useState<{ [key: string]: string }>({});

const { providers } = useFetchProviders();

const {
isRunning,
handleRunClick,
Expand All @@ -739,6 +750,9 @@ export function WorkflowTileOld({ workflow }: { workflow: Workflow }) {
getTriggerModalProps,
} = useWorkflowRun(workflow!);

const { loading, isValid, error } = useWorkflowValidator(workflow, providers || null);


const handleConnectProvider = (provider: FullProvider) => {
setSelectedProvider(provider);
// prepopulate it with the name
Expand Down Expand Up @@ -831,7 +845,7 @@ export function WorkflowTileOld({ workflow }: { workflow: Workflow }) {
)
.map((type) => {
let fullProvider =
providers.find((fp) => fp.type === type) || ({} as FullProvider);
providers?.find((fp) => fp.type === type) || ({} as FullProvider);
let workflowProvider =
workflowProvidersMap.get(type) || ({} as FullProvider);

Expand All @@ -858,22 +872,28 @@ export function WorkflowTileOld({ workflow }: { workflow: Workflow }) {
<Loading />
</div>
)}
<Card>
<div className="flex w-full justify-between items-center h-14">
<Card className="relative">
{!loading && !isValid && <div className="relative group"><BiSolidError className="absolute top-[-40px] right-[-35px] text-red-500" size={32} />
<Callout
className="mt-2.5 mb-2.5 absolute top-[-100px] right-5 scale-0 rounded bg-gray-800 text-xs text-white group-hover:scale-100"
title="Validation Error"
icon={ExclamationCircleIcon}
>{error}</Callout>

</div>} <div className="flex w-full justify-between items-center h-14">
<Title className="truncate max-w-64 text-left text-lightBlack">
{workflow.name}
</Title>
{!!handleRunClick &&
WorkflowMenuSection({
onDelete: handleDeleteClick,
onRun: handleRunClick,
onDownload: handleDownloadClick,
onView: handleViewClick,
onBuilder: handleBuilderClick,
runButtonToolTip: message,
isRunButtonDisabled: !!isRunButtonDisabled,
provisioned: workflow.provisioned,
})}
{!!handleRunClick && WorkflowMenuSection({
onDelete: handleDeleteClick,
onRun: handleRunClick,
onDownload: handleDownloadClick,
onView: handleViewClick,
onBuilder: handleBuilderClick,
runButtonToolTip: message || error || "",
isRunButtonDisabled: !!isRunButtonDisabled || !isValid,
provisioned: workflow.provisioned,
})}
</div>

<div className="flex items-center justify-between h-10">
Expand Down
8 changes: 6 additions & 2 deletions keep-ui/app/workflows/workflows.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { ArrowRightIcon } from "@radix-ui/react-icons";
import { useRouter } from "next/navigation";
import Modal from "@/components/ui/Modal";
import MockWorkflowCardSection from "./mockworkflows";
import { useFetchProviders } from "app/providers/page.client";

export default function WorkflowsPage() {
const apiUrl = getApiURL();
Expand Down Expand Up @@ -51,6 +52,9 @@ export default function WorkflowsPage() {
(url: string) => fetcher(url, session?.accessToken!)
);

const { providers } = useFetchProviders();


/**
Add Mock Workflows (6 Random Workflows on Every Request)
To add mock workflows, a new backend API endpoint has been created: /workflows/random-templates.
Expand Down Expand Up @@ -299,13 +303,13 @@ export default function WorkflowsPage() {
) : !isSwitchOn ? (
<div className="flex flex-wrap gap-2">
{data.map((workflow) => (
<WorkflowTileOld key={workflow.id} workflow={workflow} />
<WorkflowTileOld key={workflow.id} workflow={workflow} providers={providers}/>
))}
</div>
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 w-full gap-4 p-4">
{data.map((workflow) => (
<WorkflowTile key={workflow.id} workflow={workflow} />
<WorkflowTile key={workflow.id} workflow={workflow} providers={providers}/>
))}
</div>
)}
Expand Down
13 changes: 11 additions & 2 deletions keep-ui/utils/hooks/useWorkflowInitialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { FlowNode } from "../../app/workflows/builder/builder-store";
import { Provider } from "app/providers/providers";
import ELK from 'elkjs/lib/elk.bundled.js';
import { processWorkflowV2, getTriggerStep } from "utils/reactFlow";
import { validate as isUUID } from 'uuid';

const layoutOptions = {
"elk.nodeLabels.placement": "INSIDE V_CENTER H_BOTTOM",
Expand Down Expand Up @@ -175,8 +176,15 @@ const useWorkflowInitialization = (
const initializeWorkflow = async () => {
setIsLoading(true);
let parsedWorkflow = definition?.value;
const name = parsedWorkflow?.properties?.name || parsedWorkflow?.properties?.id;

let name = parsedWorkflow?.properties?.name
if(!name) {
name = !isUUID(parsedWorkflow?.properties?.id)
? parsedWorkflow?.properties?.id
: "";
}
if(name === '[No Workflow Name]'){
name = '';
}
const sequences = [
{
id: "start",
Expand All @@ -199,6 +207,7 @@ const useWorkflowInitialization = (
];
const intialPositon = { x: 0, y: 50 };
let { nodes, edges } = processWorkflowV2(sequences, intialPositon, true);
//TO DO update all the flow data at one go instead of one by one
setSelectedNode(null);
setFirstInitilisationDone(false)
setIsLayouted(false);
Expand Down
Loading
Loading