From 563f20bde656b4f3a9ebd9bee2417f9e59263a45 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Tue, 7 Feb 2023 20:07:02 +0000 Subject: [PATCH] add variable and builder pages --- Common/Types/Icon/IconProp.ts | 1 + CommonUI/src/Components/Icon/Icon.tsx | 6 + Dashboard/src/Pages/Workflow/Logs.tsx | 83 ++++++++++ Dashboard/src/Pages/Workflow/Variable.tsx | 135 +++++++++++++++ Dashboard/src/Pages/Workflow/View/Logs.tsx | 49 +++++- .../src/Pages/Workflow/View/Variable.tsx | 154 ++++++++++++++++++ Dashboard/src/Pages/Workflow/Workflows.tsx | 2 +- Dashboard/src/Utils/PageMap.ts | 2 + Dashboard/src/Utils/RouteMap.ts | 10 +- 9 files changed, 439 insertions(+), 3 deletions(-) create mode 100644 Dashboard/src/Pages/Workflow/Logs.tsx create mode 100644 Dashboard/src/Pages/Workflow/Variable.tsx create mode 100644 Dashboard/src/Pages/Workflow/View/Variable.tsx diff --git a/Common/Types/Icon/IconProp.ts b/Common/Types/Icon/IconProp.ts index 225e634104..9ab6d6b0ab 100644 --- a/Common/Types/Icon/IconProp.ts +++ b/Common/Types/Icon/IconProp.ts @@ -17,6 +17,7 @@ enum IconProp { Public = 'Public', Home = 'Home', Graph = 'Graph', + Variable = 'Variable', Image = 'Image', Grid = 'Grid', More = 'More', diff --git a/CommonUI/src/Components/Icon/Icon.tsx b/CommonUI/src/Components/Icon/Icon.tsx index 1e9e5a5c5a..a07d8ddcd2 100644 --- a/CommonUI/src/Components/Icon/Icon.tsx +++ b/CommonUI/src/Components/Icon/Icon.tsx @@ -154,6 +154,12 @@ const Icon: FunctionComponent = ({ d="M12 20.25c4.97 0 9-3.694 9-8.25s-4.03-8.25-9-8.25S3 7.444 3 12c0 2.104.859 4.023 2.273 5.48.432.447.74 1.04.586 1.641a4.483 4.483 0 01-.923 1.785A5.969 5.969 0 006 21c1.282 0 2.47-.402 3.445-1.087.81.22 1.668.337 2.555.337z" /> ); + } else if (icon === IconProp.Variable) { + return getSvgWrapper( + + + + ); } else if (icon === IconProp.Workflow) { return getSvgWrapper( = ( + _props: PageComponentProps +): ReactElement => { + return ( + + + modelType={WorkflowLogs} + id="workflow-logs-table" + isDeleteable={false} + isEditable={false} + isCreateable={false} + name="Workflow Logs" + isViewable={false} + cardProps={{ + icon: IconProp.Logs, + title: 'Workflow Logs', + description: + 'List of logs in the last 30 days for all your workflows', + }} + noItemsMessage={'Looks like no workflow ran so far in the last 30 days.'} + showRefreshButton={true} + showFilterButton={true} + viewPageRoute={Navigation.getCurrentRoute()} + columns={[ + { + field: { + workflow: { + name: true + }, + }, + title: 'Workflow Name', + type: FieldType.Text, + isFilterable: true, + }, + { + field: { + createdAt: true, + }, + title: 'Logs Created At', + type: FieldType.DateTime, + isFilterable: true, + }, + ]} + /> + + ); +}; + +export default Workflows; diff --git a/Dashboard/src/Pages/Workflow/Variable.tsx b/Dashboard/src/Pages/Workflow/Variable.tsx new file mode 100644 index 0000000000..11ea61a517 --- /dev/null +++ b/Dashboard/src/Pages/Workflow/Variable.tsx @@ -0,0 +1,135 @@ +import Route from 'Common/Types/API/Route'; +import Page from 'CommonUI/src/Components/Page/Page'; +import React, { FunctionComponent, ReactElement } from 'react'; +import PageMap from '../../Utils/PageMap'; +import RouteMap, { RouteUtil } from '../../Utils/RouteMap'; +import PageComponentProps from '../PageComponentProps'; +import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable'; +import WorkflowVariable from 'Model/Models/WorkflowVariable'; +import FieldType from 'CommonUI/src/Components/Types/FieldType'; +import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType'; +import { IconProp } from 'CommonUI/src/Components/Icon/Icon'; +import Navigation from 'CommonUI/src/Utils/Navigation'; +import DashboardNavigation from '../../Utils/Navigation'; + +const Workflows: FunctionComponent = ( + _props: PageComponentProps +): ReactElement => { + return ( + + + modelType={WorkflowVariable} + id="status-page-table" + isDeleteable={false} + isEditable={false} + isCreateable={true} + name="Workflows" + isViewable={false} + cardProps={{ + icon: IconProp.Variable, + title: 'Global Variables', + description: + 'Here is a list of global secrets and variables for this project.', + }} + query={{ + workflowId: null, + projectId: DashboardNavigation.getProjectId()?.toString(), + }} + noItemsMessage={'No workflows found.'} + formFields={[ + { + field: { + name: true, + }, + title: 'Name', + fieldType: FormFieldSchemaType.Text, + required: true, + placeholder: 'Workflow Name', + validation: { + minLength: 2, + }, + }, + { + field: { + description: true, + }, + title: 'Description', + fieldType: FormFieldSchemaType.LongText, + required: true, + placeholder: 'Description', + }, + { + field: { + isSecret: true, + }, + title: 'Secret', + description: "Is this variable secret or secure? Should this be encrypted in the Database?", + fieldType: FormFieldSchemaType.Checkbox, + required: true, + }, + { + field: { + content: true, + }, + title: 'Content', + description: "Is this variable secret or secure? Should this be encrypted in the Database?", + fieldType: FormFieldSchemaType.Checkbox, + required: true, + }, + ]} + showRefreshButton={true} + showFilterButton={true} + columns={[ + { + field: { + name: true, + }, + title: 'Name', + type: FieldType.Text, + isFilterable: true, + }, + { + field: { + description: true, + }, + title: 'Description', + type: FieldType.Text, + isFilterable: true, + }, + { + field: { + createdAt: true, + }, + title: 'Created At', + type: FieldType.DateTime, + isFilterable: true, + }, + ]} + /> + + ); +}; + +export default Workflows; diff --git a/Dashboard/src/Pages/Workflow/View/Logs.tsx b/Dashboard/src/Pages/Workflow/View/Logs.tsx index b8e49a9665..48a999ac73 100644 --- a/Dashboard/src/Pages/Workflow/View/Logs.tsx +++ b/Dashboard/src/Pages/Workflow/View/Logs.tsx @@ -7,6 +7,11 @@ import PageComponentProps from '../../PageComponentProps'; import SideMenu from './SideMenu'; import Navigation from 'CommonUI/src/Utils/Navigation'; import ObjectID from 'Common/Types/ObjectID'; +import FieldType from 'CommonUI/src/Components/Types/FieldType'; +import { IconProp } from 'CommonUI/src/Components/Icon/Icon'; +import WorkflowLogs from 'Model/Models/WorkflowLog'; +import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable'; +import DashboardNavigation from '../../../Utils/Navigation'; const Delete: FunctionComponent = ( _props: PageComponentProps @@ -48,7 +53,49 @@ const Delete: FunctionComponent = ( ]} sideMenu={} > -
+ + modelType={WorkflowLogs} + id="workflow-logs-table" + isDeleteable={false} + isEditable={false} + isCreateable={false} + name="Workflow Logs" + query={{ + workflowId: modelId, + projectId: DashboardNavigation.getProjectId()?.toString(), + }} + isViewable={false} + cardProps={{ + icon: IconProp.Logs, + title: 'Workflow Logs', + description: + 'List of logs in the last 30 days for this workflow', + }} + noItemsMessage={'Looks like this workflow did not run so far in the last 30 days.'} + showRefreshButton={true} + showFilterButton={true} + viewPageRoute={Navigation.getCurrentRoute()} + columns={[ + { + field: { + workflow: { + name: true + }, + }, + title: 'Workflow Name', + type: FieldType.Text, + isFilterable: true, + }, + { + field: { + createdAt: true, + }, + title: 'Logs Created At', + type: FieldType.DateTime, + isFilterable: true, + }, + ]} + /> ); }; diff --git a/Dashboard/src/Pages/Workflow/View/Variable.tsx b/Dashboard/src/Pages/Workflow/View/Variable.tsx new file mode 100644 index 0000000000..9c911ec91b --- /dev/null +++ b/Dashboard/src/Pages/Workflow/View/Variable.tsx @@ -0,0 +1,154 @@ +import Route from 'Common/Types/API/Route'; +import Page from 'CommonUI/src/Components/Page/Page'; +import React, { FunctionComponent, ReactElement } from 'react'; +import PageMap from '../../../Utils/PageMap'; +import RouteMap, { RouteUtil } from '../../../Utils/RouteMap'; +import PageComponentProps from '../../PageComponentProps'; +import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable'; +import WorkflowVariable from 'Model/Models/WorkflowVariable'; +import FieldType from 'CommonUI/src/Components/Types/FieldType'; +import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType'; +import { IconProp } from 'CommonUI/src/Components/Icon/Icon'; +import Navigation from 'CommonUI/src/Utils/Navigation'; +import DashboardNavigation from '../../../Utils/Navigation'; +import ObjectID from 'Common/Types/ObjectID'; + +const Workflows: FunctionComponent = ( + _props: PageComponentProps +): ReactElement => { + + const modelId: ObjectID = Navigation.getLastParamAsObjectID(1); + + return ( + + + modelType={WorkflowVariable} + id="status-page-table" + isDeleteable={false} + isEditable={false} + isCreateable={true} + name="Workflows" + isViewable={false} + cardProps={{ + icon: IconProp.Variable, + title: 'Global Variables', + description: + 'Here is a list of global secrets and variables for this project.', + }} + query={{ + workflowId: modelId, + projectId: DashboardNavigation.getProjectId()?.toString(), + }} + onBeforeCreate={( + item: WorkflowVariable + ): Promise => { + item.workflowId = modelId; + item.projectId = DashboardNavigation.getProjectId()!; + return Promise.resolve(item); + }} + noItemsMessage={'No workflows found.'} + formFields={[ + { + field: { + name: true, + }, + title: 'Name', + fieldType: FormFieldSchemaType.Text, + required: true, + placeholder: 'Workflow Name', + validation: { + minLength: 2, + }, + }, + { + field: { + description: true, + }, + title: 'Description', + fieldType: FormFieldSchemaType.LongText, + required: true, + placeholder: 'Description', + }, + { + field: { + isSecret: true, + }, + title: 'Secret', + description: "Is this variable secret or secure? Should this be encrypted in the Database?", + fieldType: FormFieldSchemaType.Checkbox, + required: true, + }, + { + field: { + content: true, + }, + title: 'Content', + description: "Is this variable secret or secure? Should this be encrypted in the Database?", + fieldType: FormFieldSchemaType.Checkbox, + required: true, + }, + ]} + showRefreshButton={true} + showFilterButton={true} + columns={[ + { + field: { + name: true, + }, + title: 'Name', + type: FieldType.Text, + isFilterable: true, + }, + { + field: { + description: true, + }, + title: 'Description', + type: FieldType.Text, + isFilterable: true, + }, + { + field: { + createdAt: true, + }, + title: 'Created At', + type: FieldType.DateTime, + isFilterable: true, + }, + ]} + /> + + ); +}; + +export default Workflows; diff --git a/Dashboard/src/Pages/Workflow/Workflows.tsx b/Dashboard/src/Pages/Workflow/Workflows.tsx index c07fb2bcc2..3ccdb3705e 100644 --- a/Dashboard/src/Pages/Workflow/Workflows.tsx +++ b/Dashboard/src/Pages/Workflow/Workflows.tsx @@ -27,7 +27,7 @@ const Workflows: FunctionComponent = ( { title: 'Workflows', to: RouteUtil.populateRouteParams( - RouteMap[PageMap.STATUS_PAGES] as Route + RouteMap[PageMap.WORKFLOWS] as Route ), }, ]} diff --git a/Dashboard/src/Utils/PageMap.ts b/Dashboard/src/Utils/PageMap.ts index 17f66a492e..2acbb58fa0 100644 --- a/Dashboard/src/Utils/PageMap.ts +++ b/Dashboard/src/Utils/PageMap.ts @@ -101,6 +101,8 @@ enum PageMap { // WORKFLOW WORKFLOWS = 'WORKFLOWS', + WORKFLOWS_LOGS = 'WORKFLOWS_LOGS', + WORKFLOWS_VARIABLES = 'WORKFLOWS_VARIABLES', WORKFLOW_VIEW = 'WORKFLOW_VIEW', WORKFLOW_DELETE = 'WORKFLOW_DELETE', WORKFLOW_BUILDER = 'WORKFLOW_BUILDER', diff --git a/Dashboard/src/Utils/RouteMap.ts b/Dashboard/src/Utils/RouteMap.ts index e83eccac33..89f7a0427e 100644 --- a/Dashboard/src/Utils/RouteMap.ts +++ b/Dashboard/src/Utils/RouteMap.ts @@ -265,6 +265,14 @@ const RouteMap: Dictionary = { `/dashboard/${RouteParams.ProjectID}/workflows` ), + [PageMap.WORKFLOWS_LOGS]: new Route( + `/dashboard/${RouteParams.ProjectID}/workflows/logs` + ), + + [PageMap.WORKFLOWS_VARIABLES]: new Route( + `/dashboard/${RouteParams.ProjectID}/workflows/variables` + ), + [PageMap.WORKFLOW_BUILDER]: new Route( `/dashboard/${RouteParams.ProjectID}/workflows/${RouteParams.ModelID}/builder` ), @@ -290,7 +298,7 @@ export class RouteUtil { if ( route.toString() === RouteMap[PageMap.USER_PROFILE]?.toString() || route.toString() === - RouteMap[PageMap.PROJECT_INVITATIONS]?.toString() || + RouteMap[PageMap.PROJECT_INVITATIONS]?.toString() || route.toString() === RouteMap[PageMap.ACTIVE_INCIDENTS]?.toString() ) { return true;