mirror of
https://github.com/sartography/spiffworkflow-frontend.git
synced 2025-02-24 04:08:10 +00:00
eslint is passing w/ burnettk
This commit is contained in:
parent
b9238739eb
commit
c9e118b7c2
27
.eslintrc.js
27
.eslintrc.js
@ -4,20 +4,27 @@ module.exports = {
|
||||
es2021: true,
|
||||
},
|
||||
extends: [
|
||||
"react-app",
|
||||
"react-app/jest",
|
||||
"plugin:react/recommended",
|
||||
"airbnb",
|
||||
"plugin:jest/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
'react-app',
|
||||
'react-app/jest',
|
||||
'plugin:react/recommended',
|
||||
'airbnb',
|
||||
'plugin:jest/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['react'],
|
||||
rules: {
|
||||
'react/jsx-no-bind': 'off',
|
||||
'jsx-a11y/no-autofocus': 'off',
|
||||
'jsx-a11y/label-has-associated-control': 'off',
|
||||
'no-console': 'off',
|
||||
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
},
|
||||
plugins: ["react"],
|
||||
rules: {},
|
||||
};
|
||||
|
1
package-lock.json
generated
1
package-lock.json
generated
@ -25,6 +25,7 @@
|
||||
"dmn-js": "^12.1.1",
|
||||
"dmn-js-properties-panel": "^1.0.0",
|
||||
"dmn-js-shared": "^12.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.4.0",
|
||||
"react-datepicker": "^4.8.0",
|
||||
|
@ -20,6 +20,7 @@
|
||||
"dmn-js": "^12.1.1",
|
||||
"dmn-js-properties-panel": "^1.0.0",
|
||||
"dmn-js-shared": "^12.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.4.0",
|
||||
"react-datepicker": "^4.8.0",
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
//FIXME: this is currently not actually catching any issues. not sure why
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -8,26 +9,29 @@ class ErrorBoundary extends React.Component {
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
// Update state so the next render will show the fallback UI.
|
||||
return { hasError: true };
|
||||
return { hasError: true, error };
|
||||
}
|
||||
|
||||
componentDidCatch(error, errorInfo) {
|
||||
this.setState({
|
||||
error: error,
|
||||
errorInfo: errorInfo
|
||||
})
|
||||
// You can also log the error to an error reporting service
|
||||
console.log("HELLO: ", error, errorInfo);
|
||||
console.log('HELLO: ', error, errorInfo);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
const { hasError } = this.state;
|
||||
const { children } = this.props;
|
||||
|
||||
if (hasError) {
|
||||
// You can render any custom fallback UI
|
||||
return <h1>Something went wrong.</h1>;
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorBoundary;
|
||||
|
||||
ErrorBoundary.propTypes = {
|
||||
children: PropTypes.string.isRequired,
|
||||
};
|
||||
|
@ -1,23 +1,25 @@
|
||||
import React from "react";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import React from 'react';
|
||||
import axios from 'axios';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
|
||||
export default class FileInput extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
constructor({ processGroupId, processModelId }) {
|
||||
super({ processGroupId, processModelId });
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.fileInput = React.createRef();
|
||||
this.props = props;
|
||||
this.processGroupId = processGroupId;
|
||||
this.processModelId = processModelId;
|
||||
}
|
||||
|
||||
handleSubmit(event) {
|
||||
event.preventDefault()
|
||||
const url = `${BACKEND_BASE_URL}/process-models/${this.props.processModel.process_group_id}/${this.props.processModel.id}/file`;
|
||||
event.preventDefault();
|
||||
const url = `${BACKEND_BASE_URL}/process-models/${this.processGroupId}/${this.processModelId}/file`;
|
||||
const formData = new FormData();
|
||||
formData.append('file', this.fileInput.current.files[0]);
|
||||
formData.append('fileName', this.fileInput.current.files[0].name);
|
||||
|
||||
// this might work if we remove the content-type header
|
||||
// const headers = {
|
||||
// 'Authorization': `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
// 'content-type': 'multipart/form-data',
|
||||
@ -38,7 +40,7 @@ export default class FileInput extends React.Component {
|
||||
const config = {
|
||||
headers: {
|
||||
'content-type': 'multipart/form-data',
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
},
|
||||
};
|
||||
axios.post(url, formData, config).then((response) => {
|
||||
@ -58,3 +60,8 @@ export default class FileInput extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FileInput.propTypes = {
|
||||
processGroupId: PropTypes.string.isRequired,
|
||||
processModelId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
@ -1,93 +1,162 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Dropdown, Stack } from 'react-bootstrap'
|
||||
import { Dropdown, Stack } from 'react-bootstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const DEFAULT_PER_PAGE = 50;
|
||||
export const DEFAULT_PAGE = 1;
|
||||
|
||||
export default function PaginationForTable(props) {
|
||||
export default function PaginationForTable({
|
||||
page,
|
||||
perPage,
|
||||
pagination,
|
||||
tableToDisplay,
|
||||
queryParamString,
|
||||
path,
|
||||
}) {
|
||||
const PER_PAGE_OPTIONS = [2, 10, 50, 100];
|
||||
|
||||
const buildPerPageDropdown = (() => {
|
||||
const perPageDropdownRows = PER_PAGE_OPTIONS.map(perPageOption => {
|
||||
if (perPageOption === props.perPage) {
|
||||
return <Dropdown.Item key={perPageOption} href={`${props.path}?page=1&per_page=${perPageOption}`} active>{perPageOption}</Dropdown.Item>
|
||||
} else {
|
||||
return <Dropdown.Item key={perPageOption} href={`${props.path}?page=1&per_page=${perPageOption}`}>{perPageOption}</Dropdown.Item>
|
||||
const buildPerPageDropdown = () => {
|
||||
const perPageDropdownRows = PER_PAGE_OPTIONS.map((perPageOption) => {
|
||||
if (perPageOption === perPage) {
|
||||
return (
|
||||
<Dropdown.Item
|
||||
key={perPageOption}
|
||||
href={`${path}?page=1&per_page=${perPageOption}`}
|
||||
active
|
||||
>
|
||||
{perPageOption}
|
||||
</Dropdown.Item>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Dropdown.Item
|
||||
key={perPageOption}
|
||||
href={`${path}?page=1&per_page=${perPageOption}`}
|
||||
>
|
||||
{perPageOption}
|
||||
</Dropdown.Item>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<Dropdown className="ms-auto" id="pagination-page-dropdown">
|
||||
<Dropdown.Toggle id="process-instances-per-page" variant="light border">
|
||||
Process Instances to Show: {props.perPage}
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown className="ms-auto" id="pagination-page-dropdown">
|
||||
<Dropdown.Toggle
|
||||
id="process-instances-per-page"
|
||||
variant="light border"
|
||||
>
|
||||
Process Instances to Show: {perPage}
|
||||
</Dropdown.Toggle>
|
||||
|
||||
<Dropdown.Menu variant="light">
|
||||
{perPageDropdownRows}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
<Dropdown.Menu variant="light">{perPageDropdownRows}</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
</Stack>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
const buildPaginationNav = (() => {
|
||||
let previousPageTag = "";
|
||||
if (props.page === 1) {
|
||||
const buildPaginationNav = () => {
|
||||
let previousPageTag = '';
|
||||
if (page === 1) {
|
||||
previousPageTag = (
|
||||
<li data-qa="pagination-previous-button-inactive" className="page-item disabled" key="previous"><span style={{fontSize:"1.5em"}} className="page-link">«</span></li>
|
||||
)
|
||||
<li
|
||||
data-qa="pagination-previous-button-inactive"
|
||||
className="page-item disabled"
|
||||
key="previous"
|
||||
>
|
||||
<span style={{ fontSize: '1.5em' }} className="page-link">
|
||||
«
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
} else {
|
||||
previousPageTag = (
|
||||
<li className="page-item" key="previous">
|
||||
<Link data-qa="pagination-previous-button" className="page-link" style={{fontSize:"1.5em"}} to={`${props.path}?page=${props.page - 1}&per_page=${props.perPage}${props.queryParamString}`}>«</Link>
|
||||
<Link
|
||||
data-qa="pagination-previous-button"
|
||||
className="page-link"
|
||||
style={{ fontSize: '1.5em' }}
|
||||
to={`${path}?page=${
|
||||
page - 1
|
||||
}&per_page=${perPage}${queryParamString}`}
|
||||
>
|
||||
«
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let nextPageTag = "";
|
||||
if (props.page >= props.pagination.pages) {
|
||||
let nextPageTag = '';
|
||||
if (page >= pagination.pages) {
|
||||
nextPageTag = (
|
||||
<li data-qa="pagination-next-button-inactive" className="page-item disabled" key="next"><span style={{fontSize:"1.5em"}} className="page-link">»</span></li>
|
||||
)
|
||||
<li
|
||||
data-qa="pagination-next-button-inactive"
|
||||
className="page-item disabled"
|
||||
key="next"
|
||||
>
|
||||
<span style={{ fontSize: '1.5em' }} className="page-link">
|
||||
»
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
} else {
|
||||
nextPageTag = (
|
||||
<li className="page-item" key="next">
|
||||
<Link data-qa="pagination-next-button" className="page-link" style={{fontSize:"1.5em"}} to={`${props.path}?page=${props.page + 1}&per_page=${props.perPage}${props.queryParamString}`}>»</Link>
|
||||
<Link
|
||||
data-qa="pagination-next-button"
|
||||
className="page-link"
|
||||
style={{ fontSize: '1.5em' }}
|
||||
to={`${path}?page=${
|
||||
page + 1
|
||||
}&per_page=${perPage}${queryParamString}`}
|
||||
>
|
||||
»
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let startingNumber = ((props.page - 1) * props.perPage) + 1
|
||||
let endingNumber = ((props.page) * props.perPage)
|
||||
if (endingNumber > props.pagination.total) {
|
||||
endingNumber = props.pagination.total
|
||||
let startingNumber = (page - 1) * perPage + 1;
|
||||
let endingNumber = page * perPage;
|
||||
if (endingNumber > pagination.total) {
|
||||
endingNumber = pagination.total;
|
||||
}
|
||||
if (startingNumber > props.pagination.total) {
|
||||
startingNumber = props.pagination.total
|
||||
if (startingNumber > pagination.total) {
|
||||
startingNumber = pagination.total;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<p className="ms-auto">{startingNumber}-{endingNumber} of <span data-qa="total-paginated-items">{props.pagination.total}</span></p>
|
||||
<p className="ms-auto">
|
||||
{startingNumber}-{endingNumber} of{' '}
|
||||
<span data-qa="total-paginated-items">{pagination.total}</span>
|
||||
</p>
|
||||
<nav aria-label="Page navigation">
|
||||
<div>
|
||||
<ul className="pagination">
|
||||
{previousPageTag}
|
||||
{nextPageTag}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="pagination">
|
||||
{previousPageTag}
|
||||
{nextPageTag}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</Stack>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
return(
|
||||
return (
|
||||
<main>
|
||||
{buildPaginationNav()}
|
||||
{props.tableToDisplay}
|
||||
{buildPerPageDropdown()}
|
||||
{buildPaginationNav()}
|
||||
{tableToDisplay}
|
||||
{buildPerPageDropdown()}
|
||||
</main>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
PaginationForTable.propTypes = {
|
||||
page: PropTypes.number.isRequired,
|
||||
perPage: PropTypes.number.isRequired,
|
||||
pagination: PropTypes.objectOf(PropTypes.number).isRequired,
|
||||
tableToDisplay: PropTypes.string.isRequired,
|
||||
queryParamString: PropTypes.string.isRequired,
|
||||
path: PropTypes.string.isRequired,
|
||||
};
|
||||
|
@ -1,30 +1,67 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import Breadcrumb from 'react-bootstrap/Breadcrumb'
|
||||
import { Link } from 'react-router-dom';
|
||||
import Breadcrumb from 'react-bootstrap/Breadcrumb';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function ProcessBreadcrumb(props) {
|
||||
let processGroupBreadcrumb = ''
|
||||
let processModelBreadcrumb = ''
|
||||
export default function ProcessBreadcrumb({
|
||||
processModelId,
|
||||
processGroupId,
|
||||
linkProcessModel,
|
||||
}) {
|
||||
let processGroupBreadcrumb = '';
|
||||
let processModelBreadcrumb = '';
|
||||
|
||||
if (props.processModelId) {
|
||||
if (props.linkProcessModel) {
|
||||
processModelBreadcrumb = <Breadcrumb.Item linkAs={Link} linkProps={{ to: `/process-models/${props.processGroupId}/${props.processModelId}` }}>Process Model: {props.processModelId}</Breadcrumb.Item>
|
||||
if (processModelId) {
|
||||
if (linkProcessModel) {
|
||||
processModelBreadcrumb = (
|
||||
<Breadcrumb.Item
|
||||
linkAs={Link}
|
||||
linkProps={{
|
||||
to: `/process-models/${processGroupId}/${processModelId}`,
|
||||
}}
|
||||
>
|
||||
Process Model: {processModelId}
|
||||
</Breadcrumb.Item>
|
||||
);
|
||||
} else {
|
||||
processModelBreadcrumb = <Breadcrumb.Item active={true}>Process Model: {props.processModelId}</Breadcrumb.Item>
|
||||
processModelBreadcrumb = (
|
||||
<Breadcrumb.Item active>
|
||||
Process Model: {processModelId}
|
||||
</Breadcrumb.Item>
|
||||
);
|
||||
}
|
||||
processGroupBreadcrumb = <Breadcrumb.Item linkAs={Link} linkProps={{ to: `/process-groups/${props.processGroupId}` }}>
|
||||
Process Group: {props.processGroupId}
|
||||
</Breadcrumb.Item>
|
||||
} else if (props.processGroupId) {
|
||||
processGroupBreadcrumb = <Breadcrumb.Item active={true}>Process Group: {props.processGroupId}</Breadcrumb.Item>
|
||||
processGroupBreadcrumb = (
|
||||
<Breadcrumb.Item
|
||||
linkAs={Link}
|
||||
linkProps={{ to: `/process-groups/${processGroupId}` }}
|
||||
>
|
||||
Process Group: {processGroupId}
|
||||
</Breadcrumb.Item>
|
||||
);
|
||||
} else if (processGroupId) {
|
||||
processGroupBreadcrumb = (
|
||||
<Breadcrumb.Item active>Process Group: {processGroupId}</Breadcrumb.Item>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item linkAs={Link} linkProps={{ to: '/' }}>Home</Breadcrumb.Item>
|
||||
{processGroupBreadcrumb}
|
||||
{processModelBreadcrumb}
|
||||
</Breadcrumb>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item linkAs={Link} linkProps={{ to: '/' }}>
|
||||
Home
|
||||
</Breadcrumb.Item>
|
||||
{processGroupBreadcrumb}
|
||||
{processModelBreadcrumb}
|
||||
</Breadcrumb>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
ProcessBreadcrumb.propTypes = {
|
||||
processModelId: PropTypes.string.isRequired,
|
||||
processGroupId: PropTypes.string.isRequired,
|
||||
linkProcessModel: PropTypes.bool,
|
||||
};
|
||||
|
||||
ProcessBreadcrumb.defaultProps = {
|
||||
linkProcessModel: false,
|
||||
};
|
||||
|
@ -1,30 +1,46 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import ProcessBreadcrumb from './ProcessBreadcrumb';
|
||||
import {
|
||||
BrowserRouter,
|
||||
} from "react-router-dom";
|
||||
|
||||
test('renders home link', () => {
|
||||
render(<BrowserRouter><ProcessBreadcrumb /></BrowserRouter>);
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<ProcessBreadcrumb />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const homeElement = screen.getByText(/Home/);
|
||||
expect(homeElement).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders process group when given processGroupId', async () => {
|
||||
render(<BrowserRouter><ProcessBreadcrumb processGroupId='group-a'/></BrowserRouter>);
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<ProcessBreadcrumb processGroupId="group-a" />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const processGroupElement = screen.getByText(/group-a/);
|
||||
expect(processGroupElement).toBeInTheDocument();
|
||||
const processGroupBreadcrumbs = await screen.findAllByText(/Process Group: group-a/);
|
||||
const processGroupBreadcrumbs = await screen.findAllByText(
|
||||
/Process Group: group-a/
|
||||
);
|
||||
expect(processGroupBreadcrumbs[0]).toHaveClass('breadcrumb-item active');
|
||||
});
|
||||
|
||||
test('renders process model when given processModelId', async () => {
|
||||
render(<BrowserRouter><ProcessBreadcrumb processGroupId='group-b' processModelId='model-c'/></BrowserRouter>);
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<ProcessBreadcrumb processGroupId="group-b" processModelId="model-c" />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const processGroupElement = screen.getByText(/group-b/);
|
||||
expect(processGroupElement).toBeInTheDocument();
|
||||
const processModelBreadcrumbs = await screen.findAllByText(/Process Model: model-c/);
|
||||
const processModelBreadcrumbs = await screen.findAllByText(
|
||||
/Process Model: model-c/
|
||||
);
|
||||
expect(processModelBreadcrumbs[0]).toHaveClass('breadcrumb-item active');
|
||||
const processGroupBreadcrumbs = await screen.findAllByText(/Process Group: group-b/);
|
||||
const processGroupBreadcrumbs = await screen.findAllByText(
|
||||
/Process Group: group-b/
|
||||
);
|
||||
expect(processGroupBreadcrumbs[0]).toBeInTheDocument();
|
||||
// expect(processGroupBreadcrumbs[0]).toHaveClass('breadcrumb-item');
|
||||
});
|
||||
|
@ -1,23 +1,24 @@
|
||||
const host = window.location.hostname;
|
||||
const hostAndPort = `${host}:7000`;
|
||||
|
||||
export const BACKEND_BASE_URL = `http://${hostAndPort}/v1.0`
|
||||
export const HOT_AUTH_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOm51bGx9.krsOjlSilPMu_3r7WkkUfKyr-h3HprXr6R4_FXRXz6Y"
|
||||
export const BACKEND_BASE_URL = `http://${hostAndPort}/v1.0`;
|
||||
export const HOT_AUTH_TOKEN =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOm51bGx9.krsOjlSilPMu_3r7WkkUfKyr-h3HprXr6R4_FXRXz6Y';
|
||||
|
||||
export const STANDARD_HEADERS = {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
}
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
};
|
||||
|
||||
export const PROCESS_STATUSES = [
|
||||
"all",
|
||||
"not_started",
|
||||
"user_input_required",
|
||||
"waiting",
|
||||
"complete",
|
||||
"faulted",
|
||||
"suspended",
|
||||
]
|
||||
'all',
|
||||
'not_started',
|
||||
'user_input_required',
|
||||
'waiting',
|
||||
'complete',
|
||||
'faulted',
|
||||
'suspended',
|
||||
];
|
||||
|
||||
export const DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"
|
||||
export const DATE_FORMAT = 'yyyy-MM-dd HH:mm:ss';
|
||||
|
@ -1,20 +1,20 @@
|
||||
// https://www.30secondsofcode.org/js/s/slugify
|
||||
export const slugifyString = ((str) => {
|
||||
export const slugifyString = (str) => {
|
||||
return str
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[^\w\s-]/g, '')
|
||||
.replace(/[\s_-]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
});
|
||||
};
|
||||
|
||||
export const convertDateToSeconds = ((date, onChangeFunction) => {
|
||||
export const convertDateToSeconds = (date, onChangeFunction) => {
|
||||
if (date === null) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let dateInMilliseconds = date;
|
||||
if (typeof(date.getTime) === "function") {
|
||||
if (typeof date.getTime === 'function') {
|
||||
dateInMilliseconds = date.getTime();
|
||||
}
|
||||
const dateInSeconds = Math.floor(dateInMilliseconds / 1000);
|
||||
@ -23,4 +23,6 @@ export const convertDateToSeconds = ((date, onChangeFunction) => {
|
||||
} else {
|
||||
return dateInSeconds;
|
||||
}
|
||||
});
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
86
src/index.js
86
src/index.js
@ -1,33 +1,27 @@
|
||||
import React from 'react';
|
||||
import * as ReactDOMClient from 'react-dom/client';
|
||||
import logo from './logo.svg';
|
||||
|
||||
import { Container } from 'react-bootstrap';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.css';
|
||||
import './index.css';
|
||||
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
import {
|
||||
BrowserRouter,
|
||||
Routes,
|
||||
Route,
|
||||
} from "react-router-dom";
|
||||
|
||||
import ProcessGroups from "./routes/ProcessGroups"
|
||||
import ProcessGroupShow from "./routes/ProcessGroupShow"
|
||||
import ProcessGroupNew from "./routes/ProcessGroupNew"
|
||||
import ProcessGroupEdit from "./routes/ProcessGroupEdit"
|
||||
import ProcessModelShow from "./routes/ProcessModelShow"
|
||||
import ProcessModelEditDiagram from "./routes/ProcessModelEditDiagram"
|
||||
import ProcessInstanceList from "./routes/ProcessInstanceList"
|
||||
import ProcessInstanceReport from "./routes/ProcessInstanceReport"
|
||||
import ProcessModelNew from "./routes/ProcessModelNew"
|
||||
import ProcessModelEdit from "./routes/ProcessModelEdit"
|
||||
import ProcessInstanceShow from "./routes/ProcessInstanceShow"
|
||||
import ErrorBoundary from "./components/ErrorBoundary"
|
||||
|
||||
import { Container } from 'react-bootstrap'
|
||||
import ProcessGroups from './routes/ProcessGroups';
|
||||
import ProcessGroupShow from './routes/ProcessGroupShow';
|
||||
import ProcessGroupNew from './routes/ProcessGroupNew';
|
||||
import ProcessGroupEdit from './routes/ProcessGroupEdit';
|
||||
import ProcessModelShow from './routes/ProcessModelShow';
|
||||
import ProcessModelEditDiagram from './routes/ProcessModelEditDiagram';
|
||||
import ProcessInstanceList from './routes/ProcessInstanceList';
|
||||
import ProcessInstanceReport from './routes/ProcessInstanceReport';
|
||||
import ProcessModelNew from './routes/ProcessModelNew';
|
||||
import ProcessModelEdit from './routes/ProcessModelEdit';
|
||||
import ProcessInstanceShow from './routes/ProcessInstanceShow';
|
||||
import ErrorBoundary from './components/ErrorBoundary';
|
||||
|
||||
import logo from './logo.svg';
|
||||
|
||||
const root = ReactDOMClient.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
@ -40,18 +34,48 @@ root.render(
|
||||
<Route path="/" element={<ProcessGroups />} />
|
||||
|
||||
<Route path="process-groups" element={<ProcessGroups />} />
|
||||
<Route path="process-groups/:process_group_id" element={<ProcessGroupShow />} />
|
||||
<Route
|
||||
path="process-groups/:process_group_id"
|
||||
element={<ProcessGroupShow />}
|
||||
/>
|
||||
<Route path="process-groups/new" element={<ProcessGroupNew />} />
|
||||
<Route path="process-groups/:process_group_id/edit" element={<ProcessGroupEdit />} />
|
||||
<Route
|
||||
path="process-groups/:process_group_id/edit"
|
||||
element={<ProcessGroupEdit />}
|
||||
/>
|
||||
|
||||
<Route path="process-models/:process_group_id/new" element={<ProcessModelNew />} />
|
||||
<Route path="process-models/:process_group_id/:process_model_id" element={<ProcessModelShow />} />
|
||||
<Route path="process-models/:process_group_id/:process_model_id/file" element={<ProcessModelEditDiagram />} />
|
||||
<Route path="process-models/:process_group_id/:process_model_id/file/:file_name" element={<ProcessModelEditDiagram />} />
|
||||
<Route path="process-models/:process_group_id/:process_model_id/process-instances" element={<ProcessInstanceList />} />
|
||||
<Route path="process-models/:process_group_id/:process_model_id/process-instances/report" element={<ProcessInstanceReport />} />
|
||||
<Route path="process-models/:process_group_id/:process_model_id/edit" element={<ProcessModelEdit />} />
|
||||
<Route path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id" element={<ProcessInstanceShow />} />
|
||||
<Route
|
||||
path="process-models/:process_group_id/new"
|
||||
element={<ProcessModelNew />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id"
|
||||
element={<ProcessModelShow />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/file"
|
||||
element={<ProcessModelEditDiagram />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/file/:file_name"
|
||||
element={<ProcessModelEditDiagram />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances"
|
||||
element={<ProcessInstanceList />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances/report"
|
||||
element={<ProcessInstanceReport />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/edit"
|
||||
element={<ProcessModelEdit />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id"
|
||||
element={<ProcessInstanceShow />}
|
||||
/>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</ErrorBoundary>
|
||||
|
@ -10,34 +10,44 @@ import {
|
||||
DmnPropertiesProviderModule,
|
||||
} from 'dmn-js-properties-panel';
|
||||
|
||||
import React, { useRef, useEffect, useState } from "react";
|
||||
import { BACKEND_BASE_URL } from './config';
|
||||
import { HOT_AUTH_TOKEN } from './config';
|
||||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import spiffworkflowIO from 'bpmn-js-spiffworkflow/app/spiffworkflow/InputOutput';
|
||||
import spiffworkflowPanel from 'bpmn-js-spiffworkflow/app/spiffworkflow/PropertiesPanel';
|
||||
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import PropTypes from 'prop-types';
|
||||
import { HOT_AUTH_TOKEN, BACKEND_BASE_URL } from './config';
|
||||
|
||||
import "bpmn-js/dist/assets/diagram-js.css";
|
||||
import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
|
||||
import "bpmn-js-properties-panel/dist/assets/properties-panel.css"
|
||||
import 'bpmn-js/dist/assets/diagram-js.css';
|
||||
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
|
||||
import 'bpmn-js-properties-panel/dist/assets/properties-panel.css';
|
||||
import './bpmn-js-properties-panel.css';
|
||||
import "bpmn-js/dist/assets/bpmn-js.css";
|
||||
import 'bpmn-js/dist/assets/bpmn-js.css';
|
||||
|
||||
import "dmn-js/dist/assets/diagram-js.css";
|
||||
import "dmn-js/dist/assets/dmn-js-decision-table-controls.css";
|
||||
import "dmn-js/dist/assets/dmn-js-decision-table.css";
|
||||
import "dmn-js/dist/assets/dmn-js-drd.css";
|
||||
import "dmn-js/dist/assets/dmn-js-literal-expression.css";
|
||||
import "dmn-js/dist/assets/dmn-js-shared.css";
|
||||
import "dmn-js/dist/assets/dmn-font/css/dmn-embedded.css";
|
||||
import "dmn-js-properties-panel/dist/assets/properties-panel.css"
|
||||
import 'dmn-js/dist/assets/diagram-js.css';
|
||||
import 'dmn-js/dist/assets/dmn-js-decision-table-controls.css';
|
||||
import 'dmn-js/dist/assets/dmn-js-decision-table.css';
|
||||
import 'dmn-js/dist/assets/dmn-js-drd.css';
|
||||
import 'dmn-js/dist/assets/dmn-js-literal-expression.css';
|
||||
import 'dmn-js/dist/assets/dmn-js-shared.css';
|
||||
import 'dmn-js/dist/assets/dmn-font/css/dmn-embedded.css';
|
||||
import 'dmn-js-properties-panel/dist/assets/properties-panel.css';
|
||||
|
||||
import "bpmn-js-spiffworkflow/app/css/app.css"
|
||||
import 'bpmn-js-spiffworkflow/app/css/app.css';
|
||||
|
||||
// https://codesandbox.io/s/quizzical-lake-szfyo?file=/src/App.js was a handy reference
|
||||
export default function ReactDiagramEditor(props) {
|
||||
const [diagramXML, setDiagramXML] = useState("");
|
||||
export default function ReactDiagramEditor({
|
||||
processModelId,
|
||||
processGroupId,
|
||||
saveDiagram,
|
||||
diagramType,
|
||||
|
||||
diagramXML,
|
||||
fileName,
|
||||
onLaunchScriptEditor,
|
||||
url,
|
||||
}) {
|
||||
const [diagramXMLString, setDiagramXMLString] = useState('');
|
||||
const [diagramModelerState, setDiagramModelerState] = useState(null);
|
||||
const [performingXmlUpdates, setPerformingXmlUpdates] = useState(false);
|
||||
|
||||
@ -48,8 +58,8 @@ export default function ReactDiagramEditor(props) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById("diagram-container").innerHTML = "";
|
||||
var temp = document.createElement('template');
|
||||
document.getElementById('diagram-container').innerHTML = '';
|
||||
const temp = document.createElement('template');
|
||||
|
||||
temp.innerHTML = `
|
||||
<div class="content with-diagram" id="js-drop-zone">
|
||||
@ -57,61 +67,48 @@ export default function ReactDiagramEditor(props) {
|
||||
style="border:1px solid #000000; height:90vh; width:90vw; margin:auto;"></div>
|
||||
<div class="properties-panel-parent" id="js-properties-panel"></div>
|
||||
</div>
|
||||
`
|
||||
`;
|
||||
|
||||
var frag = temp.content;
|
||||
document.getElementById("diagram-container").appendChild(frag);
|
||||
const frag = temp.content;
|
||||
document.getElementById('diagram-container').appendChild(frag);
|
||||
|
||||
let diagramModeler = null;
|
||||
|
||||
if (props.diagramType === "bpmn") {
|
||||
if (diagramType === 'bpmn') {
|
||||
diagramModeler = new BpmnModeler({
|
||||
container: "#canvas",
|
||||
container: '#canvas',
|
||||
keyboard: {
|
||||
bindTo: document
|
||||
bindTo: document,
|
||||
},
|
||||
propertiesPanel: {
|
||||
parent: '#js-properties-panel'
|
||||
parent: '#js-properties-panel',
|
||||
},
|
||||
additionalModules: [
|
||||
BpmnPropertiesPanelModule,
|
||||
BpmnPropertiesProviderModule,
|
||||
spiffworkflowIO,
|
||||
spiffworkflowPanel
|
||||
spiffworkflowPanel,
|
||||
],
|
||||
});
|
||||
} else if (props.diagramType === "dmn") {
|
||||
} else if (diagramType === 'dmn') {
|
||||
diagramModeler = new DmnModeler({
|
||||
container: "#canvas",
|
||||
container: '#canvas',
|
||||
keyboard: {
|
||||
bindTo: document
|
||||
bindTo: document,
|
||||
},
|
||||
drd: {
|
||||
propertiesPanel: {
|
||||
parent: '#js-properties-panel'
|
||||
parent: '#js-properties-panel',
|
||||
},
|
||||
additionalModules: [
|
||||
DmnPropertiesPanelModule,
|
||||
DmnPropertiesProviderModule,
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
setDiagramModelerState(diagramModeler);
|
||||
|
||||
diagramModeler.on('launch.script.editor', (event) => {
|
||||
const {
|
||||
error,
|
||||
element,
|
||||
} = event;
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
handleLaunchScriptEditor(element);
|
||||
});
|
||||
|
||||
function handleLaunchScriptEditor(element) {
|
||||
const { onLaunchScriptEditor } = props;
|
||||
if (onLaunchScriptEditor) {
|
||||
setPerformingXmlUpdates(true);
|
||||
const modeling = diagramModeler.get('modeling');
|
||||
@ -119,108 +116,150 @@ export default function ReactDiagramEditor(props) {
|
||||
}
|
||||
}
|
||||
|
||||
}, [props, diagramModelerState])
|
||||
setDiagramModelerState(diagramModeler);
|
||||
|
||||
diagramModeler.on('launch.script.editor', (event) => {
|
||||
const { error, element } = event;
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
handleLaunchScriptEditor(element);
|
||||
});
|
||||
}, [diagramModelerState, diagramType, onLaunchScriptEditor]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!diagramModelerState) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
if (performingXmlUpdates) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function handleError(err) {
|
||||
console.log('ERROR:', err);
|
||||
}
|
||||
|
||||
diagramModelerState.on('import.done', (event) => {
|
||||
const {
|
||||
error,
|
||||
} = event;
|
||||
const { error } = event;
|
||||
|
||||
if (error) {
|
||||
return handleError(error);
|
||||
handleError(error);
|
||||
return;
|
||||
}
|
||||
|
||||
let modeler = diagramModelerState;
|
||||
if (props.diagramType === "dmn") {
|
||||
if (diagramType === 'dmn') {
|
||||
modeler = diagramModelerState.getActiveViewer();
|
||||
}
|
||||
|
||||
// only get the canvas if the dmn active viewer is actually
|
||||
// a Modeler and not an Editor which is what it will when we are
|
||||
// actively editing a decision table
|
||||
if (modeler.constructor.name === "Modeler") {
|
||||
if (modeler.constructor.name === 'Modeler') {
|
||||
modeler.get('canvas').zoom('fit-viewport');
|
||||
}
|
||||
});
|
||||
|
||||
var diagramXMLToUse = props.diagramXML || diagramXML
|
||||
if (diagramXMLToUse) {
|
||||
if (!diagramXML) {
|
||||
setDiagramXML(diagramXMLToUse);
|
||||
}
|
||||
return displayDiagram(diagramModelerState, diagramXMLToUse);
|
||||
}
|
||||
|
||||
if (!diagramXML) {
|
||||
if (props.url) {
|
||||
return fetchDiagramFromURL(props.url);
|
||||
} else if (props.fileName) {
|
||||
return fetchDiagramFromJsonAPI(props.process_group_id, props.process_model_id, props.fileName);
|
||||
} else {
|
||||
let newDiagramFileName = 'new_bpmn_diagram.bpmn';
|
||||
if (props.diagramType === "dmn" ) {
|
||||
newDiagramFileName = 'new_dmn_diagram.dmn';
|
||||
}
|
||||
return fetchDiagramFromURL(process.env.PUBLIC_URL + '/' + newDiagramFileName);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
diagramModelerState.destroy();
|
||||
}
|
||||
|
||||
function fetchDiagramFromURL(url) {
|
||||
fetch(url)
|
||||
.then(response => response.text())
|
||||
.then(text => setDiagramXML(text))
|
||||
.catch(err => handleError(err));
|
||||
}
|
||||
|
||||
function fetchDiagramFromJsonAPI(processGroupId, processModelId, fileName) {
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${processGroupId}/${processModelId}/file/${fileName}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(response_json => setDiagramXML(response_json.file_contents))
|
||||
.catch(err => handleError(err));
|
||||
}
|
||||
|
||||
function handleError(err) {
|
||||
const { onError } = props;
|
||||
if (onError) {
|
||||
onError(err);
|
||||
}
|
||||
}
|
||||
|
||||
function displayDiagram(diagramModelerToUse, diagramXMLToDisplay) {
|
||||
if (alreadyImportedXmlRef.current) {
|
||||
return;
|
||||
}
|
||||
diagramModelerToUse.importXML(diagramXMLToDisplay);
|
||||
alreadyImportedXmlRef.current = true
|
||||
alreadyImportedXmlRef.current = true;
|
||||
}
|
||||
}, [props, diagramXML, diagramModelerState, performingXmlUpdates]);
|
||||
|
||||
function fetchDiagramFromURL(urlToUse) {
|
||||
fetch(urlToUse)
|
||||
.then((response) => response.text())
|
||||
.then((text) => setDiagramXMLString(text))
|
||||
.catch((err) => handleError(err));
|
||||
}
|
||||
|
||||
function fetchDiagramFromJsonAPI() {
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${processGroupId}/${processModelId}/file/${fileName}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((responseJson) => setDiagramXMLString(responseJson.file_contents))
|
||||
.catch((err) => handleError(err));
|
||||
}
|
||||
|
||||
const diagramXMLToUse = diagramXML || diagramXMLString;
|
||||
if (diagramXMLToUse) {
|
||||
if (!diagramXMLString) {
|
||||
setDiagramXMLString(diagramXMLToUse);
|
||||
}
|
||||
displayDiagram(diagramModelerState, diagramXMLToUse);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!diagramXMLString) {
|
||||
if (url) {
|
||||
fetchDiagramFromURL(url);
|
||||
return undefined;
|
||||
}
|
||||
if (fileName) {
|
||||
fetchDiagramFromJsonAPI();
|
||||
return undefined;
|
||||
}
|
||||
let newDiagramFileName = 'new_bpmn_diagram.bpmn';
|
||||
if (diagramType === 'dmn') {
|
||||
newDiagramFileName = 'new_dmn_diagram.dmn';
|
||||
}
|
||||
fetchDiagramFromURL(`${process.env.PUBLIC_URL}/${newDiagramFileName}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return () => {
|
||||
diagramModelerState.destroy();
|
||||
};
|
||||
}, [
|
||||
diagramModelerState,
|
||||
diagramType,
|
||||
diagramXML,
|
||||
diagramXMLString,
|
||||
fileName,
|
||||
performingXmlUpdates,
|
||||
processGroupId,
|
||||
processModelId,
|
||||
url,
|
||||
]);
|
||||
|
||||
function handleSave() {
|
||||
diagramModelerState.saveXML({ format: true })
|
||||
.then(xmlObject => {
|
||||
props.saveDiagram(xmlObject.xml);
|
||||
})
|
||||
diagramModelerState.saveXML({ format: true }).then((xmlObject) => {
|
||||
saveDiagram(xmlObject.xml);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={handleSave} variant="danger">Save</Button>
|
||||
<Button onClick={handleSave} variant="danger">
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDiagramEditor.propTypes = {
|
||||
processModelId: PropTypes.string.isRequired,
|
||||
processGroupId: PropTypes.string.isRequired,
|
||||
saveDiagram: PropTypes.func.isRequired,
|
||||
diagramType: PropTypes.string.isRequired,
|
||||
|
||||
diagramXML: PropTypes.string,
|
||||
fileName: PropTypes.string,
|
||||
onLaunchScriptEditor: PropTypes.func,
|
||||
url: PropTypes.string,
|
||||
};
|
||||
|
||||
ReactDiagramEditor.defaultProps = {
|
||||
diagramXML: null,
|
||||
fileName: null,
|
||||
onLaunchScriptEditor: null,
|
||||
url: null,
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
const reportWebVitals = (onPerfEntry) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
|
@ -1,19 +1,21 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN, STANDARD_HEADERS } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import { Button, Stack } from 'react-bootstrap'
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { Button, Stack } from 'react-bootstrap';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN, STANDARD_HEADERS } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
|
||||
export default function ProcessGroupEdit() {
|
||||
const [displayName, setDisplayName] = useState("");
|
||||
const [displayName, setDisplayName] = useState('');
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [processGroup, setProcessGroup] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${BACKEND_BASE_URL}/process-groups/${params.process_group_id}`, STANDARD_HEADERS)
|
||||
.then(res => res.json())
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-groups/${params.process_group_id}`,
|
||||
STANDARD_HEADERS
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
setProcessGroup(result);
|
||||
@ -22,85 +24,84 @@ export default function ProcessGroupEdit() {
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
);
|
||||
}, [params]);
|
||||
|
||||
const updateProcessGroup = ((event) => {
|
||||
event.preventDefault()
|
||||
const updateProcessGroup = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
fetch(`${BACKEND_BASE_URL}/process-groups/${processGroup.id}`, {
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({
|
||||
display_name: displayName,
|
||||
id: processGroup.id,
|
||||
}),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
navigate(`/process-groups/${processGroup.id}`)
|
||||
},
|
||||
// Note: it's important to handle errors here
|
||||
// instead of a catch() block so that we don't swallow
|
||||
// exceptions from actual bugs in components.
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
)
|
||||
}).then(
|
||||
() => {
|
||||
navigate(`/process-groups/${processGroup.id}`);
|
||||
},
|
||||
// Note: it's important to handle errors here
|
||||
// instead of a catch() block so that we don't swallow
|
||||
// exceptions from actual bugs in components.
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
const deleteProcessGroup = (() => {
|
||||
const deleteProcessGroup = () => {
|
||||
fetch(`${BACKEND_BASE_URL}/process-groups/${processGroup.id}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'DELETE',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
navigate(`/process-groups`);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
});
|
||||
}).then(
|
||||
() => {
|
||||
navigate(`/process-groups`);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const onDisplayNameChanged = ((newDisplayName) => {
|
||||
const onDisplayNameChanged = (newDisplayName) => {
|
||||
setDisplayName(newDisplayName);
|
||||
});
|
||||
};
|
||||
|
||||
if (processGroup) {
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb processGroupId={processGroup.id} />
|
||||
<h2>Edit Process Group: {processGroup.id}</h2>
|
||||
<form onSubmit={updateProcessGroup}>
|
||||
<label>Display Name:</label>
|
||||
<input
|
||||
name='display_name'
|
||||
type='text'
|
||||
name="display_name"
|
||||
type="text"
|
||||
value={displayName}
|
||||
onChange={e => onDisplayNameChanged(e.target.value)}
|
||||
onChange={(e) => onDisplayNameChanged(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<Button type="submit">Submit</Button>
|
||||
<Button variant="secondary" href={`/process-groups/${processGroup.id}`}>Cancel</Button>
|
||||
<Button onClick={deleteProcessGroup} variant="danger">Delete Process Group</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
href={`/process-groups/${processGroup.id}`}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={deleteProcessGroup} variant="danger">
|
||||
Delete Process Group
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
</main>
|
||||
);
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,71 +1,70 @@
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import { slugifyString } from '../helpers'
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import { slugifyString } from '../helpers';
|
||||
|
||||
export default function ProcessGroupNew() {
|
||||
const [identifier, setIdentifier] = useState("");
|
||||
const [identifier, setIdentifier] = useState('');
|
||||
const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] = useState(false);
|
||||
const [displayName, setDisplayName] = useState("");
|
||||
const [displayName, setDisplayName] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const addProcessGroup = ((event) => {
|
||||
event.preventDefault()
|
||||
const addProcessGroup = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
fetch(`${BACKEND_BASE_URL}/process-groups`, {
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
id: identifier,
|
||||
display_name: displayName,
|
||||
}),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
navigate(`/process-groups/${identifier}`)
|
||||
},
|
||||
// Note: it's important to handle errors here
|
||||
// instead of a catch() block so that we don't swallow
|
||||
// exceptions from actual bugs in components.
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
)
|
||||
}).then(
|
||||
() => {
|
||||
navigate(`/process-groups/${identifier}`);
|
||||
},
|
||||
// Note: it's important to handle errors here
|
||||
// instead of a catch() block so that we don't swallow
|
||||
// exceptions from actual bugs in components.
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
const onDisplayNameChanged = ((newDisplayName) => {
|
||||
const onDisplayNameChanged = (newDisplayName) => {
|
||||
setDisplayName(newDisplayName);
|
||||
if (!idHasBeenUpdatedByUser) {
|
||||
setIdentifier(slugifyString(newDisplayName));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb />
|
||||
<h2>Add Process Group</h2>
|
||||
<form onSubmit={addProcessGroup}>
|
||||
<label>Display Name:</label>
|
||||
<input
|
||||
name='display_name'
|
||||
type='text'
|
||||
name="display_name"
|
||||
type="text"
|
||||
value={displayName}
|
||||
onChange={e => onDisplayNameChanged(e.target.value)}
|
||||
onChange={(e) => onDisplayNameChanged(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<label>ID:</label>
|
||||
<input
|
||||
name='id'
|
||||
type='text'
|
||||
name="id"
|
||||
type="text"
|
||||
value={identifier}
|
||||
onChange={e => { setIdentifier(e.target.value); setIdHasBeenUpdatedByUser(true)} }
|
||||
onChange={(e) => {
|
||||
setIdentifier(e.target.value);
|
||||
setIdHasBeenUpdatedByUser(true);
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
<button type="submit">Submit</button>
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Link, useSearchParams } from "react-router-dom";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import { useParams } from "react-router-dom";
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import { Button, Table, Stack } from 'react-bootstrap'
|
||||
import PaginationForTable, { DEFAULT_PER_PAGE, DEFAULT_PAGE } from '../components/PaginationForTable'
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link, useSearchParams, useParams } from 'react-router-dom';
|
||||
import { Button, Table, Stack } from 'react-bootstrap';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import PaginationForTable, {
|
||||
DEFAULT_PER_PAGE,
|
||||
DEFAULT_PAGE,
|
||||
} from '../components/PaginationForTable';
|
||||
|
||||
export default function ProcessGroupShow() {
|
||||
const params = useParams();
|
||||
@ -16,92 +17,107 @@ export default function ProcessGroupShow() {
|
||||
const [pagination, setPagination] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const page = searchParams.get('page') || DEFAULT_PAGE;
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE, 10);
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
fetch(`${BACKEND_BASE_URL}/process-groups/${params.process_group_id}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
setProcessGroup(result);
|
||||
fetch(`${BACKEND_BASE_URL}/process-groups/${params.process_group_id}/process-models?per_page=${perPage}&page=${page}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
(processGroupResult) => {
|
||||
setProcessGroup(processGroupResult);
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-groups/${params.process_group_id}/process-models?per_page=${perPage}&page=${page}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
setProcessModels(result.results);
|
||||
setPagination(result.pagination);
|
||||
(processModelResult) => {
|
||||
setProcessModels(processModelResult.results);
|
||||
setPagination(processModelResult.pagination);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
);
|
||||
}, [params, searchParams]);
|
||||
|
||||
const buildTable = (() => {
|
||||
const rows = processModels.map((row,index) => {
|
||||
const buildTable = () => {
|
||||
const rows = processModels.map((row) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
<tr key={row.id}>
|
||||
<td>
|
||||
<Link to={`/process-models/${processGroup.id}/${row.id}`}>{row.id}</Link>
|
||||
<Link to={`/process-models/${processGroup.id}/${row.id}`}>
|
||||
{row.id}
|
||||
</Link>
|
||||
</td>
|
||||
<td>{row.display_name}</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
return(
|
||||
);
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<h3>Process Models</h3>
|
||||
<Table striped bordered >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Process Model Id</th>
|
||||
<th>Display Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
</Table>
|
||||
<h3>Process Models</h3>
|
||||
<Table striped bordered>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Process Model Id</th>
|
||||
<th>Display Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{rows}</tbody>
|
||||
</Table>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
if (processGroup && pagination) {
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE);
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE, 10);
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb processGroupId={processGroup.id} />
|
||||
<h2>Process Group: {processGroup.id}</h2>
|
||||
<ul>
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<Button href={`/process-models/${processGroup.id}/new`}>Add a process model</Button>
|
||||
<Button href={`/process-groups/${processGroup.id}/edit`} variant="secondary">Edit process group</Button>
|
||||
</Stack>
|
||||
<br />
|
||||
<br />
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
path={`/process-groups/${processGroup.id}`}
|
||||
/>
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<Button href={`/process-models/${processGroup.id}/new`}>
|
||||
Add a process model
|
||||
</Button>
|
||||
<Button
|
||||
href={`/process-groups/${processGroup.id}/edit`}
|
||||
variant="secondary"
|
||||
>
|
||||
Edit process group
|
||||
</Button>
|
||||
</Stack>
|
||||
<br />
|
||||
<br />
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
path={`/process-groups/${processGroup.id}`}
|
||||
/>
|
||||
</ul>
|
||||
</main>
|
||||
);
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Link, useSearchParams } from "react-router-dom";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import { Button, Table } from 'react-bootstrap'
|
||||
import PaginationForTable, { DEFAULT_PER_PAGE, DEFAULT_PAGE } from '../components/PaginationForTable'
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link, useSearchParams } from 'react-router-dom';
|
||||
import { Button, Table } from 'react-bootstrap';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import PaginationForTable, {
|
||||
DEFAULT_PER_PAGE,
|
||||
DEFAULT_PAGE,
|
||||
} from '../components/PaginationForTable';
|
||||
|
||||
// Example process group json
|
||||
// {'admin': False, 'display_name': 'Test Workflows', 'display_order': 0, 'id': 'test_process_group'}
|
||||
@ -15,14 +17,20 @@ export default function ProcessGroups() {
|
||||
const [pagination, setPagination] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const page = searchParams.get('page') || DEFAULT_PAGE;
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
fetch(`${BACKEND_BASE_URL}/process-groups?per_page=${perPage}&page=${page}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE, 10);
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-groups?per_page=${perPage}&page=${page}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
setProcessGroups(result.results);
|
||||
@ -31,43 +39,44 @@ export default function ProcessGroups() {
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
)
|
||||
);
|
||||
}, [searchParams]);
|
||||
|
||||
const buildTable = (() => {
|
||||
const rows = processGroups.map((row,index) => {
|
||||
const buildTable = () => {
|
||||
const rows = processGroups.map((row) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
<tr key={row.id}>
|
||||
<td>
|
||||
<Link to={`/process-groups/${row.id}`}>{row.id}</Link>
|
||||
</td>
|
||||
<td>{row.display_name}</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
return(
|
||||
<Table striped bordered >
|
||||
);
|
||||
});
|
||||
return (
|
||||
<Table striped bordered>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Process Group Id</th>
|
||||
<th>Display Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
<tbody>{rows}</tbody>
|
||||
</Table>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
if (processGroups?.length > 0) {
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE);
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE, 10);
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb />
|
||||
<h2>Process Groups</h2>
|
||||
<Button href={`/process-groups/new`}>Add a process group</Button>
|
||||
<Button href="/process-groups/new">Add a process group</Button>
|
||||
<br />
|
||||
<br />
|
||||
<PaginationForTable
|
||||
@ -75,11 +84,9 @@ export default function ProcessGroups() {
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
path={`/process-groups`}
|
||||
path="/process-groups"
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,28 @@
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { Link, useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
Link,
|
||||
useNavigate,
|
||||
useParams,
|
||||
useSearchParams,
|
||||
} from 'react-router-dom';
|
||||
|
||||
import { BACKEND_BASE_URL, PROCESS_STATUSES, DATE_FORMAT } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import { Button, Table, Stack, Dropdown } from 'react-bootstrap';
|
||||
import DatePicker from 'react-datepicker';
|
||||
import { format } from 'date-fns';
|
||||
import {
|
||||
BACKEND_BASE_URL,
|
||||
PROCESS_STATUSES,
|
||||
DATE_FORMAT,
|
||||
HOT_AUTH_TOKEN,
|
||||
} from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import { Button, Table, Stack, Dropdown } from 'react-bootstrap';
|
||||
import DatePicker from "react-datepicker";
|
||||
import { convertDateToSeconds } from "../helpers";
|
||||
import { convertDateToSeconds } from '../helpers';
|
||||
|
||||
import PaginationForTable, { DEFAULT_PER_PAGE, DEFAULT_PAGE } from '../components/PaginationForTable'
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import { format } from "date-fns";
|
||||
import PaginationForTable, {
|
||||
DEFAULT_PER_PAGE,
|
||||
DEFAULT_PAGE,
|
||||
} from '../components/PaginationForTable';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
|
||||
export default function ProcessInstanceList() {
|
||||
const params = useParams();
|
||||
@ -22,56 +34,71 @@ export default function ProcessInstanceList() {
|
||||
|
||||
const oneHourInSeconds = 3600;
|
||||
const oneMonthInSeconds = oneHourInSeconds * 24 * 30;
|
||||
const [startFrom, setStartFrom] = useState(convertDateToSeconds(new Date()) - oneMonthInSeconds);
|
||||
const [startTill, setStartTill] = useState(convertDateToSeconds(new Date()) + oneHourInSeconds);
|
||||
const [endFrom, setEndFrom] = useState(convertDateToSeconds(new Date()) - oneMonthInSeconds);
|
||||
const [endTill, setEndTill] = useState(convertDateToSeconds(new Date()) + oneHourInSeconds);
|
||||
const [startFrom, setStartFrom] = useState(
|
||||
convertDateToSeconds(new Date()) - oneMonthInSeconds
|
||||
);
|
||||
const [startTill, setStartTill] = useState(
|
||||
convertDateToSeconds(new Date()) + oneHourInSeconds
|
||||
);
|
||||
const [endFrom, setEndFrom] = useState(
|
||||
convertDateToSeconds(new Date()) - oneMonthInSeconds
|
||||
);
|
||||
const [endTill, setEndTill] = useState(
|
||||
convertDateToSeconds(new Date()) + oneHourInSeconds
|
||||
);
|
||||
|
||||
const [processStatus, setProcessStatus] = useState(PROCESS_STATUSES[0]);
|
||||
const parametersToAlwaysFilterBy = useMemo(() => {
|
||||
return {
|
||||
'start_from': setStartFrom,
|
||||
'start_till': setStartTill,
|
||||
'end_from': setEndFrom,
|
||||
'end_till': setEndTill,
|
||||
}
|
||||
start_from: setStartFrom,
|
||||
start_till: setStartTill,
|
||||
end_from: setEndFrom,
|
||||
end_till: setEndTill,
|
||||
};
|
||||
}, [setStartFrom, setStartTill, setEndFrom, setEndTill]);
|
||||
|
||||
useEffect(() => {
|
||||
getProcessInstances();
|
||||
|
||||
function getProcessInstances() {
|
||||
const page = searchParams.get('page') || DEFAULT_PAGE;
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
let queryParamString = `per_page=${perPage}&page=${page}`;
|
||||
|
||||
for (const paramName in parametersToAlwaysFilterBy) {
|
||||
const functionToCall = parametersToAlwaysFilterBy[paramName]
|
||||
Object.keys(parametersToAlwaysFilterBy).forEach((paramName) => {
|
||||
const functionToCall = parametersToAlwaysFilterBy[paramName];
|
||||
let defaultValue = null;
|
||||
if (paramName.endsWith("_from")) {
|
||||
if (paramName.endsWith('_from')) {
|
||||
defaultValue = convertDateToSeconds(new Date()) - oneMonthInSeconds;
|
||||
} else if (paramName.endsWith("_till")) {
|
||||
} else if (paramName.endsWith('_till')) {
|
||||
defaultValue = convertDateToSeconds(new Date()) + oneHourInSeconds;
|
||||
}
|
||||
let searchParamValue = searchParams.get(paramName);
|
||||
const searchParamValue = searchParams.get(paramName);
|
||||
if (searchParamValue) {
|
||||
queryParamString += `&${paramName}=${searchParamValue}`;
|
||||
functionToCall(searchParamValue);
|
||||
} else if (defaultValue) {
|
||||
queryParamString += `&${paramName}=${defaultValue}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (searchParams.get('process_status')) {
|
||||
queryParamString += `&process_status=${searchParams.get('process_status')}`;
|
||||
queryParamString += `&process_status=${searchParams.get(
|
||||
'process_status'
|
||||
)}`;
|
||||
setProcessStatus(searchParams.get('process_status'));
|
||||
}
|
||||
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/process-instances?${queryParamString}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/process-instances?${queryParamString}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
const processInstancesFromApi = result.results;
|
||||
@ -81,14 +108,25 @@ export default function ProcessInstanceList() {
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [searchParams, params, oneMonthInSeconds, oneHourInSeconds, parametersToAlwaysFilterBy]);
|
||||
|
||||
const handleFilter = ((event) => {
|
||||
getProcessInstances();
|
||||
}, [
|
||||
searchParams,
|
||||
params,
|
||||
oneMonthInSeconds,
|
||||
oneHourInSeconds,
|
||||
parametersToAlwaysFilterBy,
|
||||
]);
|
||||
|
||||
const handleFilter = (event) => {
|
||||
event.preventDefault();
|
||||
const page = searchParams.get('page') || DEFAULT_PAGE;
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
let queryParamString = `per_page=${perPage}&page=${page}`;
|
||||
|
||||
if (startFrom) {
|
||||
@ -103,14 +141,16 @@ export default function ProcessInstanceList() {
|
||||
if (endTill) {
|
||||
queryParamString += `&end_till=${endTill}`;
|
||||
}
|
||||
if (processStatus && processStatus !== "all") {
|
||||
if (processStatus && processStatus !== 'all') {
|
||||
queryParamString += `&process_status=${processStatus}`;
|
||||
}
|
||||
|
||||
navigate(`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances?${queryParamString}`)
|
||||
});
|
||||
navigate(
|
||||
`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances?${queryParamString}`
|
||||
);
|
||||
};
|
||||
|
||||
const dateComponent = ((labelString, name, initialDate, onChangeFunction) => {
|
||||
const dateComponent = (labelString, name, initialDate, onChangeFunction) => {
|
||||
return (
|
||||
<Stack className="ms-auto" direction="horizontal" gap={3}>
|
||||
<label className="text-nowrap">{labelString}</label>
|
||||
@ -122,27 +162,37 @@ export default function ProcessInstanceList() {
|
||||
dateFormat={DATE_FORMAT}
|
||||
/>
|
||||
</Stack>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
const getSearchParamsAsQueryString = (() => {
|
||||
let queryParamString = "";
|
||||
for (const paramName in parametersToAlwaysFilterBy) {
|
||||
let searchParamValue = searchParams.get(paramName);
|
||||
const getSearchParamsAsQueryString = () => {
|
||||
let queryParamString = '';
|
||||
Object.keys(parametersToAlwaysFilterBy).forEach((paramName) => {
|
||||
const searchParamValue = searchParams.get(paramName);
|
||||
if (searchParamValue) {
|
||||
queryParamString += `&${paramName}=${searchParamValue}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
return queryParamString;
|
||||
});
|
||||
};
|
||||
|
||||
const filterOptions = (() => {
|
||||
const processStatusesRows = PROCESS_STATUSES.map(processStatusOption => {
|
||||
const filterOptions = () => {
|
||||
const processStatusesRows = PROCESS_STATUSES.map((processStatusOption) => {
|
||||
if (processStatusOption === processStatus) {
|
||||
return <Dropdown.Item key={processStatusOption} active>{processStatusOption}</Dropdown.Item>
|
||||
} else {
|
||||
return <Dropdown.Item key={processStatusOption} onClick={(e) => setProcessStatus(processStatusOption)}>{processStatusOption}</Dropdown.Item>
|
||||
return (
|
||||
<Dropdown.Item key={processStatusOption} active>
|
||||
{processStatusOption}
|
||||
</Dropdown.Item>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Dropdown.Item
|
||||
key={processStatusOption}
|
||||
onClick={() => setProcessStatus(processStatusOption)}
|
||||
>
|
||||
{processStatusOption}
|
||||
</Dropdown.Item>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
@ -151,17 +201,25 @@ export default function ProcessInstanceList() {
|
||||
<div className="col">
|
||||
<form onSubmit={handleFilter}>
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
{dateComponent("Start Range: ", "start-from", startFrom, setStartFrom)}
|
||||
{dateComponent("-", "start-till", startTill, setStartTill)}
|
||||
{dateComponent(
|
||||
'Start Range: ',
|
||||
'start-from',
|
||||
startFrom,
|
||||
setStartFrom
|
||||
)}
|
||||
{dateComponent('-', 'start-till', startTill, setStartTill)}
|
||||
</Stack>
|
||||
<br />
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
{dateComponent("End Range: ", "end-from", endFrom, setEndFrom)}
|
||||
{dateComponent("-", "end-till", endTill, setEndTill)}
|
||||
{dateComponent('End Range: ', 'end-from', endFrom, setEndFrom)}
|
||||
{dateComponent('-', 'end-till', endTill, setEndTill)}
|
||||
</Stack>
|
||||
<br />
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<Dropdown data-qa="process-status-dropdown" id="process-status-dropdown">
|
||||
<Dropdown
|
||||
data-qa="process-status-dropdown"
|
||||
id="process-status-dropdown"
|
||||
>
|
||||
<Dropdown.Toggle id="process-status" variant="light border">
|
||||
Process Statuses: {processStatus}
|
||||
</Dropdown.Toggle>
|
||||
@ -170,42 +228,48 @@ export default function ProcessInstanceList() {
|
||||
{processStatusesRows}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
<Button className="ms-auto" variant="secondary" type="submit">Filter</Button>
|
||||
<Button className="ms-auto" variant="secondary" type="submit">
|
||||
Filter
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
</div>
|
||||
<div className="col">
|
||||
</div>
|
||||
<div className="col" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
const buildTable = (() => {
|
||||
const rows = processInstances.map((row,i) => {
|
||||
let start_date = 'N/A'
|
||||
if (row.start_in_seconds) {
|
||||
start_date = new Date(row.start_in_seconds * 1000);
|
||||
}
|
||||
let end_date = 'N/A'
|
||||
if (row.end_in_seconds) {
|
||||
end_date = new Date(row.end_in_seconds * 1000);
|
||||
}
|
||||
return (
|
||||
<tr key={i}>
|
||||
const buildTable = () => {
|
||||
const rows = processInstances.map((row) => {
|
||||
let startDate = 'N/A';
|
||||
if (row.start_in_seconds) {
|
||||
startDate = new Date(row.start_in_seconds * 1000);
|
||||
}
|
||||
let endDate = 'N/A';
|
||||
if (row.end_in_seconds) {
|
||||
endDate = new Date(row.end_in_seconds * 1000);
|
||||
}
|
||||
return (
|
||||
<tr key={row.id}>
|
||||
<td>
|
||||
<Link data-qa="process-instance-show-link" to={`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${row.id}`}>{row.id}</Link>
|
||||
<Link
|
||||
data-qa="process-instance-show-link"
|
||||
to={`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${row.id}`}
|
||||
>
|
||||
{row.id}
|
||||
</Link>
|
||||
</td>
|
||||
<td>{row.process_model_identifier}</td>
|
||||
<td>{row.process_group_id}</td>
|
||||
<td>{format(start_date, DATE_FORMAT)}</td>
|
||||
<td>{format(end_date, DATE_FORMAT)}</td>
|
||||
<td>{format(startDate, DATE_FORMAT)}</td>
|
||||
<td>{format(endDate, DATE_FORMAT)}</td>
|
||||
<td data-qa="process-instance-status">{row.status}</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
return(
|
||||
<Table striped bordered >
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<Table striped bordered>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Process Instance Id</th>
|
||||
@ -216,36 +280,35 @@ export default function ProcessInstanceList() {
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
<tbody>{rows}</tbody>
|
||||
</Table>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
if (pagination) {
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE);
|
||||
return(
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE, 10);
|
||||
return (
|
||||
<main>
|
||||
<ProcessBreadcrumb
|
||||
processModelId={params.process_model_id}
|
||||
processGroupId={params.process_group_id}
|
||||
linkProcessModel="true"
|
||||
/>
|
||||
<h2>Process Instances for {params.process_model_id}</h2>
|
||||
{filterOptions()}
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
queryParamString={getSearchParamsAsQueryString()}
|
||||
path={`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances`}
|
||||
/>
|
||||
</main>
|
||||
)
|
||||
} else {
|
||||
return(<></>)
|
||||
<ProcessBreadcrumb
|
||||
processModelId={params.process_model_id}
|
||||
processGroupId={params.process_group_id}
|
||||
linkProcessModel="true"
|
||||
/>
|
||||
<h2>Process Instances for {params.process_model_id}</h2>
|
||||
{filterOptions()}
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
queryParamString={getSearchParamsAsQueryString()}
|
||||
path={`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances`}
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +1,72 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useParams, useSearchParams } from "react-router-dom";
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import { Table } from 'react-bootstrap'
|
||||
import { Table } from 'react-bootstrap';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
|
||||
import PaginationForTable, { DEFAULT_PER_PAGE, DEFAULT_PAGE } from '../components/PaginationForTable'
|
||||
import PaginationForTable, {
|
||||
DEFAULT_PER_PAGE,
|
||||
DEFAULT_PAGE,
|
||||
} from '../components/PaginationForTable';
|
||||
|
||||
export default function ProcessInstanceReport() {
|
||||
let params = useParams();
|
||||
let [searchParams] = useSearchParams();
|
||||
const params = useParams();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const [processInstances, setProcessInstances] = useState([]);
|
||||
const [pagination, setPagination] = useState(null);
|
||||
const [processGroupId, setProcessGroupId] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
getProcessInstances();
|
||||
|
||||
function getProcessInstances() {
|
||||
const page = searchParams.get('page') || DEFAULT_PAGE;
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/report?per_page=${perPage}&page=${page}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/report?per_page=${perPage}&page=${page}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
const processInstancesFromApi = result.results;
|
||||
setProcessInstances(processInstancesFromApi);
|
||||
setPagination(result.pagination);
|
||||
if (processInstancesFromApi[0]) {
|
||||
setProcessGroupId(processInstancesFromApi[0].process_group_id)
|
||||
setProcessGroupId(processInstancesFromApi[0].process_group_id);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
getProcessInstances();
|
||||
}, [searchParams, params]);
|
||||
|
||||
const buildTable = (() => {
|
||||
const rows = processInstances.map((row,i) => {
|
||||
return (
|
||||
<tr key={i}>
|
||||
<td>{row.id}</td>
|
||||
<td>{row.data.month}</td>
|
||||
<td>{row.data.milestone}</td>
|
||||
<td>{row.data.req_id}</td>
|
||||
<td>{row.data.feature}</td>
|
||||
<td>{row.data.priority}</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
return(
|
||||
<Table striped bordered >
|
||||
const buildTable = () => {
|
||||
const rows = processInstances.map((row) => {
|
||||
return (
|
||||
<tr key={row.id}>
|
||||
<td>{row.id}</td>
|
||||
<td>{row.data.month}</td>
|
||||
<td>{row.data.milestone}</td>
|
||||
<td>{row.data.req_id}</td>
|
||||
<td>{row.data.feature}</td>
|
||||
<td>{row.data.priority}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<Table striped bordered>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>db id</th>
|
||||
@ -69,34 +77,33 @@ export default function ProcessInstanceReport() {
|
||||
<th>priority</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
<tbody>{rows}</tbody>
|
||||
</Table>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
if (pagination) {
|
||||
const perPage = parseInt(searchParams.get('per_page') || DEFAULT_PER_PAGE);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE);
|
||||
return(
|
||||
const perPage = parseInt(
|
||||
searchParams.get('per_page') || DEFAULT_PER_PAGE,
|
||||
10
|
||||
);
|
||||
const page = parseInt(searchParams.get('page') || DEFAULT_PAGE, 10);
|
||||
return (
|
||||
<main>
|
||||
<ProcessBreadcrumb
|
||||
processModelId={params.process_model_id}
|
||||
processGroupId={processGroupId}
|
||||
linkProcessModel="true"
|
||||
/>
|
||||
<h2>Process Instances for {params.process_model_id}</h2>
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
path={`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/report`}
|
||||
/>
|
||||
</main>
|
||||
)
|
||||
} else {
|
||||
return(<></>)
|
||||
<ProcessBreadcrumb
|
||||
processModelId={params.process_model_id}
|
||||
processGroupId={processGroupId}
|
||||
linkProcessModel="true"
|
||||
/>
|
||||
<h2>Process Instances for {params.process_model_id}</h2>
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
path={`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/report`}
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,42 +1,46 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import React, { useEffect } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
import { Button } from 'react-bootstrap'
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
|
||||
export default function ProcessInstanceShow(props) {
|
||||
export default function ProcessInstanceShow() {
|
||||
const navigate = useNavigate();
|
||||
const params = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
}, []);
|
||||
useEffect(() => {}, []);
|
||||
|
||||
const deleteProcessInstance = (() => {
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
}),
|
||||
method: 'DELETE',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
navigate(`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances`);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
});
|
||||
const deleteProcessInstance = () => {
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'DELETE',
|
||||
}
|
||||
).then(
|
||||
() => {
|
||||
navigate(
|
||||
`/process-models/${params.process_group_id}/${params.process_model_id}/process-instances`
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb
|
||||
processModelId={params.process_model_id}
|
||||
processGroupId={params.process_group_id}
|
||||
linkProcessModel="true"
|
||||
/>
|
||||
<Button onClick={deleteProcessInstance} variant="danger">Delete process instance</Button>
|
||||
<Button onClick={deleteProcessInstance} variant="danger">
|
||||
Delete process instance
|
||||
</Button>
|
||||
</main>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,21 +1,20 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN, STANDARD_HEADERS } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import { Button, Stack } from 'react-bootstrap'
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { Button, Stack } from 'react-bootstrap';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN, STANDARD_HEADERS } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
|
||||
export default function ProcessModelEdit() {
|
||||
const [displayName, setDisplayName] = useState("");
|
||||
const [displayName, setDisplayName] = useState('');
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [processModel, setProcessModel] = useState(null);
|
||||
|
||||
const processModelPath = `process-models/${params.process_group_id}/${params.process_model_id}`
|
||||
const processModelPath = `process-models/${params.process_group_id}/${params.process_model_id}`;
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${BACKEND_BASE_URL}/${processModelPath}`, STANDARD_HEADERS)
|
||||
.then(res => res.json())
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
setProcessModel(result);
|
||||
@ -24,16 +23,16 @@ export default function ProcessModelEdit() {
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
);
|
||||
}, [processModelPath]);
|
||||
|
||||
const updateProcessModel = ((event) => {
|
||||
event.preventDefault()
|
||||
const updateProcessModel = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
fetch(`${BACKEND_BASE_URL}/${processModelPath}`, {
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({
|
||||
@ -45,69 +44,68 @@ export default function ProcessModelEdit() {
|
||||
standalone: processModel.standalone,
|
||||
library: processModel.library,
|
||||
}),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
navigate(`/${processModelPath}`)
|
||||
},
|
||||
// Note: it's important to handle errors here
|
||||
// instead of a catch() block so that we don't swallow
|
||||
// exceptions from actual bugs in components.
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
)
|
||||
}).then(
|
||||
() => {
|
||||
navigate(`/${processModelPath}`);
|
||||
},
|
||||
// Note: it's important to handle errors here
|
||||
// instead of a catch() block so that we don't swallow
|
||||
// exceptions from actual bugs in components.
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
});
|
||||
const deleteProcessModel = () => {
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${processModel.process_group_id}/${processModel.id}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'DELETE',
|
||||
}
|
||||
).then(
|
||||
() => {
|
||||
navigate(`/process-groups/${params.process_group_id}`);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const deleteProcessModel = (() => {
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${processModel.process_group_id}/${processModel.id}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
}),
|
||||
method: 'DELETE',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
navigate(`/process-groups/${params.process_group_id}`);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
const onDisplayNameChanged = ((newDisplayName) => {
|
||||
const onDisplayNameChanged = (newDisplayName) => {
|
||||
setDisplayName(newDisplayName);
|
||||
});
|
||||
};
|
||||
|
||||
if (processModel) {
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb processGroupId={processModel.id} />
|
||||
<h2>Edit Process Group: {processModel.id}</h2>
|
||||
<form onSubmit={updateProcessModel}>
|
||||
<label>Display Name:</label>
|
||||
<input
|
||||
name='display_name'
|
||||
type='text'
|
||||
name="display_name"
|
||||
type="text"
|
||||
value={displayName}
|
||||
onChange={e => onDisplayNameChanged(e.target.value)}
|
||||
onChange={(e) => onDisplayNameChanged(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<Button type="submit">Submit</Button>
|
||||
<Button variant="secondary" href={`/${processModelPath}`}>Cancel</Button>
|
||||
<Button onClick={deleteProcessModel} variant="danger">Delete process model</Button>
|
||||
<Button variant="secondary" href={`/${processModelPath}`}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={deleteProcessModel} variant="danger">
|
||||
Delete process model
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
</main>
|
||||
);
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,17 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||
|
||||
import ReactDiagramEditor from "../react_diagram_editor"
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { Button, Modal } from 'react-bootstrap';
|
||||
import Editor from '@monaco-editor/react';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
|
||||
import Editor from "@monaco-editor/react";
|
||||
import ReactDiagramEditor from '../react_diagram_editor';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
|
||||
export default function ProcessModelEditDiagram() {
|
||||
const [showFileNameEditor, setShowFileNameEditor] = useState(false);
|
||||
const handleShowFileNameEditor = () => setShowFileNameEditor(true);
|
||||
|
||||
const [scriptText, setScriptText] = useState("");
|
||||
const [scriptText, setScriptText] = useState('');
|
||||
const [scriptModeling, setScriptModeling] = useState(null);
|
||||
const [scriptElement, setScriptElement] = useState(null);
|
||||
const [showScriptEditor, setShowScriptEditor] = useState(false);
|
||||
@ -25,17 +22,21 @@ export default function ProcessModelEditDiagram() {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const [processModelFile, setProcessModelFile] = useState(null);
|
||||
const [newFileName, setNewFileName] = useState("");
|
||||
const [bpmnXmlForDiagramRendering, setBpmnXmlForDiagramRendering] = useState(null);
|
||||
const [newFileName, setNewFileName] = useState('');
|
||||
const [bpmnXmlForDiagramRendering, setBpmnXmlForDiagramRendering] =
|
||||
useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (params.file_name) {
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/file/${params.file_name}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/file/${params.file_name}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
setProcessModelFile(result);
|
||||
@ -44,26 +45,16 @@ export default function ProcessModelEditDiagram() {
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [params]);
|
||||
|
||||
function onError(err) {
|
||||
console.log('ERROR:', err);
|
||||
}
|
||||
|
||||
const handleFileNameCancel = (() => {
|
||||
const handleFileNameCancel = () => {
|
||||
setShowFileNameEditor(false);
|
||||
setNewFileName("");
|
||||
});
|
||||
setNewFileName('');
|
||||
};
|
||||
|
||||
const handleFileNameSave = ((event) => {
|
||||
event.preventDefault();
|
||||
setShowFileNameEditor(false);
|
||||
saveDiagram(bpmnXmlForDiagramRendering);
|
||||
});
|
||||
|
||||
const saveDiagram = ((bpmnXML, fileName = params.file_name) => {
|
||||
const saveDiagram = (bpmnXML, fileName = params.file_name) => {
|
||||
setBpmnXmlForDiagramRendering(bpmnXML);
|
||||
|
||||
let url = `${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}/file`;
|
||||
@ -72,7 +63,7 @@ export default function ProcessModelEditDiagram() {
|
||||
|
||||
if (newFileName) {
|
||||
fileNameWithExtension = `${newFileName}.${searchParams.get('file_type')}`;
|
||||
httpMethod = 'POST'
|
||||
httpMethod = 'POST';
|
||||
} else {
|
||||
url += `/${fileNameWithExtension}`;
|
||||
}
|
||||
@ -81,32 +72,38 @@ export default function ProcessModelEditDiagram() {
|
||||
return;
|
||||
}
|
||||
|
||||
let bpmnFile = new File([bpmnXML], fileNameWithExtension);
|
||||
const bpmnFile = new File([bpmnXML], fileNameWithExtension);
|
||||
const formData = new FormData();
|
||||
formData.append('file', bpmnFile);
|
||||
formData.append('fileName', bpmnFile.name);
|
||||
fetch(url, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: httpMethod,
|
||||
body: formData,
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
if (!params.file_name) {
|
||||
navigate(`/process-models/${params.process_group_id}/${params.process_model_id}/file/${fileNameWithExtension}`);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}).then(
|
||||
() => {
|
||||
if (!params.file_name) {
|
||||
navigate(
|
||||
`/process-models/${params.process_group_id}/${params.process_model_id}/file/${fileNameWithExtension}`
|
||||
);
|
||||
}
|
||||
)
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const newFileNameBox = (() => {
|
||||
let fileExtension = `.${searchParams.get('file_type')}`;
|
||||
const handleFileNameSave = (event) => {
|
||||
event.preventDefault();
|
||||
setShowFileNameEditor(false);
|
||||
saveDiagram(bpmnXmlForDiagramRendering);
|
||||
};
|
||||
|
||||
const newFileNameBox = () => {
|
||||
const fileExtension = `.${searchParams.get('file_type')}`;
|
||||
return (
|
||||
<Modal show={showFileNameEditor} onHide={handleFileNameCancel}>
|
||||
<Modal.Header closeButton>
|
||||
@ -116,11 +113,11 @@ export default function ProcessModelEditDiagram() {
|
||||
<label>File Name:</label>
|
||||
<span>
|
||||
<input
|
||||
name='file_name'
|
||||
type='text'
|
||||
name="file_name"
|
||||
type="text"
|
||||
value={newFileName}
|
||||
onChange={e => setNewFileName(e.target.value)}
|
||||
autoFocus={true}
|
||||
onChange={(e) => setNewFileName(e.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
{fileExtension}
|
||||
</span>
|
||||
@ -134,29 +131,29 @@ export default function ProcessModelEditDiagram() {
|
||||
</Modal.Footer>
|
||||
</form>
|
||||
</Modal>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
const onLaunchScriptEditor = ((element, modeling) => {
|
||||
setScriptText((element.businessObject.script || ''));
|
||||
const onLaunchScriptEditor = (element, modeling) => {
|
||||
setScriptText(element.businessObject.script || '');
|
||||
setScriptModeling(modeling);
|
||||
setScriptElement(element);
|
||||
handleShowScriptEditor();
|
||||
});
|
||||
const handleScriptEditorClose = (() => {
|
||||
};
|
||||
const handleScriptEditorClose = () => {
|
||||
setShowScriptEditor(false);
|
||||
});
|
||||
const handleEditorChange = ((value, event) => {
|
||||
};
|
||||
const handleEditorChange = (value) => {
|
||||
setScriptText(value);
|
||||
scriptModeling.updateProperties(scriptElement, {
|
||||
scriptFormat: "python",
|
||||
script: value
|
||||
scriptFormat: 'python',
|
||||
script: value,
|
||||
});
|
||||
});
|
||||
const scriptEditor = (() => {
|
||||
let scriptName = "";
|
||||
};
|
||||
const scriptEditor = () => {
|
||||
let scriptName = '';
|
||||
if (scriptElement) {
|
||||
scriptName = scriptElement.di.bpmnElement.name
|
||||
scriptName = scriptElement.di.bpmnElement.name;
|
||||
}
|
||||
return (
|
||||
<Modal size="xl" show={showScriptEditor} onHide={handleScriptEditorClose}>
|
||||
@ -177,62 +174,61 @@ export default function ProcessModelEditDiagram() {
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const isDmn = (() => {
|
||||
const file_name = params.file_name || "";
|
||||
if (searchParams.get('file_type') === "dmn" || file_name.endsWith(".dmn") ) {
|
||||
const isDmn = () => {
|
||||
const fileName = params.file_name || '';
|
||||
if (searchParams.get('file_type') === 'dmn' || fileName.endsWith('.dmn')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
const appropriateEditor = (() => {
|
||||
const appropriateEditor = () => {
|
||||
if (isDmn()) {
|
||||
return (
|
||||
<ReactDiagramEditor
|
||||
process_model_id={params.process_model_id}
|
||||
process_group_id={params.process_group_id}
|
||||
onError={ onError }
|
||||
saveDiagram={ saveDiagram }
|
||||
saveDiagram={saveDiagram}
|
||||
diagramXML={bpmnXmlForDiagramRendering}
|
||||
fileName={processModelFile ? processModelFile.name : null}
|
||||
diagramType='dmn'
|
||||
diagramType="dmn"
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ReactDiagramEditor
|
||||
process_model_id={params.process_model_id}
|
||||
process_group_id={params.process_group_id}
|
||||
onError={ onError }
|
||||
saveDiagram={ saveDiagram }
|
||||
process_group_id={params.process_group_id}
|
||||
saveDiagram={saveDiagram}
|
||||
diagramXML={bpmnXmlForDiagramRendering}
|
||||
fileName={processModelFile ? processModelFile.name : null}
|
||||
diagramType='bpmn'
|
||||
diagramType="bpmn"
|
||||
onLaunchScriptEditor={onLaunchScriptEditor}
|
||||
/>
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
// if a file name is not given then this is a new model and the ReactDiagramEditor component will handle it
|
||||
if (bpmnXmlForDiagramRendering || !params.file_name) {
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb
|
||||
processGroupId={params.process_group_id}
|
||||
processModelId={params.process_model_id}
|
||||
linkProcessModel="true"
|
||||
/>
|
||||
<h2>Process Model File{processModelFile ? `: ${processModelFile.name}` : ""}</h2>
|
||||
<h2>
|
||||
Process Model File
|
||||
{processModelFile ? `: ${processModelFile.name}` : ''}
|
||||
</h2>
|
||||
{appropriateEditor()}
|
||||
{newFileNameBox()}
|
||||
{scriptEditor()}
|
||||
|
||||
<div id="diagram-container"></div>
|
||||
<div id="diagram-container" />
|
||||
</main>
|
||||
);
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,24 @@
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import { slugifyString } from '../helpers'
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import { slugifyString } from '../helpers';
|
||||
|
||||
export default function ProcessModelNew(props) {
|
||||
let params = useParams();
|
||||
export default function ProcessModelNew() {
|
||||
const params = useParams();
|
||||
|
||||
const [identifier, setIdentifier] = useState("");
|
||||
const [identifier, setIdentifier] = useState('');
|
||||
const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] = useState(false);
|
||||
const [displayName, setDisplayName] = useState("");
|
||||
const [displayName, setDisplayName] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const addProcessModel = ((event) => {
|
||||
event.preventDefault()
|
||||
const addProcessModel = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
fetch(`${BACKEND_BASE_URL}/process-models`, {
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
@ -31,49 +30,55 @@ export default function ProcessModelNew(props) {
|
||||
standalone: false,
|
||||
library: false,
|
||||
}),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
navigate(`/process-models/${params.process_group_id}/${identifier}`);
|
||||
},
|
||||
// Note: it's important to handle errors here
|
||||
// instead of a catch() block so that we don't swallow
|
||||
// exceptions from actual bugs in components.
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
)
|
||||
}).then(
|
||||
() => {
|
||||
navigate(`/process-models/${params.process_group_id}/${identifier}`);
|
||||
},
|
||||
// Note: it's important to handle errors here
|
||||
// instead of a catch() block so that we don't swallow
|
||||
// exceptions from actual bugs in components.
|
||||
(newError) => {
|
||||
console.log(newError);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
const onDisplayNameChanged = ((newDisplayName) => {
|
||||
const onDisplayNameChanged = (newDisplayName) => {
|
||||
setDisplayName(newDisplayName);
|
||||
if (!idHasBeenUpdatedByUser) {
|
||||
setIdentifier(slugifyString(newDisplayName));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb />
|
||||
<h2>Add Process Model</h2>
|
||||
<form onSubmit={addProcessModel}>
|
||||
<label>Display Name:</label>
|
||||
<input
|
||||
name='display_name'
|
||||
type='text'
|
||||
value={displayName}
|
||||
onChange={e => onDisplayNameChanged(e.target.value)}
|
||||
/>
|
||||
<label htmlFor="display_name">
|
||||
Display Name:
|
||||
<input
|
||||
name="display_name"
|
||||
id="display_name"
|
||||
type="text"
|
||||
value={displayName}
|
||||
onChange={(e) => onDisplayNameChanged(e.target.value)}
|
||||
/>
|
||||
</label>
|
||||
<br />
|
||||
<label>ID:</label>
|
||||
<input
|
||||
name='id'
|
||||
type='text'
|
||||
value={identifier}
|
||||
onChange={e => { setIdentifier(e.target.value); setIdHasBeenUpdatedByUser(true)} }
|
||||
/>
|
||||
<label htmlFor="id">
|
||||
ID:
|
||||
<input
|
||||
name="id"
|
||||
id="id"
|
||||
type="text"
|
||||
value={identifier}
|
||||
onChange={(e) => {
|
||||
setIdentifier(e.target.value);
|
||||
setIdHasBeenUpdatedByUser(true);
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
<br />
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
@ -1,25 +1,26 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { BACKEND_BASE_URL } from '../config';
|
||||
import { HOT_AUTH_TOKEN } from '../config';
|
||||
import { useParams } from "react-router-dom";
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'
|
||||
import FileInput from '../components/FileInput'
|
||||
import { Button, Stack } from 'react-bootstrap'
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { Button, Stack } from 'react-bootstrap';
|
||||
import { BACKEND_BASE_URL, HOT_AUTH_TOKEN } from '../config';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import FileInput from '../components/FileInput';
|
||||
|
||||
export default function ProcessModelShow() {
|
||||
let params = useParams();
|
||||
const params = useParams();
|
||||
|
||||
const [processModel, setProcessModel] = useState(null);
|
||||
const [processInstanceResult, setProcessInstanceResult] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${params.process_group_id}/${params.process_model_id}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
setProcessModel(result);
|
||||
@ -27,35 +28,20 @@ export default function ProcessModelShow() {
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
);
|
||||
}, [params]);
|
||||
|
||||
const processInstanceCreateAndRun = ((event) => {
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${processModel.process_group_id}/${processModel.id}`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
}),
|
||||
method: 'POST',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
processModelRun(result);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
const processModelRun = ((processInstance) => {
|
||||
fetch(`${BACKEND_BASE_URL}/process-models/${processModel.process_group_id}/${processModel.id}/process-instances/${processInstance.id}/run`, {
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${HOT_AUTH_TOKEN}`
|
||||
}),
|
||||
method: 'POST',
|
||||
})
|
||||
.then(res => res.json())
|
||||
const processModelRun = (processInstance) => {
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${processModel.process_group_id}/${processModel.id}/process-instances/${processInstance.id}/run`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'POST',
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
setProcessInstanceResult(result);
|
||||
@ -63,59 +49,114 @@ export default function ProcessModelShow() {
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
let processInstanceResultTag = ""
|
||||
const processInstanceCreateAndRun = () => {
|
||||
fetch(
|
||||
`${BACKEND_BASE_URL}/process-models/${processModel.process_group_id}/${processModel.id}`,
|
||||
{
|
||||
headers: new Headers({
|
||||
Authorization: `Bearer ${HOT_AUTH_TOKEN}`,
|
||||
}),
|
||||
method: 'POST',
|
||||
}
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(
|
||||
(result) => {
|
||||
processModelRun(result);
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let processInstanceResultTag = '';
|
||||
if (processInstanceResult) {
|
||||
processInstanceResultTag = <pre>{processInstanceResult.status}: {JSON.stringify(processInstanceResult.data)}</pre>
|
||||
processInstanceResultTag = (
|
||||
<pre>
|
||||
{processInstanceResult.status}:{' '}
|
||||
{JSON.stringify(processInstanceResult.data)}
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
|
||||
if (processModel) {
|
||||
let processModelFilesTag = "";
|
||||
processModelFilesTag = processModel.files.map(file_bpmn => {
|
||||
if (file_bpmn.name === processModel.primary_file_name) {
|
||||
let processModelFilesTag = '';
|
||||
processModelFilesTag = processModel.files.map((fileBpmn) => {
|
||||
if (fileBpmn.name === processModel.primary_file_name) {
|
||||
return (
|
||||
<li key={file_bpmn.name}>
|
||||
<Link to={`/process-models/${processModel.process_group_id}/${processModel.id}/file/${file_bpmn.name}`}>{file_bpmn.name}</Link> - Primary File
|
||||
<li key={fileBpmn.name}>
|
||||
<Link
|
||||
to={`/process-models/${processModel.process_group_id}/${processModel.id}/file/${fileBpmn.name}`}
|
||||
>
|
||||
{fileBpmn.name}
|
||||
</Link>{' '}
|
||||
- Primary File
|
||||
</li>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<li key={file_bpmn.name}>
|
||||
<Link to={`/process-models/${processModel.process_group_id}/${processModel.id}/file/${file_bpmn.name}`}>{file_bpmn.name}</Link>
|
||||
</li>
|
||||
)
|
||||
);
|
||||
}
|
||||
})
|
||||
return (
|
||||
<li key={fileBpmn.name}>
|
||||
<Link
|
||||
to={`/process-models/${processModel.process_group_id}/${processModel.id}/file/${fileBpmn.name}`}
|
||||
>
|
||||
{fileBpmn.name}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<ProcessBreadcrumb
|
||||
processGroupId={processModel.process_group_id}
|
||||
processModelId={processModel.id}
|
||||
/>
|
||||
<h2>Process Model: {processModel.id}</h2>
|
||||
{processInstanceResultTag}
|
||||
<FileInput processModel={processModel} />
|
||||
<br />
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<Button onClick={processInstanceCreateAndRun} variant="primary">Run</Button>
|
||||
<Button href={`/process-models/${processModel.process_group_id}/${processModel.id}/edit`} variant="secondary">Edit process model</Button>
|
||||
<Button href={`/process-models/${processModel.process_group_id}/${processModel.id}/file?file_type=bpmn`} variant="warning">Add New BPMN File</Button>
|
||||
<Button href={`/process-models/${processModel.process_group_id}/${processModel.id}/file?file_type=dmn`} variant="success">Add New DMN File</Button>
|
||||
</Stack>
|
||||
<br />
|
||||
<br />
|
||||
<Link to={`/process-models/${processModel.process_group_id}/${processModel.id}/process-instances`}>Process Instances</Link>
|
||||
<br />
|
||||
<br />
|
||||
<h3>Files</h3>
|
||||
<ul>{processModelFilesTag}</ul>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<ProcessBreadcrumb
|
||||
processGroupId={processModel.process_group_id}
|
||||
processModelId={processModel.id}
|
||||
/>
|
||||
<h2>Process Model: {processModel.id}</h2>
|
||||
{processInstanceResultTag}
|
||||
<FileInput
|
||||
processModelId={processModel.id}
|
||||
processGroupId={processModel.process_group_id}
|
||||
/>
|
||||
<br />
|
||||
<Stack direction="horizontal" gap={3}>
|
||||
<Button onClick={processInstanceCreateAndRun} variant="primary">
|
||||
Run
|
||||
</Button>
|
||||
<Button
|
||||
href={`/process-models/${processModel.process_group_id}/${processModel.id}/edit`}
|
||||
variant="secondary"
|
||||
>
|
||||
Edit process model
|
||||
</Button>
|
||||
<Button
|
||||
href={`/process-models/${processModel.process_group_id}/${processModel.id}/file?file_type=bpmn`}
|
||||
variant="warning"
|
||||
>
|
||||
Add New BPMN File
|
||||
</Button>
|
||||
<Button
|
||||
href={`/process-models/${processModel.process_group_id}/${processModel.id}/file?file_type=dmn`}
|
||||
variant="success"
|
||||
>
|
||||
Add New DMN File
|
||||
</Button>
|
||||
</Stack>
|
||||
<br />
|
||||
<br />
|
||||
<Link
|
||||
to={`/process-models/${processModel.process_group_id}/${processModel.id}/process-instances`}
|
||||
>
|
||||
Process Instances
|
||||
</Link>
|
||||
<br />
|
||||
<br />
|
||||
<h3>Files</h3>
|
||||
<ul>{processModelFilesTag}</ul>
|
||||
</main>
|
||||
);
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
export default function Expenses() {
|
||||
return (
|
||||
<main style={{ padding: "1rem 0" }}>
|
||||
<main style={{ padding: '1rem 0' }}>
|
||||
<h2>Expenses</h2>
|
||||
</main>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user