mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
fix workflow variable bugs
This commit is contained in:
@@ -8,6 +8,11 @@ import Icon, { IconType, SizeProp, ThickProp } from '../Icon/Icon';
|
||||
import IconProp from 'Common/Types/Icon/IconProp';
|
||||
import { VeryLightGrey } from 'Common/Types/BrandColors';
|
||||
|
||||
export enum ModalWidth {
|
||||
Normal,
|
||||
Large
|
||||
}
|
||||
|
||||
export interface ComponentProps {
|
||||
title: string;
|
||||
description?: string | undefined;
|
||||
@@ -23,6 +28,7 @@ export interface ComponentProps {
|
||||
isBodyLoading?: boolean | undefined;
|
||||
icon?: IconProp | undefined;
|
||||
iconType?: IconType | undefined;
|
||||
modalWidth?: ModalWidth | undefined
|
||||
}
|
||||
|
||||
const Modal: FunctionComponent<ComponentProps> = (
|
||||
@@ -51,7 +57,7 @@ const Modal: FunctionComponent<ComponentProps> = (
|
||||
|
||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
||||
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
||||
<div className="relative transform rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
|
||||
<div className={`relative transform rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full ${props.modalWidth && props.modalWidth === ModalWidth.Large ? "sm:max-w-7xl" : "sm:max-w-lg"} `}>
|
||||
{props.onClose && (
|
||||
<div className="absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
|
||||
<Button
|
||||
@@ -85,9 +91,8 @@ const Modal: FunctionComponent<ComponentProps> = (
|
||||
)}
|
||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:mr-4 sm:text-left">
|
||||
<h3
|
||||
className={`text-lg font-medium leading-6 text-gray-900 ${
|
||||
props.icon ? 'ml-10 -mt-8 mb-5' : ''
|
||||
}`}
|
||||
className={`text-lg font-medium leading-6 text-gray-900 ${props.icon ? 'ml-10 -mt-8 mb-5' : ''
|
||||
}`}
|
||||
id="modal-title"
|
||||
>
|
||||
{props.title}
|
||||
|
||||
@@ -64,14 +64,14 @@ export enum ShowTableAs {
|
||||
}
|
||||
|
||||
export interface ComponentProps<TBaseModel extends BaseModel> {
|
||||
modelType: { new (): TBaseModel };
|
||||
modelType: { new(): TBaseModel };
|
||||
id: string;
|
||||
onFetchInit?:
|
||||
| undefined
|
||||
| ((pageNumber: number, itemsOnPage: number) => void);
|
||||
| undefined
|
||||
| ((pageNumber: number, itemsOnPage: number) => void);
|
||||
onFetchSuccess?:
|
||||
| undefined
|
||||
| ((data: Array<TBaseModel>, totalCount: number) => void);
|
||||
| undefined
|
||||
| ((data: Array<TBaseModel>, totalCount: number) => void);
|
||||
cardProps?: CardComponentProps | undefined;
|
||||
columns: Columns<TBaseModel>;
|
||||
selectMoreFields?: Select<TBaseModel>;
|
||||
@@ -203,8 +203,8 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
alignItem: column.alignItem,
|
||||
getElement: column.getElement
|
||||
? (item: JSONObject): ReactElement => {
|
||||
return column.getElement!(item, onBeforeFetchData);
|
||||
}
|
||||
return column.getElement!(item, onBeforeFetchData);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
@@ -236,7 +236,7 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
try {
|
||||
setErrorModalText(
|
||||
(err as HTTPErrorResponse).message ||
|
||||
'Server Error. Please try again'
|
||||
'Server Error. Please try again'
|
||||
);
|
||||
} catch (e) {
|
||||
setErrorModalText('Server Error. Please try again');
|
||||
@@ -349,7 +349,7 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
try {
|
||||
setTableFilterError(
|
||||
(err as HTTPErrorResponse).message ||
|
||||
'Server Error. Please try again'
|
||||
'Server Error. Please try again'
|
||||
);
|
||||
} catch (e) {
|
||||
setTableFilterError('Server Error. Please try again');
|
||||
@@ -385,8 +385,8 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
getSelect(),
|
||||
sortBy
|
||||
? {
|
||||
[sortBy as any]: sortOrder,
|
||||
}
|
||||
[sortBy as any]: sortOrder,
|
||||
}
|
||||
: {},
|
||||
getPopulate(),
|
||||
props.fetchRequestOptions
|
||||
@@ -398,7 +398,7 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
try {
|
||||
setError(
|
||||
(err as HTTPErrorResponse).message ||
|
||||
'Server Error. Please try again'
|
||||
'Server Error. Please try again'
|
||||
);
|
||||
} catch (e) {
|
||||
setError('Server Error. Please try again');
|
||||
@@ -511,9 +511,8 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
showTableAs !== ShowTableAs.OrderedStatesList
|
||||
) {
|
||||
headerbuttons.push({
|
||||
title: `${props.createVerb || 'Create'} ${
|
||||
props.singularName || model.singularName
|
||||
}`,
|
||||
title: `${props.createVerb || 'Create'} ${props.singularName || model.singularName
|
||||
}`,
|
||||
buttonStyle: ButtonStyleType.NORMAL,
|
||||
className:
|
||||
props.showFilterButton || props.showRefreshButton
|
||||
@@ -730,10 +729,10 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
PermissionUtil.getAllPermissions();
|
||||
|
||||
if (
|
||||
permissions &&
|
||||
((props.isDeleteable && model.hasDeletePermissions(permissions)) ||
|
||||
(props.isEditable && model.hasUpdatePermissions(permissions)) ||
|
||||
(props.isViewable && model.hasReadPermissions(permissions)))
|
||||
(permissions &&
|
||||
((props.isDeleteable && model.hasDeletePermissions(permissions)) ||
|
||||
(props.isEditable && model.hasUpdatePermissions(permissions)) ||
|
||||
(props.isViewable && model.hasReadPermissions(permissions)))) || (props.actionButtons && props.actionButtons.length > 0)
|
||||
) {
|
||||
columns.push({
|
||||
title: 'Actions',
|
||||
@@ -1000,9 +999,9 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
|
||||
let getTitleElement:
|
||||
| ((
|
||||
item: JSONObject,
|
||||
onBeforeFetchData?: JSONObject | undefined
|
||||
) => ReactElement)
|
||||
item: JSONObject,
|
||||
onBeforeFetchData?: JSONObject | undefined
|
||||
) => ReactElement)
|
||||
| undefined = undefined;
|
||||
let getDescriptionElement:
|
||||
| ((item: JSONObject) => ReactElement)
|
||||
@@ -1046,10 +1045,10 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
onCreateNewItem={
|
||||
props.isCreateable
|
||||
? (order: number) => {
|
||||
setOrderedStatesListNewItemOrder(order);
|
||||
setModalType(ModalType.Create);
|
||||
setShowModal(true);
|
||||
}
|
||||
setOrderedStatesListNewItemOrder(order);
|
||||
setModalType(ModalType.Create);
|
||||
setShowModal(true);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
singularLabel={
|
||||
@@ -1114,9 +1113,8 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
}}
|
||||
>
|
||||
<Pill
|
||||
text={`${
|
||||
new props.modelType().readBillingPlan
|
||||
} Plan`}
|
||||
text={`${new props.modelType().readBillingPlan
|
||||
} Plan`}
|
||||
color={Yellow}
|
||||
/>
|
||||
</span>
|
||||
@@ -1190,19 +1188,16 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
<ModelFormModal<TBaseModel>
|
||||
title={
|
||||
modalType === ModalType.Create
|
||||
? `${props.createVerb || 'Create'} New ${
|
||||
props.singularName || model.singularName
|
||||
}`
|
||||
? `${props.createVerb || 'Create'} New ${props.singularName || model.singularName
|
||||
}`
|
||||
: `Edit ${props.singularName || model.singularName}`
|
||||
}
|
||||
name={
|
||||
modalType === ModalType.Create
|
||||
? `${props.name} > ${
|
||||
props.createVerb || 'Create'
|
||||
} New ${props.singularName || model.singularName}`
|
||||
: `${props.name} > Edit ${
|
||||
props.singularName || model.singularName
|
||||
}`
|
||||
? `${props.name} > ${props.createVerb || 'Create'
|
||||
} New ${props.singularName || model.singularName}`
|
||||
: `${props.name} > Edit ${props.singularName || model.singularName
|
||||
}`
|
||||
}
|
||||
initialValues={
|
||||
modalType === ModalType.Create
|
||||
@@ -1214,9 +1209,8 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
}}
|
||||
submitButtonText={
|
||||
modalType === ModalType.Create
|
||||
? `${props.createVerb || 'Create'} ${
|
||||
props.singularName || model.singularName
|
||||
}`
|
||||
? `${props.createVerb || 'Create'} ${props.singularName || model.singularName
|
||||
}`
|
||||
: `Save Changes`
|
||||
}
|
||||
onSuccess={async (item: TBaseModel) => {
|
||||
|
||||
@@ -82,7 +82,7 @@ const TableRow: FunctionComponent<ComponentProps> = (
|
||||
props.item[column.key] ? (
|
||||
OneUptimeDate.getDateAsLocalFormattedString(
|
||||
props.item[
|
||||
column.key
|
||||
column.key
|
||||
] as string,
|
||||
true
|
||||
)
|
||||
@@ -90,11 +90,11 @@ const TableRow: FunctionComponent<ComponentProps> = (
|
||||
''
|
||||
)
|
||||
) : column.type ===
|
||||
FieldType.DateTime ? (
|
||||
FieldType.DateTime ? (
|
||||
props.item[column.key] ? (
|
||||
OneUptimeDate.getDateAsLocalFormattedString(
|
||||
props.item[
|
||||
column.key
|
||||
column.key
|
||||
] as string,
|
||||
false
|
||||
)
|
||||
@@ -102,10 +102,10 @@ const TableRow: FunctionComponent<ComponentProps> = (
|
||||
''
|
||||
)
|
||||
) : column.type ===
|
||||
FieldType.Boolean ? (
|
||||
FieldType.Boolean ? (
|
||||
props.item[column.key] ? (
|
||||
<Icon
|
||||
icon={IconProp.CheckCircle}
|
||||
icon={IconProp.Check}
|
||||
className={
|
||||
'h-5 w-5 text-gray-500'
|
||||
}
|
||||
@@ -183,7 +183,7 @@ const TableRow: FunctionComponent<ComponentProps> = (
|
||||
}
|
||||
isLoading={
|
||||
isButtonLoading[
|
||||
i
|
||||
i
|
||||
]
|
||||
}
|
||||
onClick={() => {
|
||||
|
||||
42
Dashboard/src/Components/Workflow/WorkflowElement.tsx
Normal file
42
Dashboard/src/Components/Workflow/WorkflowElement.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import Link from 'CommonUI/src/Components/Link/Link';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import Workflow from 'Model/Models/Workflow';
|
||||
|
||||
export interface ComponentProps {
|
||||
workflow: Workflow;
|
||||
onNavigateComplete?: (() => void) | undefined;
|
||||
}
|
||||
|
||||
const WorkflowElement: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
if (
|
||||
props.workflow._id &&
|
||||
(props.workflow.projectId ||
|
||||
(props.workflow.project && props.workflow.project._id))
|
||||
) {
|
||||
const projectId: string | undefined = props.workflow.projectId
|
||||
? props.workflow.projectId.toString()
|
||||
: props.workflow.project
|
||||
? props.workflow.project._id
|
||||
: '';
|
||||
return (
|
||||
<Link
|
||||
onNavigateComplete={props.onNavigateComplete}
|
||||
className="underline-on-hover"
|
||||
to={
|
||||
new Route(
|
||||
`/dashboard/${projectId}/workflows/workflow/${props.workflow._id}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<span>{props.workflow.name}</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return <span>{props.workflow.name}</span>;
|
||||
};
|
||||
|
||||
export default WorkflowElement;
|
||||
@@ -1,6 +1,6 @@
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import Page from 'CommonUI/src/Components/Page/Page';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import React, { FunctionComponent, ReactElement, useState } from 'react';
|
||||
import PageMap from '../../Utils/PageMap';
|
||||
import RouteMap, { RouteUtil } from '../../Utils/RouteMap';
|
||||
import PageComponentProps from '../PageComponentProps';
|
||||
@@ -10,10 +10,22 @@ import FieldType from 'CommonUI/src/Components/Types/FieldType';
|
||||
import IconProp from 'Common/Types/Icon/IconProp';
|
||||
import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import WorkflowSideMenu from './SideMenu';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import Workflow from 'Model/Models/Workflow';
|
||||
import WorkflowElement from '../../Components/Workflow/WorkflowElement';
|
||||
import JSONFunctions from 'Common/Types/JSONFunctions';
|
||||
import { ButtonStyleType } from 'CommonUI/src/Components/Button/Button';
|
||||
import Modal, { ModalWidth } from 'CommonUI/src/Components/Modal/Modal';
|
||||
|
||||
const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
_props: PageComponentProps
|
||||
): ReactElement => {
|
||||
|
||||
|
||||
|
||||
const [showViewLogsModal, setShowViewLogsModal] = useState<boolean>(false);
|
||||
const [logs, setLogs] = useState<string>('');
|
||||
|
||||
return (
|
||||
<Page
|
||||
title={'Workflow Logs'}
|
||||
@@ -39,48 +51,104 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
]}
|
||||
sideMenu={<WorkflowSideMenu />}
|
||||
>
|
||||
<ModelTable<WorkflowLogs>
|
||||
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,
|
||||
<>
|
||||
<ModelTable<WorkflowLogs>
|
||||
modelType={WorkflowLogs}
|
||||
id="workflow-logs-table"
|
||||
isDeleteable={false}
|
||||
actionButtons={[
|
||||
{
|
||||
title: 'View Logs',
|
||||
buttonStyleType: ButtonStyleType.NORMAL,
|
||||
icon: IconProp.List,
|
||||
onClick: async (
|
||||
item: JSONObject,
|
||||
onCompleteAction: Function
|
||||
) => {
|
||||
|
||||
setLogs((item['logs'] as string));
|
||||
setShowViewLogsModal(true);
|
||||
|
||||
onCompleteAction();
|
||||
},
|
||||
},
|
||||
title: 'Workflow Name',
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
createdAt: true,
|
||||
]}
|
||||
isEditable={false}
|
||||
isCreateable={false}
|
||||
name="Workflow Logs"
|
||||
isViewable={false}
|
||||
selectMoreFields={{
|
||||
logs: true
|
||||
}}
|
||||
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,
|
||||
getElement: (item: JSONObject): ReactElement => {
|
||||
return (
|
||||
<WorkflowElement
|
||||
workflow={
|
||||
JSONFunctions.fromJSON(
|
||||
(item['workflow'] as JSONObject) || [],
|
||||
Workflow
|
||||
) as Workflow
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
title: 'Logs Created At',
|
||||
type: FieldType.DateTime,
|
||||
isFilterable: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Page>
|
||||
{
|
||||
field: {
|
||||
createdAt: true,
|
||||
},
|
||||
title: 'Workflow Ran At',
|
||||
type: FieldType.DateTime,
|
||||
isFilterable: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{showViewLogsModal && <Modal
|
||||
title={'Workflow Logs'}
|
||||
description="Here are the logs for this workflow"
|
||||
isLoading={false}
|
||||
modalWidth={ModalWidth.Large}
|
||||
onSubmit={() => {
|
||||
setShowViewLogsModal(false);
|
||||
}}
|
||||
|
||||
submitButtonText={
|
||||
'Close'
|
||||
}
|
||||
submitButtonStyleType={
|
||||
ButtonStyleType.NORMAL
|
||||
}
|
||||
>
|
||||
<div className="text-gray-500 mt-5 text-sm h-96 overflow-scroll overflow-x-hidden p-5 border-gray-50 border border-2 bg-gray-100 rounded">
|
||||
{logs}
|
||||
</div>
|
||||
</Modal>}
|
||||
|
||||
</>
|
||||
</Page >
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
workflowId: null,
|
||||
projectId: DashboardNavigation.getProjectId()?.toString(),
|
||||
}}
|
||||
noItemsMessage={'No workflows found.'}
|
||||
noItemsMessage={'No global variables found.'}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
@@ -97,8 +97,8 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
},
|
||||
title: 'Content',
|
||||
description:
|
||||
'Is this variable secret or secure? Should this be encrypted in the Database?',
|
||||
fieldType: FormFieldSchemaType.Checkbox,
|
||||
'Enter the content of the variable',
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
@@ -121,6 +121,14 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isSecret: true,
|
||||
},
|
||||
title: 'Secret',
|
||||
type: FieldType.Boolean,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
createdAt: true,
|
||||
|
||||
@@ -11,6 +11,7 @@ import Workflow from 'Model/Models/Workflow';
|
||||
import CardModelDetail from 'CommonUI/src/Components/ModelDetail/CardModelDetail';
|
||||
import IconProp from 'Common/Types/Icon/IconProp';
|
||||
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
|
||||
import FieldType from 'CommonUI/src/Components/Types/FieldType';
|
||||
|
||||
const Delete: FunctionComponent<PageComponentProps> = (
|
||||
_props: PageComponentProps
|
||||
@@ -83,6 +84,13 @@ const Delete: FunctionComponent<PageComponentProps> = (
|
||||
required: true,
|
||||
placeholder: 'Description',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isEnabled: true,
|
||||
},
|
||||
title: 'Enabled',
|
||||
fieldType: FormFieldSchemaType.Checkbox
|
||||
},
|
||||
]}
|
||||
modelDetailProps={{
|
||||
showDetailsInNumberOfColumns: 2,
|
||||
@@ -107,6 +115,13 @@ const Delete: FunctionComponent<PageComponentProps> = (
|
||||
},
|
||||
title: 'Description',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isEnabled: true,
|
||||
},
|
||||
title: 'Enabled',
|
||||
fieldType: FieldType.Boolean
|
||||
},
|
||||
],
|
||||
modelId: modelId,
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import Page from 'CommonUI/src/Components/Page/Page';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import React, { FunctionComponent, ReactElement, useState } from 'react';
|
||||
import PageMap from '../../../Utils/PageMap';
|
||||
import RouteMap, { RouteUtil } from '../../../Utils/RouteMap';
|
||||
import PageComponentProps from '../../PageComponentProps';
|
||||
@@ -10,14 +10,26 @@ import ObjectID from 'Common/Types/ObjectID';
|
||||
import FieldType from 'CommonUI/src/Components/Types/FieldType';
|
||||
import IconProp from 'Common/Types/Icon/IconProp';
|
||||
import WorkflowLogs from 'Model/Models/WorkflowLog';
|
||||
import Workflow from 'Model/Models/Workflow';
|
||||
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
|
||||
import DashboardNavigation from '../../../Utils/Navigation';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import WorkflowElement from '../../../Components/Workflow/WorkflowElement';
|
||||
import JSONFunctions from 'Common/Types/JSONFunctions';
|
||||
import { ButtonStyleType } from 'CommonUI/src/Components/Button/Button';
|
||||
import Modal, { ModalWidth } from 'CommonUI/src/Components/Modal/Modal';
|
||||
|
||||
const Delete: FunctionComponent<PageComponentProps> = (
|
||||
_props: PageComponentProps
|
||||
): ReactElement => {
|
||||
const modelId: ObjectID = Navigation.getLastParamAsObjectID(1);
|
||||
|
||||
|
||||
|
||||
const [showViewLogsModal, setShowViewLogsModal] = useState<boolean>(false);
|
||||
const [logs, setLogs] = useState<string>('');
|
||||
|
||||
|
||||
return (
|
||||
<Page
|
||||
title={'Workflow'}
|
||||
@@ -53,51 +65,107 @@ const Delete: FunctionComponent<PageComponentProps> = (
|
||||
]}
|
||||
sideMenu={<SideMenu modelId={modelId} />}
|
||||
>
|
||||
<ModelTable<WorkflowLogs>
|
||||
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,
|
||||
<>
|
||||
<ModelTable<WorkflowLogs>
|
||||
modelType={WorkflowLogs}
|
||||
id="workflow-logs-table"
|
||||
isDeleteable={false}
|
||||
isEditable={false}
|
||||
isCreateable={false}
|
||||
name="Workflow Logs"
|
||||
query={{
|
||||
workflowId: modelId,
|
||||
projectId: DashboardNavigation.getProjectId()?.toString(),
|
||||
}}
|
||||
selectMoreFields={{
|
||||
logs: true
|
||||
}}
|
||||
actionButtons={[
|
||||
{
|
||||
title: 'View Logs',
|
||||
buttonStyleType: ButtonStyleType.NORMAL,
|
||||
icon: IconProp.List,
|
||||
onClick: async (
|
||||
item: JSONObject,
|
||||
onCompleteAction: Function
|
||||
) => {
|
||||
|
||||
setLogs((item['logs'] as string));
|
||||
setShowViewLogsModal(true);
|
||||
|
||||
onCompleteAction();
|
||||
},
|
||||
},
|
||||
title: 'Workflow Name',
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
createdAt: true,
|
||||
]}
|
||||
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',
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
getElement: (item: JSONObject): ReactElement => {
|
||||
return (
|
||||
<WorkflowElement
|
||||
workflow={
|
||||
JSONFunctions.fromJSON(
|
||||
(item['workflow'] as JSONObject) || [],
|
||||
Workflow
|
||||
) as Workflow
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
title: 'Logs Created At',
|
||||
type: FieldType.DateTime,
|
||||
isFilterable: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{
|
||||
field: {
|
||||
createdAt: true,
|
||||
},
|
||||
title: 'Workflow Ran At',
|
||||
type: FieldType.DateTime,
|
||||
isFilterable: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{showViewLogsModal && <Modal
|
||||
title={'Workflow Logs'}
|
||||
description="Here are the logs for this workflow"
|
||||
isLoading={false}
|
||||
modalWidth={ModalWidth.Large}
|
||||
onSubmit={() => {
|
||||
setShowViewLogsModal(false);
|
||||
}}
|
||||
|
||||
submitButtonText={
|
||||
'Close'
|
||||
}
|
||||
submitButtonStyleType={
|
||||
ButtonStyleType.NORMAL
|
||||
}
|
||||
>
|
||||
<div className="text-gray-500 mt-5 text-sm h-96 overflow-scroll overflow-x-hidden p-5 border-gray-50 border border-2 bg-gray-100 rounded">
|
||||
{logs}
|
||||
</div>
|
||||
</Modal>}
|
||||
</>
|
||||
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ import IconProp from 'Common/Types/Icon/IconProp';
|
||||
import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import DashboardNavigation from '../../../Utils/Navigation';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import SideMenu from './SideMenu';
|
||||
|
||||
const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
_props: PageComponentProps
|
||||
@@ -49,6 +50,7 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
),
|
||||
},
|
||||
]}
|
||||
sideMenu={<SideMenu modelId={modelId} />}
|
||||
>
|
||||
<ModelTable<WorkflowVariable>
|
||||
modelType={WorkflowVariable}
|
||||
@@ -60,9 +62,9 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
isViewable={false}
|
||||
cardProps={{
|
||||
icon: IconProp.Variable,
|
||||
title: 'Global Variables',
|
||||
title: 'Workflow Variables',
|
||||
description:
|
||||
'Here is a list of global secrets and variables for this project.',
|
||||
'Here is a list of workflow secrets and variables for this specific workflow.',
|
||||
}}
|
||||
query={{
|
||||
workflowId: modelId,
|
||||
@@ -72,10 +74,9 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
item: WorkflowVariable
|
||||
): Promise<WorkflowVariable> => {
|
||||
item.workflowId = modelId;
|
||||
item.projectId = DashboardNavigation.getProjectId()!;
|
||||
return Promise.resolve(item);
|
||||
}}
|
||||
noItemsMessage={'No workflows found.'}
|
||||
noItemsMessage={'No workflow variables found.'}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
@@ -114,8 +115,8 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
},
|
||||
title: 'Content',
|
||||
description:
|
||||
'Is this variable secret or secure? Should this be encrypted in the Database?',
|
||||
fieldType: FormFieldSchemaType.Checkbox,
|
||||
'Enter the content of the variable',
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
@@ -138,6 +139,14 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isSecret: true,
|
||||
},
|
||||
title: 'Secret',
|
||||
type: FieldType.Boolean,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
createdAt: true,
|
||||
|
||||
@@ -71,6 +71,13 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
required: true,
|
||||
placeholder: 'Description',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isEnabled: true,
|
||||
},
|
||||
title: 'Enabled',
|
||||
fieldType: FormFieldSchemaType.Checkbox
|
||||
},
|
||||
]}
|
||||
showRefreshButton={true}
|
||||
showFilterButton={true}
|
||||
@@ -94,6 +101,14 @@ const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isEnabled: true,
|
||||
},
|
||||
title: 'Enabled',
|
||||
type: FieldType.Boolean,
|
||||
isFilterable: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Page>
|
||||
|
||||
@@ -273,6 +273,10 @@ const RouteMap: Dictionary<Route> = {
|
||||
`/dashboard/${RouteParams.ProjectID}/workflows/variables`
|
||||
),
|
||||
|
||||
[PageMap.WORKFLOW_VARIABLES]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/workflows/workflow/${RouteParams.ModelID}/variables`
|
||||
),
|
||||
|
||||
[PageMap.WORKFLOW_BUILDER]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/workflows/workflow/${RouteParams.ModelID}/builder`
|
||||
),
|
||||
@@ -298,7 +302,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;
|
||||
|
||||
@@ -12,6 +12,7 @@ import ColumnAccessControl from 'Common/Types/Database/AccessControl/ColumnAcces
|
||||
import TenantColumn from 'Common/Types/Database/TenantColumn';
|
||||
import SingularPluralName from 'Common/Types/Database/SingularPluralName';
|
||||
import BaseModel from 'Common/Models/BaseModel';
|
||||
import Workflow from './Workflow';
|
||||
|
||||
@TenantColumn('projectId')
|
||||
@TableAccessControl({
|
||||
@@ -42,7 +43,7 @@ import BaseModel from 'Common/Models/BaseModel';
|
||||
name: 'WorkflowLog',
|
||||
})
|
||||
@SingularPluralName('Workflow Log', 'Workflow Logs')
|
||||
export default class Workflow extends BaseModel {
|
||||
export default class WorkflowLog extends BaseModel {
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
|
||||
@@ -15,6 +15,7 @@ import UniqueColumnBy from 'Common/Types/Database/UniqueColumnBy';
|
||||
import TenantColumn from 'Common/Types/Database/TenantColumn';
|
||||
import SingularPluralName from 'Common/Types/Database/SingularPluralName';
|
||||
import BaseModel from 'Common/Models/BaseModel';
|
||||
import Workflow from './Workflow';
|
||||
|
||||
@TenantColumn('projectId')
|
||||
@TableAccessControl({
|
||||
@@ -45,7 +46,7 @@ import BaseModel from 'Common/Models/BaseModel';
|
||||
name: 'WorkflowVariable',
|
||||
})
|
||||
@SingularPluralName('Workflow Variable', 'Workflow Variables')
|
||||
export default class Workflow extends BaseModel {
|
||||
export default class WorkflowVariable extends BaseModel {
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -127,7 +128,7 @@ export default class Workflow extends BaseModel {
|
||||
})
|
||||
@ManyToOne(
|
||||
(_type: string) => {
|
||||
return Project;
|
||||
return Workflow;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
@@ -245,7 +246,10 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflowVariable,
|
||||
],
|
||||
read: [],
|
||||
read: [Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflowVariable],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({ required: true, type: TableColumnType.Boolean })
|
||||
|
||||
Reference in New Issue
Block a user