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