mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
add workflow client pages
This commit is contained in:
@@ -97,6 +97,12 @@ enum Permission {
|
||||
CanEditStatusPageResource = 'CanEditStatusPageResource',
|
||||
CanReadStatusPageResource = 'CanReadStatusPageResource',
|
||||
|
||||
// Workflow Permissions (Owner Permission)
|
||||
CanCreateWorkflow = 'CanCreateWorkflow',
|
||||
CanDeleteWorkflow = 'CanDeleteWorkflow',
|
||||
CanEditWorkflow = 'CanEditWorkflow',
|
||||
CanReadWorkflow = 'CanReadWorkflow',
|
||||
|
||||
// Probe Permissions (Owner Permission)
|
||||
CanCreateStatusPageGroup = 'CanCreateStatusPageGroup',
|
||||
CanDeleteStatusPageGroup = 'CanDeleteStatusPageGroup',
|
||||
@@ -811,6 +817,42 @@ export class PermissionHelper {
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateWorkflow,
|
||||
title: 'Can Create Workflow',
|
||||
description:
|
||||
'A user assigned this permission can create Workflow in this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanDeleteWorkflow,
|
||||
title: 'Can Delete Workflow',
|
||||
description:
|
||||
'A user assigned this permission can delete Workflow in this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanEditWorkflow,
|
||||
title: 'Can Edit Workflow',
|
||||
description:
|
||||
'A user assigned this permission can edit Workflow in this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanReadWorkflow,
|
||||
title: 'Can Read Workflow',
|
||||
description:
|
||||
'A user assigned this permission can read Workflow in this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateStatusPageGroup,
|
||||
title: 'Can Create Status Page Group',
|
||||
|
||||
10
CommonServer/Services/WorkflowService.ts
Normal file
10
CommonServer/Services/WorkflowService.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/Workflow';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
@@ -16,8 +16,8 @@ const NotFound: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<div className="mx-auto max-w-full sm:px-6 lg:px-8 rounded-lg drop-shadow-md">
|
||||
<div className="min-h-full bg-white py-16 px-6 sm:py-24 md:grid md:place-items-center lg:px-8">
|
||||
<div className="mx-auto max-w-full sm:px-6 lg:px-8 rounded-lg">
|
||||
<div className="min-h-full py-16 px-6 sm:py-24 md:grid md:place-items-center lg:px-8">
|
||||
<div className="mx-auto">
|
||||
<main className="sm:flex">
|
||||
<p className="text-4xl tracking-tight text-indigo-600 sm:text-5xl">
|
||||
|
||||
@@ -17,6 +17,8 @@ import OngoingScheduledEvents from './Pages/Home/OngingScheduledMaintenance';
|
||||
|
||||
import useAsyncEffect from 'use-async-effect';
|
||||
|
||||
import Workflows from './Pages/Workflow/Workflows';
|
||||
|
||||
import StatusPages from './Pages/StatusPages/StatusPages';
|
||||
import StatusPagesView from './Pages/StatusPages/View/Index';
|
||||
import StatusPagesViewDelete from './Pages/StatusPages/View/Delete';
|
||||
@@ -381,6 +383,19 @@ const App: FunctionComponent = () => {
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Workflows */}
|
||||
|
||||
<PageRoute
|
||||
path={RouteMap[PageMap.WORKFLOWS]?.toString() || ''}
|
||||
element={
|
||||
<Workflows
|
||||
pageRoute={RouteMap[PageMap.WORKFLOWS] as Route}
|
||||
currentProject={selectedProject}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
{/* Status Pages */}
|
||||
|
||||
<PageRoute
|
||||
|
||||
@@ -11,7 +11,7 @@ const PageNotFound: FunctionComponent<PageComponentProps> = (
|
||||
_props: PageComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<Page title={'Page Not Found'} breadcrumbLinks={[]}>
|
||||
<Page title={''} breadcrumbLinks={[]}>
|
||||
<NotFound
|
||||
homeRoute={new Route('/dashboard')}
|
||||
supportEmail={new Email('support@oneuptime.com')}
|
||||
|
||||
0
Dashboard/src/Pages/Workflow/View/Index.tsx
Normal file
0
Dashboard/src/Pages/Workflow/View/Index.tsx
Normal file
99
Dashboard/src/Pages/Workflow/Workflows.tsx
Normal file
99
Dashboard/src/Pages/Workflow/Workflows.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
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 Workflow from 'Model/Models/Workflow';
|
||||
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';
|
||||
|
||||
const Workflows: FunctionComponent<PageComponentProps> = (
|
||||
_props: PageComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<Page
|
||||
title={'Workflows'}
|
||||
breadcrumbLinks={[
|
||||
{
|
||||
title: 'Project',
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[PageMap.HOME] as Route
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Workflows',
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[PageMap.STATUS_PAGES] as Route
|
||||
),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ModelTable<Workflow>
|
||||
modelType={Workflow}
|
||||
id="status-page-table"
|
||||
isDeleteable={false}
|
||||
isEditable={true}
|
||||
isCreateable={true}
|
||||
name="Workflows"
|
||||
isViewable={true}
|
||||
cardProps={{
|
||||
icon: IconProp.CheckCircle,
|
||||
title: 'Workflows',
|
||||
description:
|
||||
'Here is a list of workflows for this project.',
|
||||
}}
|
||||
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',
|
||||
}
|
||||
]}
|
||||
showRefreshButton={true}
|
||||
showFilterButton={true}
|
||||
viewPageRoute={Navigation.getCurrentRoute()}
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: 'Name',
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
description: true,
|
||||
},
|
||||
title: 'Description',
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default Workflows;
|
||||
@@ -98,6 +98,10 @@ enum PageMap {
|
||||
USER_PROFILE = 'USER_PROFILE',
|
||||
ACTIVE_INCIDENTS = 'ACTIVE_INCIDENTS',
|
||||
PROJECT_INVITATIONS = 'PROJECT_INVITATIONS',
|
||||
|
||||
// WORKFLOW
|
||||
WORKFLOWS = 'WORKFLOWS',
|
||||
WORKFLOW_VIEW = 'WORKFLOW_VIEW'
|
||||
}
|
||||
|
||||
export default PageMap;
|
||||
|
||||
@@ -260,6 +260,11 @@ const RouteMap: Dictionary<Route> = {
|
||||
`/dashboard/${RouteParams.ProjectID}/settings/labels`
|
||||
),
|
||||
|
||||
// labels.
|
||||
[PageMap.WORKFLOWS]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/workflows`
|
||||
),
|
||||
|
||||
// logout.
|
||||
[PageMap.LOGOUT]: new Route(`/dashboard/logout`),
|
||||
};
|
||||
|
||||
@@ -20,6 +20,11 @@ import ProjectService, {
|
||||
Service as ProjectServiceType,
|
||||
} from 'CommonServer/Services/ProjectService';
|
||||
|
||||
import Workflow from 'Model/Models/Workflow';
|
||||
import WorkflowService, {
|
||||
Service as WorkflowServiceType,
|
||||
} from 'CommonServer/Services/WorkflowService';
|
||||
|
||||
import Probe from 'Model/Models/Probe';
|
||||
import ProbeService, {
|
||||
Service as ProbeServiceType,
|
||||
@@ -268,6 +273,14 @@ app.use(
|
||||
).getRouter()
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<Workflow, WorkflowServiceType>(
|
||||
Workflow,
|
||||
WorkflowService
|
||||
).getRouter()
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<Domain, DomainServiceType>(Domain, DomainService).getRouter()
|
||||
|
||||
@@ -63,6 +63,10 @@ import BillingInvoice from './BillingInvoice';
|
||||
import GreenlockChallenge from './GreenlockChallenge';
|
||||
import GreenlockCertificate from './GreenlockCertificate';
|
||||
|
||||
|
||||
// Workflows.
|
||||
import Workflow from './Workflow';
|
||||
|
||||
export default [
|
||||
User,
|
||||
Probe,
|
||||
@@ -109,4 +113,7 @@ export default [
|
||||
|
||||
GreenlockChallenge,
|
||||
GreenlockCertificate,
|
||||
|
||||
|
||||
Workflow
|
||||
];
|
||||
|
||||
312
Model/Models/Workflow.ts
Normal file
312
Model/Models/Workflow.ts
Normal file
@@ -0,0 +1,312 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import User from './User';
|
||||
import Project from './Project';
|
||||
import CrudApiEndpoint from 'Common/Types/Database/CrudApiEndpoint';
|
||||
import SlugifyColumn from 'Common/Types/Database/SlugifyColumn';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import TableColumnType from 'Common/Types/Database/TableColumnType';
|
||||
import TableColumn from 'Common/Types/Database/TableColumn';
|
||||
import ColumnType from 'Common/Types/Database/ColumnType';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import ColumnLength from 'Common/Types/Database/ColumnLength';
|
||||
import TableAccessControl from 'Common/Types/Database/AccessControl/TableAccessControl';
|
||||
import Permission from 'Common/Types/Permission';
|
||||
import ColumnAccessControl from 'Common/Types/Database/AccessControl/ColumnAccessControl';
|
||||
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';
|
||||
|
||||
@TenantColumn('projectId')
|
||||
@TableAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanDeleteWorkflow,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@CrudApiEndpoint(new Route('/workflow'))
|
||||
@SlugifyColumn('name', 'slug')
|
||||
@Entity({
|
||||
name: 'Workflow',
|
||||
})
|
||||
@SingularPluralName('Workflow', 'Workflows')
|
||||
export default class Workflow extends BaseModel {
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: 'projectId',
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Project,
|
||||
})
|
||||
@ManyToOne(
|
||||
(_type: string) => {
|
||||
return Project;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: 'CASCADE',
|
||||
orphanedRowAction: 'nullify',
|
||||
}
|
||||
)
|
||||
@JoinColumn({ name: 'projectId' })
|
||||
public project?: Project = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
canReadOnPopulate: true,
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public projectId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
required: true,
|
||||
type: TableColumnType.ShortText,
|
||||
canReadOnPopulate: true,
|
||||
})
|
||||
@Column({
|
||||
nullable: false,
|
||||
type: ColumnType.ShortText,
|
||||
length: ColumnLength.ShortText,
|
||||
})
|
||||
@UniqueColumnBy('projectId')
|
||||
public name?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({ required: true, unique: true, type: TableColumnType.Slug })
|
||||
@Column({
|
||||
nullable: false,
|
||||
type: ColumnType.Slug,
|
||||
length: ColumnLength.Slug,
|
||||
})
|
||||
public slug?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@TableColumn({ required: false, type: TableColumnType.LongText })
|
||||
@Column({
|
||||
nullable: true,
|
||||
type: ColumnType.LongText,
|
||||
length: ColumnLength.LongText,
|
||||
})
|
||||
public description?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: 'createdByUserId',
|
||||
type: TableColumnType.Entity,
|
||||
modelType: User,
|
||||
})
|
||||
@ManyToOne(
|
||||
(_type: string) => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: 'CASCADE',
|
||||
orphanedRowAction: 'nullify',
|
||||
}
|
||||
)
|
||||
@JoinColumn({ name: 'createdByUserId' })
|
||||
public createdByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({ type: TableColumnType.ObjectID })
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public createdByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: 'deletedByUserId',
|
||||
type: TableColumnType.ObjectID,
|
||||
})
|
||||
@ManyToOne(
|
||||
(_type: string) => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
cascade: false,
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: 'CASCADE',
|
||||
orphanedRowAction: 'nullify',
|
||||
}
|
||||
)
|
||||
@JoinColumn({ name: 'deletedByUserId' })
|
||||
public deletedByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({ type: TableColumnType.ObjectID })
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public deletedByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadWorkflow,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@TableColumn({ isDefaultValueColumn: true, type: TableColumnType.Boolean })
|
||||
@Column({
|
||||
type: ColumnType.Boolean,
|
||||
default: false,
|
||||
})
|
||||
public isEnabled?: boolean = undefined;
|
||||
}
|
||||
@@ -70,6 +70,7 @@ const RouteMap: Dictionary<Route> = {
|
||||
[PageMap.PREVIEW_RESET_PASSWORD]: new Route(
|
||||
`/status-page/${RouteParams.StatusPageId}/reset-password/:token`
|
||||
),
|
||||
|
||||
};
|
||||
|
||||
export class RouteUtil {
|
||||
|
||||
Reference in New Issue
Block a user