Squashed 'spiffworkflow-frontend/' changes from ab6cf2817..c096ca3f9

c096ca3f9 Report URL fixes (#29)
ca49db4d7 get pagination for groups
2bff2d4b2 Merge branch 'main' into feature/nested-groups-2
8a443ebe2 use error as a status instead of faulted w/ burnettk
2e32ed4d4 favor h1 tags over h2 w/ burnettk
0a4ac2d53 fixed up the process instance show page and moved contents of scss to css file and load that last w/ burnettk
670cbabb0 fix lint
d21a94467 Assure we are using the latest bpmn-js-spiffworkflow library.
a5339a3cb Use the modify method
3983a6eda Minor fixes for the launch buttons.
c63161699 moved usage of ProcessBreadcrumb to use hotCrumbs except for report pages
d06a3b6b7 cleaned up breadcrumbs some more and cleaned up console.log statements
614080e39 support process-groups in breadcrumb component
fe8f79017 add breadcrumb to instances page sometimes
2206972c5 fix recent process models, at least after they visit process model show page
ff0721362 make Files half-width and add link to file
f08538225 lint

git-subtree-dir: spiffworkflow-frontend
git-subtree-split: c096ca3f9c99df2812191b2a02702c1916c239bd
This commit is contained in:
Dan 2022-11-11 11:24:41 -05:00
parent 2b5c7d138e
commit 997146e18f
34 changed files with 610 additions and 472 deletions

9
package-lock.json generated
View File

@ -7485,7 +7485,7 @@
},
"node_modules/bpmn-js-spiffworkflow": {
"version": "0.0.8",
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#24c2cc36067adf8fed75990c6bf4a1a67bc9122b",
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#09fa713bb0bb1b9d4f97684afc46bc3711e11770",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.4",
@ -35755,7 +35755,7 @@
}
},
"bpmn-js-spiffworkflow": {
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#24c2cc36067adf8fed75990c6bf4a1a67bc9122b",
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#09fa713bb0bb1b9d4f97684afc46bc3711e11770",
"from": "bpmn-js-spiffworkflow@sartography/bpmn-js-spiffworkflow#main",
"requires": {
"inherits": "^2.0.4",
@ -46545,7 +46545,7 @@
"@csstools/postcss-text-decoration-shorthand": "^1.0.0",
"@csstools/postcss-trigonometric-functions": "^1.0.2",
"@csstools/postcss-unset-value": "^1.0.2",
"autoprefixer": "10.4.5",
"autoprefixer": "10.4.8",
"browserslist": "^4.21.3",
"css-blank-pseudo": "^3.0.3",
"css-has-pseudo": "^3.0.4",
@ -46583,8 +46583,7 @@
},
"dependencies": {
"autoprefixer": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.5.tgz",
"version": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.5.tgz",
"integrity": "sha512-Fvd8yCoA7lNX/OUllvS+aS1I7WRBclGXsepbvT8ZaPgrH24rgXpZzF0/6Hh3ZEkwg+0AES/Osd196VZmYoEFtw==",
"requires": {
"browserslist": "^4.20.2",

View File

@ -38,6 +38,10 @@ export default function NavigationBar() {
let newActiveKey = '/admin/process-groups';
if (location.pathname.match(/^\/admin\/messages\b/)) {
newActiveKey = '/admin/messages';
} else if (
location.pathname.match(/^\/admin\/process-instances\/reports\b/)
) {
newActiveKey = '/admin/process-instances/reports';
} else if (location.pathname.match(/^\/admin\/process-instances\b/)) {
newActiveKey = '/admin/process-instances';
} else if (location.pathname.match(/^\/admin\/secrets\b/)) {
@ -119,6 +123,12 @@ export default function NavigationBar() {
>
Authentications
</HeaderMenuItem>
<HeaderMenuItem
href="/admin/process-instances/reports"
isCurrentPage={isActivePage('/admin/process-instances/reports')}
>
Reports
</HeaderMenuItem>
</>
);
};

View File

@ -25,36 +25,3 @@ test('renders hotCrumbs', () => {
const nextElement = screen.getByText(/Process Group: hey/);
expect(nextElement).toBeInTheDocument();
});
// FIXME: update to use hotcrumbs
// test('renders process group when given processGroupId', async () => {
// render(
// <BrowserRouter>
// <ProcessBreadcrumb processGroupId="group-a" />
// </BrowserRouter>
// );
// const processGroupElement = screen.getByText(/group-a/);
// expect(processGroupElement).toBeInTheDocument();
// const processGroupBreadcrumbs = await screen.findAllByText(
// /Process Group: group-a/
// );
// expect(processGroupBreadcrumbs[0]).toHaveClass('breadcrumb-item active');
// });
//
// test('renders process model when given processModelId', async () => {
// render(
// <BrowserRouter>
// <ProcessBreadcrumb processGroupId="group-b" processModelId="model-c" />
// </BrowserRouter>
// );
// const processGroupElement = screen.getByText(/group-b/);
// expect(processGroupElement).toBeInTheDocument();
// const processModelBreadcrumbs = await screen.findAllByText(
// /Process Model: model-c/
// );
// expect(processModelBreadcrumbs[0]).toHaveClass('breadcrumb-item active');
// const processGroupBreadcrumbs = await screen.findAllByText(
// /Process Group: group-b/
// );
// expect(processGroupBreadcrumbs[0]).toBeInTheDocument();
// });

View File

@ -13,7 +13,7 @@ type OwnProps = {
const explodeCrumb = (crumb: HotCrumbItem) => {
const url: string = crumb[1] || '';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_unused, processModelId, link] = url.split(':');
const [endingUrlType, processModelId, link] = url.split(':');
const processModelIdSegments = splitProcessModelId(processModelId);
const paths: string[] = [];
const lastPathItem = processModelIdSegments.pop();
@ -29,7 +29,13 @@ const explodeCrumb = (crumb: HotCrumbItem) => {
}
);
if (link === 'link') {
const lastUrl = `/admin/process-models/${paths.join(':')}:${lastPathItem}`;
if (lastPathItem !== undefined) {
paths.push(lastPathItem);
}
// process_model to process-models
const lastUrl = `/admin/${endingUrlType
.replace('_', '-')
.replace(/s*$/, 's')}/${paths.join(':')}`;
breadcrumbItems.push(
<BreadcrumbItem key={lastPathItem} href={lastUrl}>
{lastPathItem}
@ -64,7 +70,7 @@ export default function ProcessBreadcrumb({
</BreadcrumbItem>
);
}
if (url && url.startsWith('process_model:')) {
if (url && url.match(/^process[_-](model|group)s?:/)) {
return explodeCrumb(crumb);
}
return (

View File

@ -2,7 +2,7 @@ import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
// @ts-ignore
import { Button, ButtonSet, Form, Stack, TextInput } from '@carbon/react';
import {modifyProcessModelPath, slugifyString} from '../helpers';
import { modifyProcessModelPath, slugifyString } from '../helpers';
import HttpService from '../services/HttpService';
import { ProcessGroup } from '../interfaces';
import ButtonWithConfirmation from './ButtonWithConfirmation';
@ -79,12 +79,9 @@ export default function ProcessGroupForm({
description: processGroup.description,
};
if (mode === 'new') {
console.log(`parentGroupId: ${parentGroupId}`);
console.log(`processGroup.id: ${processGroup.id}`);
if (parentGroupId) {
newProcessGroupId = `${parentGroupId}/${processGroup.id}`;
}
console.log(`newProcessGroupId: ${newProcessGroupId}`);
Object.assign(postBody, {
id: parentGroupId
? `${parentGroupId}/${processGroup.id}`

View File

@ -229,7 +229,7 @@ export default function ReactDiagramEditor({
diagramModeler.on('spiff.script.edit', (event: any) => {
const { error, element, scriptType, script, eventBus } = event;
if (error) {
console.log(error);
console.error(error);
}
handleLaunchScriptEditor(element, script, scriptType, eventBus);
});
@ -237,7 +237,7 @@ export default function ReactDiagramEditor({
diagramModeler.on('spiff.markdown.edit', (event: any) => {
const { error, element, value, eventBus } = event;
if (error) {
console.log(error);
console.error(error);
}
handleLaunchMarkdownEditor(element, value, eventBus);
});
@ -318,7 +318,7 @@ export default function ReactDiagramEditor({
}
function handleError(err: any) {
console.log('ERROR:', err);
console.error('ERROR:', err);
}
function checkTaskCanBeHighlighted(taskBpmnId: string) {
@ -406,7 +406,6 @@ export default function ReactDiagramEditor({
}
function fetchDiagramFromURL(urlToUse: any) {
console.log(`urlToUse: ${urlToUse}`);
fetch(urlToUse)
.then((response) => response.text())
.then((text) => {

View File

@ -10,6 +10,10 @@ export default function SubNavigation() {
let newActiveKey = '/admin/process-groups';
if (location.pathname.match(/^\/admin\/messages\b/)) {
newActiveKey = '/admin/messages';
} else if (
location.pathname.match(/^\/admin\/process-instances\/reports\b/)
) {
newActiveKey = '/admin/process-instances/reports';
} else if (location.pathname.match(/^\/admin\/process-instances\b/)) {
newActiveKey = '/admin/process-instances';
} else if (location.pathname.match(/^\/admin\/secrets\b/)) {
@ -45,6 +49,9 @@ export default function SubNavigation() {
<Nav.Item>
<Nav.Link href="/admin/authentications">Authentications</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link href="/admin/process-instances/reports">Reports</Nav.Link>
</Nav.Item>
</Nav>
);
}

View File

@ -12,10 +12,11 @@ export const PROCESS_STATUSES = [
'user_input_required',
'waiting',
'complete',
'faulted',
'error',
'suspended',
];
// with time: yyyy-MM-dd HH:mm:ss
export const DATE_TIME_FORMAT = 'yyyy-MM-dd HH:mm:ss';
export const DATE_FORMAT = 'yyyy-MM-dd';
export const DATE_FORMAT_CARBON = 'Y-m-d';

View File

@ -1,5 +1,5 @@
import { format } from 'date-fns';
import { DATE_FORMAT } from './config';
import { DATE_TIME_FORMAT, DATE_FORMAT } from './config';
import {
DEFAULT_PER_PAGE,
DEFAULT_PAGE,
@ -51,6 +51,14 @@ export const convertStringToDate = (dateString: string) => {
return null;
};
export const convertSecondsToFormattedDateTime = (seconds: number) => {
if (seconds) {
const dateObject = new Date(seconds * 1000);
return format(dateObject, DATE_TIME_FORMAT);
}
return null;
};
export const convertSecondsToFormattedDate = (seconds: number) => {
if (seconds) {
const dateObject = new Date(seconds * 1000);

View File

@ -1,24 +1,79 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* site is mainly using white theme. */
/* header is mainly using g100 */
/* mockup wanted white, not grey, text */
.cds--header, a.cds--header__menu-item {
color: white;
}
h1{
height: 36px;
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 400;
font-size: 28px;
line-height: 36px;
color: #161616;
flex: none;
order: 0;
align-self: stretch;
flex-grow: 0;
margin-bottom: 1em
}
.span-tag {
color: black;
}
.cds--btn.button-white-background {
color: #393939;
background: #FFFFFF;
background-blend-mode: multiply;
border: 1px solid #393939;
}
.cds--btn.button-white-background:hover {
background: #525252;
}
.cds--breadcrumb-item a.cds--link:hover {
color: #525252;
}
.cds--breadcrumb-item a.cds--link:visited {
color: #525252;
}
.cds--breadcrumb-item a.cds--link:visited:hover {
color: #525252;
}
.cds--breadcrumb-item a.cds--link {
color: #525252;
}
.cds--btn--ghost {
color: black;
}
.cds--btn--ghost:visited {
color: black;
}
.cds--btn--ghost:hover {
color: black;
}
.cds--btn--ghost:visited:hover {
color: black;
}
.cds--header__global .cds--btn--primary {
background-color: #161616
}
.cds--btn--primary {
background-color: #393939;
}
.cds--btn--primary:hover {
background-color: #474747;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
span.bjs-crumb {
color: #0000ff;
}
.bjs-breadcrumbs li:last-of-type span.bjs-crumb a {
color: black;
}
.app-logo {
height: 85%;
width: 85%;
@ -52,6 +107,26 @@ span.bjs-crumb {
margin-bottom: 2em;
}
h1.with-icons {
margin-top: 5px;
}
.grid-list-title {
font-weight: 600;
font-size: 14px;
line-height: 18px;
color: #161616;
}
.grid-date {
font-size: 14px;
line-height: 18px;
letter-spacing: 0.16px;
color: #525252;
}
.smaller-text {
font-size: 14px;
}
.diagram-editor-canvas {
border:1px solid #000000;
height:70vh;
@ -59,13 +134,6 @@ span.bjs-crumb {
margin:auto;
}
.cds--btn.button-white-background {
color: #393939;
background: #FFFFFF;
background-blend-mode: multiply;
border: 1px solid #393939;
}
.with-bottom-margin {
margin-bottom: 1em;
}

View File

@ -15,85 +15,3 @@
@use '@carbon/colors';
// @use '@carbon/react/scss/colors';
@use '@carbon/react/scss/themes';
// var(--cds-link-text-color, var(--cds-link-primary, #0f62fe))
// site is mainly using white theme.
// header is mainly using g100
// mockup wanted white, not grey, text
.cds--header, a.cds--header__menu-item {
// background-color: colors.$gray-100;
color: white;
}
h1{
height: 36px;
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 400;
font-size: 28px;
line-height: 36px;
color: #161616;
flex: none;
order: 0;
align-self: stretch;
flex-grow: 0;
margin-bottom: 1em
}
.cds--breadcrumb-item a.cds--link:hover {
color: #525252;
}
.cds--breadcrumb-item a.cds--link:visited {
color: #525252;
}
.cds--breadcrumb-item a.cds--link:visited:hover {
color: #525252;
}
.cds--breadcrumb-item a.cds--link {
color: #525252;
}
.cds--btn--ghost {
color: black;
}
.cds--btn--ghost:visited {
color: black;
}
.cds--btn--ghost:hover {
color: black;
}
.cds--btn--ghost:visited:hover {
color: black;
}
$slightly-lighter-gray: #474747;
$spiff-header-background-color: #161616;
.cds--header__global .cds--btn--primary {
background-color: $spiff-header-background-color;
}
.cds--btn--primary {
background-color: #393939;
}
.cds--btn--primary:hover {
background-color: $slightly-lighter-gray;
}
// .cds--btn--ghost:visited {
// color: black;
// }
// .cds--btn--ghost:hover {
// color: black;
// }
// .cds--btn--ghost:visited:hover {
// color: black;
// }
// :root {
// --cds-link-primary: #525252;
// }
// .card {
// background: var(--orange);
// --orange: hsl(255, 72%, var(--lightness));
// }

View File

@ -3,8 +3,8 @@ import * as ReactDOMClient from 'react-dom/client';
import App from './App';
import 'bootstrap/dist/css/bootstrap.css';
import './index.css';
import './index.scss';
import './index.css';
import reportWebVitals from './reportWebVitals';
import UserService from './services/UserService';

View File

@ -6,7 +6,7 @@ export interface Secret {
}
export interface RecentProcessModel {
processGroupIdentifier: string;
processGroupIdentifier?: string;
processModelIdentifier: string;
processModelDisplayName: string;
}

View File

@ -81,19 +81,19 @@ export default function AdminRoutes() {
element={<ProcessInstanceShow />}
/>
<Route
path="process-models/:process_model_id/process-instances/reports"
path="process-instances/reports"
element={<ProcessInstanceReportList />}
/>
<Route
path="process-models/:process_group_id/:process_model_id/process-instances/reports/:report_identifier"
path="process-instances/reports/:report_identifier"
element={<ProcessInstanceReportShow />}
/>
<Route
path="process-models/:process_group_id/:process_model_id/process-instances/reports/new"
path="process-instances/reports/new"
element={<ProcessInstanceReportNew />}
/>
<Route
path="process-models/:process_group_id/:process_model_id/process-instances/reports/:report_identifier/edit"
path="process-instances/reports/:report_identifier/edit"
element={<ProcessInstanceReportEdit />}
/>
<Route

View File

@ -122,7 +122,7 @@ export default function HomePage() {
});
return (
<>
<h2>Processes I can start</h2>
<h1>Processes I can start</h1>
<Table striped bordered>
<thead>
<tr>
@ -145,7 +145,7 @@ export default function HomePage() {
);
return (
<>
<h2>Tasks waiting for me</h2>
<h1>Tasks waiting for me</h1>
<PaginationForTable
page={page}
perPage={perPage}
@ -158,13 +158,18 @@ export default function HomePage() {
);
};
const tasksWaitingForMe = tasksWaitingForMeComponent();
const relevantProcessModelSection =
recentProcessModels.length > 0 && buildRecentProcessModelSection();
(recentProcessModels.length > 0 && buildRecentProcessModelSection()) ||
null;
if (pagination) {
if (tasksWaitingForMe === null && relevantProcessModelSection === null) {
return <p>No tasks are waiting for you.</p>;
}
return (
<>
{tasksWaitingForMeComponent()}
{tasksWaitingForMe}
{relevantProcessModelSection}
</>
);

View File

@ -7,6 +7,8 @@ import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import {
convertSecondsToFormattedDate,
getPageInfoFromSearchParams,
modifyProcessModelPath,
unModifyProcessModelPath,
} from '../helpers';
import HttpService from '../services/HttpService';
@ -44,15 +46,9 @@ export default function MessageInstanceList() {
<td>
<Link
data-qa="process-model-show-link"
to={`/admin/process-groups/${rowToUse.process_group_identifier}`}
>
{rowToUse.process_group_identifier}
</Link>
</td>
<td>
<Link
data-qa="process-model-show-link"
to={`/admin/process-models/${rowToUse.process_group_identifier}/${rowToUse.process_model_identifier}`}
to={`/admin/process-models/${modifyProcessModelPath(
rowToUse.process_model_identifier
)}`}
>
{rowToUse.process_model_identifier}
</Link>
@ -60,7 +56,9 @@ export default function MessageInstanceList() {
<td>
<Link
data-qa="process-instance-show-link"
to={`/admin/process-models/${rowToUse.process_group_identifier}/${rowToUse.process_model_identifier}/process-instances/${rowToUse.process_instance_id}`}
to={`/admin/process-models/${modifyProcessModelPath(
rowToUse.process_model_identifier
)}/process-instances/${rowToUse.process_instance_id}`}
>
{rowToUse.process_instance_id}
</Link>
@ -80,7 +78,6 @@ export default function MessageInstanceList() {
<thead>
<tr>
<th>Instance Id</th>
<th>Process Group</th>
<th>Process Model</th>
<th>Process Instance</th>
<th>Message Model</th>
@ -107,16 +104,29 @@ export default function MessageInstanceList() {
)}&process_instance_id=${searchParams.get('process_instance_id')}`;
breadcrumbElement = (
<ProcessBreadcrumb
processModelId={searchParams.get('process_model_id') as any}
processGroupId={searchParams.get('process_group_id') as any}
linkProcessModel
hotCrumbs={[
['Process Groups', '/admin'],
[
`Process Model: ${params.process_model_id}`,
`process_model:${unModifyProcessModelPath(
searchParams.get('process_model_id') || ''
)}:link`,
],
[
`Process Instance: ${searchParams.get('process_instance_id')}`,
`/admin/process-models/${searchParams.get(
'process_model_id'
)}/process-instances/${searchParams.get('process_instance_id')}`,
],
['Messages'],
]}
/>
);
}
return (
<>
{breadcrumbElement}
<h2>Messages</h2>
<h1>Messages</h1>
<PaginationForTable
page={page}
perPage={perPage}

View File

@ -24,8 +24,16 @@ export default function ProcessGroupEdit() {
if (processGroup) {
return (
<>
<ProcessBreadcrumb processGroupId={(processGroup as any).id} />
<h2>Edit Process Group: {(processGroup as any).id}</h2>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
[
`Process Group: ${processGroup.id}:link`,
`process_group:${processGroup.id}:link`,
],
]}
/>
<h1>Edit Process Group: {(processGroup as any).id}</h1>
<ProcessGroupForm
mode="edit"
processGroup={processGroup}

View File

@ -1,19 +1,26 @@
import { useState } from 'react';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import ProcessGroupForm from '../components/ProcessGroupForm';
import { ProcessGroup } from '../interfaces';
import { ProcessGroup, HotCrumbItem } from '../interfaces';
export default function ProcessGroupNew() {
const searchParams = new URLSearchParams(document.location.search);
const parentGroupId = searchParams.get('parentGroupId');
const [processGroup, setProcessGroup] = useState<ProcessGroup>({
id: '',
display_name: '',
description: '',
});
const hotCrumbs: HotCrumbItem[] = [['Process Groups', '/admin']];
if (parentGroupId) {
hotCrumbs.push(['', `process_group:${parentGroupId}:link`]);
}
return (
<>
<ProcessBreadcrumb />
<h2>Add Process Group</h2>
<ProcessBreadcrumb hotCrumbs={hotCrumbs} />
<h1>Add Process Group</h1>
<ProcessGroupForm
mode="new"
processGroup={processGroup}

View File

@ -5,8 +5,12 @@ import { Button, Table, Stack } from '@carbon/react';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import PaginationForTable from '../components/PaginationForTable';
import HttpService from '../services/HttpService';
import {getPageInfoFromSearchParams, modifyProcessModelPath, unModifyProcessModelPath} from '../helpers';
import { ProcessGroup } from '../interfaces';
import {
getPageInfoFromSearchParams,
modifyProcessModelPath,
unModifyProcessModelPath,
} from '../helpers';
import { ProcessGroup, ProcessModel } from '../interfaces';
export default function ProcessGroupShow() {
const params = useParams();
@ -15,14 +19,19 @@ export default function ProcessGroupShow() {
const [processGroup, setProcessGroup] = useState<ProcessGroup | null>(null);
const [processModels, setProcessModels] = useState([]);
const [processGroups, setProcessGroups] = useState([]);
const [pagination, setPagination] = useState(null);
const [modelPagination, setModelPagination] = useState(null);
const [groupPagination, setGroupPagination] = useState(null);
useEffect(() => {
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
const setProcessModelFromResult = (result: any) => {
setProcessModels(result.results);
setPagination(result.pagination);
setModelPagination(result.pagination);
};
const setProcessGroupFromResult = (result: any) => {
setProcessGroups(result.results);
setGroupPagination(result.pagination);
};
const processResult = (result: any) => {
setProcessGroup(result);
@ -33,7 +42,10 @@ export default function ProcessGroupShow() {
path: `/process-models?process_group_identifier=${unmodifiedProcessGroupId}&per_page=${perPage}&page=${page}`,
successCallback: setProcessModelFromResult,
});
setProcessGroups(result.process_groups);
HttpService.makeCallToBackend({
path: `/process-groups?process_group_identifier=${unmodifiedProcessGroupId}&per_page=${perPage}&page=${page}`,
successCallback: setProcessGroupFromResult,
});
};
HttpService.makeCallToBackend({
path: `/process-groups/${params.process_group_id}`,
@ -45,19 +57,19 @@ export default function ProcessGroupShow() {
if (processGroup === null) {
return null;
}
const rows = processModels.map((row) => {
const modifiedProcessModelId: String = (row as any).id.replace('/', ':');
const rows = processModels.map((row: ProcessModel) => {
const modifiedProcessModelId: String = modifyProcessModelPath((row as any).id);
return (
<tr key={(row as any).id}>
<tr key={row.id}>
<td>
<Link
to={`/admin/process-models/${modifiedProcessModelId}`}
data-qa="process-model-show-link"
>
{(row as any).id}
{row.id}
</Link>
</td>
<td>{(row as any).display_name}</td>
<td>{row.display_name}</td>
</tr>
);
});
@ -81,19 +93,19 @@ export default function ProcessGroupShow() {
if (processGroup === null) {
return null;
}
const rows = processGroups.map((row) => {
const modifiedProcessGroupId: String = modifyProcessModelPath((row as any).id);
const rows = processGroups.map((row: ProcessGroup) => {
const modifiedProcessGroupId: String = modifyProcessModelPath(row.id);
return (
<tr key={(row as any).id}>
<tr key={row.id}>
<td>
<Link
to={`/admin/process-groups/${modifiedProcessGroupId}`}
data-qa="process-model-show-link"
>
{(row as any).id}
{row.id}
</Link>
</td>
<td>{(row as any).display_name}</td>
<td>{row.display_name}</td>
</tr>
);
});
@ -113,15 +125,15 @@ export default function ProcessGroupShow() {
);
};
if (processGroup && pagination) {
if (processGroup && groupPagination && modelPagination) {
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
const modifiedProcessGroupId = modifyProcessModelPath((processGroup as any).id);
const modifiedProcessGroupId = modifyProcessModelPath(processGroup.id);
return (
<>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
[`Process Group: ${processGroup.display_name}`],
['', `process_group:${processGroup.id}`],
]}
/>
<ul>
@ -149,18 +161,18 @@ export default function ProcessGroupShow() {
<PaginationForTable
page={page}
perPage={perPage}
pagination={pagination}
pagination={modelPagination}
tableToDisplay={buildModelTable()}
path={`/admin/process-groups/${(processGroup as any).id}`}
path={`/admin/process-groups/${processGroup.id}`}
/>
<br />
<br />
<PaginationForTable
page={page}
perPage={perPage}
pagination={pagination}
pagination={groupPagination}
tableToDisplay={buildGroupTable()}
path={`/admin/process-groups/${(processGroup as any).id}`}
path={`/admin/process-groups/${processGroup.id}`}
/>
</ul>
</>

View File

@ -41,6 +41,7 @@ import 'react-bootstrap-typeahead/css/Typeahead.css';
import 'react-bootstrap-typeahead/css/Typeahead.bs5.css';
import { PaginationObject, ProcessModel } from '../interfaces';
import ProcessModelSearch from '../components/ProcessModelSearch';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
export default function ProcessInstanceList() {
const params = useParams();
@ -471,26 +472,31 @@ export default function ProcessInstanceList() {
);
};
const processInstanceTitleElement = () => {
const processInstanceBreadcrumbElement = () => {
const processModelFullIdentifier =
getProcessModelFullIdentifierFromSearchParams(searchParams);
if (processModelFullIdentifier === null) {
return <h2>Process Instances</h2>;
return null;
}
return (
<h2>
Process Instances for:{' '}
<Link
to={`/admin/process-models/${modifyProcessModelPath(
processModelFullIdentifier
)}`}
>
{processModelFullIdentifier}
</Link>
</h2>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
[
`Process Model: ${processModelFullIdentifier}`,
`process_model:${processModelFullIdentifier}:link`,
],
['Process Instances'],
]}
/>
);
};
const processInstanceTitleElement = () => {
return <h1>Process Instances</h1>;
};
const toggleShowFilterOptions = () => {
setShowFilterOptions(!showFilterOptions);
};
@ -499,6 +505,7 @@ export default function ProcessInstanceList() {
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
return (
<>
{processInstanceBreadcrumbElement()}
{processInstanceTitleElement()}
<Grid fullWidth>
<Column

View File

@ -8,6 +8,7 @@ import {
getPageInfoFromSearchParams,
convertSecondsToFormattedDate,
modifyProcessModelPath,
unModifyProcessModelPath,
} from '../helpers';
import HttpService from '../services/HttpService';
@ -33,10 +34,8 @@ export default function ProcessInstanceLogList() {
}, [searchParams, params]);
const buildTable = () => {
// return null;
const rows = processInstanceLogs.map((row) => {
const rowToUse = row as any;
console.log(`rowToUse: ${rowToUse}`);
return (
<tr key={rowToUse.id}>
<td>{rowToUse.bpmn_process_identifier}</td>
@ -57,7 +56,7 @@ export default function ProcessInstanceLogList() {
);
});
return (
<Table striped bordered>
<Table size="lg">
<thead>
<tr>
<th>Bpmn Process Identifier</th>
@ -75,13 +74,25 @@ export default function ProcessInstanceLogList() {
};
if (pagination) {
console.log('params.process_model_id', params.process_model_id);
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
return (
<main>
<ProcessBreadcrumb
processModelId={params.process_model_id}
processGroupId={params.process_group_id}
linkProcessModel
hotCrumbs={[
['Process Groups', '/admin'],
[
`Process Model: ${params.process_model_id}`,
`process_model:${unModifyProcessModelPath(
params.process_model_id || ''
)}:link`,
],
[
`Process Instance: ${params.process_instance_id}`,
`/admin/process-models/${params.process_model_id}/process-instances/${params.process_instance_id}`,
],
['Logs'],
]}
/>
<PaginationForTable
page={page}

View File

@ -1,6 +1,5 @@
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import HttpService from '../services/HttpService';
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
@ -24,15 +23,11 @@ export default function ProcessInstanceReportEdit() {
const [filterBy, setFilterBy] = useState('');
const navigateToProcessInstanceReport = (_result: any) => {
navigate(
`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/${params.report_identifier}`
);
navigate(`/admin/process-instances/reports/${params.report_identifier}`);
};
const navigateToProcessInstanceReports = (_result: any) => {
navigate(
`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports`
);
navigate(`/admin/process-instances/reports`);
};
useEffect(() => {
@ -111,8 +106,7 @@ export default function ProcessInstanceReportEdit() {
return (
<>
<ProcessBreadcrumb />
<h2>Edit Process Instance Report: {params.report_identifier}</h2>
<h1>Edit Process Instance Report: {params.report_identifier}</h1>
<ButtonWithConfirmation
description={`Delete Report ${params.report_identifier}?`}
onConfirmation={deleteProcessInstanceReport}

View File

@ -2,16 +2,11 @@ import { useEffect, useState } from 'react';
// @ts-ignore
import { Button, Table } from '@carbon/react';
import { useParams, Link } from 'react-router-dom';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import HttpService from '../services/HttpService';
import { modifyProcessModelPath } from '../helpers';
export default function ProcessInstanceReportList() {
const params = useParams();
const [processInstanceReports, setProcessInstanceReports] = useState([]);
const modifiedProcessModelId = modifyProcessModelPath(
params.process_model_id || ''
);
useEffect(() => {
HttpService.makeCallToBackend({
@ -27,7 +22,7 @@ export default function ProcessInstanceReportList() {
<tr key={(row as any).id}>
<td>
<Link
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/reports/${rowToUse.identifier}`}
to={`/admin/process-instances/reports/${rowToUse.identifier}`}
>
{rowToUse.identifier}
</Link>
@ -49,15 +44,8 @@ export default function ProcessInstanceReportList() {
const headerStuff = (
<>
<ProcessBreadcrumb
processGroupId={params.process_group_id}
processModelId={params.process_model_id}
linkProcessModel
/>
<h2>Reports for Process Model: {params.process_model_id}</h2>
<Button
href={`/admin/process-models/${modifiedProcessModelId}/process-instances/reports/new`}
>
<h1>Process Instance Reports</h1>
<Button href="/admin/process-instances/reports/new">
Add a process instance report
</Button>
</>

View File

@ -1,10 +1,9 @@
import { useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import HttpService from '../services/HttpService';
export default function ProcessInstanceReportNew() {
const params = useParams();
const navigate = useNavigate();
const [identifier, setIdentifier] = useState('');
@ -13,9 +12,7 @@ export default function ProcessInstanceReportNew() {
const [filterBy, setFilterBy] = useState('');
const navigateToNewProcessInstance = (_result: any) => {
navigate(
`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/${identifier}`
);
navigate(`/admin/process-instances/reports/${identifier}`);
};
const addProcessInstanceReport = (event: any) => {
@ -59,7 +56,7 @@ export default function ProcessInstanceReportNew() {
return (
<>
<ProcessBreadcrumb />
<h2>Add Process Model</h2>
<h1>Add Process Model</h1>
<form onSubmit={addProcessInstanceReport}>
<label htmlFor="identifier">
identifier:

View File

@ -80,9 +80,9 @@ export default function ProcessInstanceReport() {
processGroupId={params.process_group_id}
linkProcessModel
/>
<h2>Process Instance Report: {params.report_identifier}</h2>
<h1>Process Instance Report: {params.report_identifier}</h1>
<Button
href={`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/${params.report_identifier}/edit`}
href={`/admin/process-instances/reports/${params.report_identifier}/edit`}
>
Edit process instance report
</Button>

View File

@ -1,13 +1,33 @@
import { useContext, useEffect, useState } from 'react';
import Editor from '@monaco-editor/react';
import { useParams, useNavigate, Link } from 'react-router-dom';
// @ts-ignore
import { Button, Modal, Stack } from '@carbon/react';
import {
TrashCan,
StopOutline,
PauseOutline,
PlayOutline,
CaretLeft,
CaretRight,
InProgress,
Checkmark,
Warning,
// @ts-ignore
} from '@carbon/icons-react';
import {
Grid,
Column,
Button,
ButtonSet,
Tag,
Modal,
Stack,
// @ts-ignore
} from '@carbon/react';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import HttpService from '../services/HttpService';
import ReactDiagramEditor from '../components/ReactDiagramEditor';
import {
convertSecondsToFormattedDate,
convertSecondsToFormattedDateTime,
unModifyProcessModelPath,
} from '../helpers';
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
@ -125,23 +145,21 @@ export default function ProcessInstanceShow() {
const spiffStepLink = (
processInstanceToUse: any,
label: string,
label: any,
distance: number
) => {
return (
<li>
<Link
reloadDocument
data-qa="process-instance-step-link"
to={`/admin/process-models/${
params.process_model_id
}/process-instances/${params.process_instance_id}/${
currentSpiffStep(processInstanceToUse) + distance
}`}
>
{label}
</Link>
</li>
<Link
reloadDocument
data-qa="process-instance-step-link"
to={`/admin/process-models/${
params.process_model_id
}/process-instances/${params.process_instance_id}/${
currentSpiffStep(processInstanceToUse) + distance
}`}
>
{label}
</Link>
);
};
@ -150,7 +168,7 @@ export default function ProcessInstanceShow() {
return null;
}
return spiffStepLink(processInstanceToUse, 'Previous Step', -1);
return spiffStepLink(processInstanceToUse, <CaretLeft />, -1);
};
const nextStepLink = (processInstanceToUse: any) => {
@ -158,68 +176,106 @@ export default function ProcessInstanceShow() {
return null;
}
return spiffStepLink(processInstanceToUse, 'Next Step', 1);
return spiffStepLink(processInstanceToUse, <CaretRight />, 1);
};
const getInfoTag = (processInstanceToUse: any) => {
const currentEndDate = convertSecondsToFormattedDate(
const currentEndDate = convertSecondsToFormattedDateTime(
processInstanceToUse.end_in_seconds
);
let currentEndDateTag;
if (currentEndDate) {
currentEndDateTag = (
<li>
Completed:{' '}
{convertSecondsToFormattedDate(processInstanceToUse.end_in_seconds) ||
'N/A'}
</li>
<Grid condensed fullWidth>
<Column sm={1} md={1} lg={1} className="grid-list-title">
Completed:{' '}
</Column>
<Column sm={3} md={3} lg={3} className="grid-date">
{convertSecondsToFormattedDateTime(
processInstanceToUse.end_in_seconds
) || 'N/A'}
</Column>
</Grid>
);
}
let statusIcon = <InProgress />;
if (processInstanceToUse.status === 'suspended') {
statusIcon = <PauseOutline />;
} else if (processInstanceToUse.status === 'complete') {
statusIcon = <Checkmark />;
} else if (processInstanceToUse.status === 'terminated') {
statusIcon = <StopOutline />;
} else if (processInstanceToUse.status === 'error') {
statusIcon = <Warning />;
}
return (
<ul>
<li>
Started:{' '}
{convertSecondsToFormattedDate(processInstanceToUse.start_in_seconds)}
</li>
<>
<Grid condensed fullWidth>
<Column sm={1} md={1} lg={1} className="grid-list-title">
Started:{' '}
</Column>
<Column sm={3} md={3} lg={3} className="grid-date">
{convertSecondsToFormattedDateTime(
processInstanceToUse.start_in_seconds
)}
</Column>
</Grid>
{currentEndDateTag}
<li>Status: {processInstanceToUse.status}</li>
<li>
<Link
data-qa="process-instance-log-list-link"
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${params.process_instance_id}/logs`}
>
Logs
</Link>
</li>
<li>
<Link
data-qa="process-instance-message-instance-list-link"
to={`/admin/messages?process_model_id=${params.process_model_id}&process_instance_id=${params.process_instance_id}`}
>
Messages
</Link>
</li>
<li>
Step {currentSpiffStep(processInstanceToUse)} of{' '}
{processInstanceToUse.spiff_step}
</li>
{previousStepLink(processInstanceToUse)}
{nextStepLink(processInstanceToUse)}
</ul>
<Grid condensed fullWidth>
<Column sm={1} md={1} lg={1} className="grid-list-title">
Status:{' '}
</Column>
<Column sm={3} md={3} lg={3}>
<Tag type="gray" size="sm" className="span-tag">
{processInstanceToUse.status} {statusIcon}
</Tag>
</Column>
</Grid>
<br />
<Grid condensed fullWidth>
<Column sm={2} md={2} lg={2}>
<ButtonSet>
<Button
size="sm"
className="button-white-background"
data-qa="process-instance-log-list-link"
href={`/admin/process-models/${modifiedProcessModelId}/process-instances/${params.process_instance_id}/logs`}
>
Logs
</Button>
<Button
size="sm"
className="button-white-background"
data-qa="process-instance-message-instance-list-link"
href={`/admin/messages?process_model_id=${params.process_model_id}&process_instance_id=${params.process_instance_id}`}
>
Messages
</Button>
</ButtonSet>
</Column>
</Grid>
</>
);
};
const terminateButton = (processInstanceToUse: any) => {
if (
['complete', 'terminated', 'faulted'].indexOf(
['complete', 'terminated', 'error'].indexOf(
processInstanceToUse.status
) === -1
) {
return (
<Button onClick={terminateProcessInstance} variant="warning">
Terminate
</Button>
<ButtonWithConfirmation
kind="ghost"
renderIcon={StopOutline}
iconDescription="Terminate"
hasIconOnly
description={`Terminate Process Instance: ${processInstanceToUse.id}`}
onConfirmation={terminateProcessInstance}
confirmButtonLabel="Terminate"
/>
);
}
return <div />;
@ -227,14 +283,19 @@ export default function ProcessInstanceShow() {
const suspendButton = (processInstanceToUse: any) => {
if (
['complete', 'terminated', 'faulted', 'suspended'].indexOf(
['complete', 'terminated', 'error', 'suspended'].indexOf(
processInstanceToUse.status
) === -1
) {
return (
<Button onClick={suspendProcessInstance} variant="warning">
Suspend
</Button>
<Button
onClick={suspendProcessInstance}
kind="ghost"
renderIcon={PauseOutline}
iconDescription="Suspend"
hasIconOnly
size="lg"
/>
);
}
return <div />;
@ -243,9 +304,14 @@ export default function ProcessInstanceShow() {
const resumeButton = (processInstanceToUse: any) => {
if (processInstanceToUse.status === 'suspended') {
return (
<Button onClick={resumeProcessInstance} variant="warning">
Resume
</Button>
<Button
onClick={resumeProcessInstance}
kind="ghost"
renderIcon={PlayOutline}
iconDescription="Resume"
hasIconOnly
size="lg"
/>
);
}
return <div />;
@ -433,6 +499,40 @@ export default function ProcessInstanceShow() {
return null;
};
const stepsElement = (processInstanceToUse: any) => {
return (
<Grid condensed fullWidth>
<Column sm={3} md={3} lg={3}>
<Stack orientation="horizontal" gap={3} className="smaller-text">
{previousStepLink(processInstanceToUse)}
Step {currentSpiffStep(processInstanceToUse)} of{' '}
{processInstanceToUse.spiff_step}
{nextStepLink(processInstanceToUse)}
</Stack>
</Column>
</Grid>
);
};
const buttonIcons = (processInstanceToUse: any) => {
const elements = [];
elements.push(terminateButton(processInstanceToUse));
elements.push(suspendButton(processInstanceToUse));
elements.push(resumeButton(processInstanceToUse));
elements.push(
<ButtonWithConfirmation
kind="ghost"
renderIcon={TrashCan}
iconDescription="Delete"
hasIconOnly
description={`Delete Process Instance: ${processInstanceToUse.id}`}
onConfirmation={deleteProcessInstance}
confirmButtonLabel="Delete"
/>
);
return elements;
};
if (processInstance && tasks) {
const processInstanceToUse = processInstance as any;
const taskIds = getTaskIds();
@ -449,22 +549,22 @@ export default function ProcessInstanceShow() {
`Process Model: ${processModelId}`,
`process_model:${processModelId}:link`,
],
[`Process Instance: ${params.process_instance_id}`],
[`Process Instance Id: ${processInstanceToUse.id}`],
]}
/>
<Stack orientation="horizontal" gap={3}>
<h2>Process Instance Id: {processInstanceToUse.id}</h2>
<ButtonWithConfirmation
description="Delete Process Instance?"
onConfirmation={deleteProcessInstance}
buttonLabel="Delete"
/>
{terminateButton(processInstanceToUse)}
{suspendButton(processInstanceToUse)}
{resumeButton(processInstanceToUse)}
<Stack orientation="horizontal" gap={1}>
<h1 className="with-icons">
Process Instance Id: {processInstanceToUse.id}
</h1>
{buttonIcons(processInstanceToUse)}
</Stack>
<br />
<br />
{getInfoTag(processInstanceToUse)}
<br />
{taskDataDisplayArea()}
{stepsElement(processInstanceToUse)}
<br />
<ReactDiagramEditor
processModelId={processModelId || ''}
diagramXML={processInstanceToUse.bpmn_xml_file_contents || ''}

View File

@ -4,10 +4,11 @@ import { useParams } from 'react-router-dom';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import HttpService from '../services/HttpService';
import ProcessModelForm from '../components/ProcessModelForm';
import { ProcessModel } from '../interfaces';
export default function ProcessModelEdit() {
const params = useParams();
const [processModel, setProcessModel] = useState(null);
const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
const processModelPath = `process-models/${params.process_model_id}`;
useEffect(() => {
@ -20,8 +21,16 @@ export default function ProcessModelEdit() {
if (processModel) {
return (
<>
<ProcessBreadcrumb processGroupId={params.process_group_id} />
<h2>Edit Process Model: {(processModel as any).id}</h2>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
[
`Process Model: ${processModel.id}`,
`process_model:${processModel.id}:link`,
],
]}
/>
<h1>Edit Process Model: {(processModel as any).id}</h1>
<ProcessModelForm
mode="edit"
processGroupId={params.process_group_id}

View File

@ -268,7 +268,7 @@ export default function ProcessModelEditDiagram() {
});
event.eventBus.fire('spiff.json_files.returned', { options });
} else {
console.log('There is no process Model.');
console.error('There is no process Model.');
}
};
@ -281,10 +281,9 @@ export default function ProcessModelEditDiagram() {
options.push({ label: ref.name, value: ref.id });
});
});
console.log('Options', options);
event.eventBus.fire('spiff.dmn_files.returned', { options });
} else {
console.log('There is no process model.');
console.error('There is no process model.');
}
};
@ -641,21 +640,18 @@ export default function ProcessModelEditDiagram() {
const markdownEditor = () => {
return (
<Modal
size="xl"
show={showMarkdownEditor}
onHide={handleMarkdownEditorClose}
open={showMarkdownEditor}
modalHeading="Edit Markdown"
primaryButtonText="Close"
onRequestSubmit={handleMarkdownEditorClose}
size="lg"
>
<Modal.Header closeButton>
<Modal.Title>Edit Markdown Content</Modal.Title>
</Modal.Header>
<Modal.Body>
<MDEditor value={markdownText} onChange={setMarkdownText} />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleMarkdownEditorClose}>
Close
</Button>
</Modal.Footer>
<MDEditor
height={500}
highlightEnable={false}
value={markdownText}
onChange={setMarkdownText}
/>
</Modal>
);
};
@ -685,33 +681,39 @@ export default function ProcessModelEditDiagram() {
* @param processId
*/
const fileNameTemplatePath =
'/admin/process-models/:process_model_id/files/:file_name';
const onLaunchBpmnEditor = (processId: string) => {
const file = findFileNameForReferenceId(processId, 'bpmn');
if (file) {
const path = generatePath(fileNameTemplatePath, {
process_model_id: params.process_model_id,
file_name: file.name,
});
const path = generatePath(
'/admin/process-models/:process_model_id/files/:file_name',
{
process_model_id: params.process_model_id,
file_name: file.name,
}
);
window.open(path);
}
};
const onLaunchJsonEditor = (fileName: string) => {
const path = generatePath(fileNameTemplatePath, {
process_model_id: params.process_model_id,
file_name: fileName,
});
const path = generatePath(
'/admin/process-models/:process_model_id/form/:file_name',
{
process_model_id: params.process_model_id,
file_name: fileName,
}
);
window.open(path);
};
const onLaunchDmnEditor = (processId: string) => {
const file = findFileNameForReferenceId(processId, 'dmn');
if (file) {
const path = generatePath(fileNameTemplatePath, {
process_model_id: params.process_model_id,
file_name: file.name,
});
const path = generatePath(
'/admin/process-models/:process_model_id/files/:file_name',
{
process_model_id: params.process_model_id,
file_name: file.name,
}
);
window.open(path);
}
};
@ -780,10 +782,10 @@ export default function ProcessModelEditDiagram() {
[processModelFileName],
]}
/>
<h2>
<h1>
Process Model File{processModelFile ? ': ' : ''}
{processModelFileName}
</h2>
</h1>
{appropriateEditor()}
{newFileNameBox()}
{scriptEditor()}

View File

@ -16,8 +16,16 @@ export default function ProcessModelNew() {
return (
<>
<ProcessBreadcrumb />
<h2>Add Process Model</h2>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
[
`Process Group: ${params.process_group_id}`,
`process_group:${params.process_group_id}:link`,
],
]}
/>
<h1>Add Process Model</h1>
<ProcessModelForm
mode="new"
processGroupId={params.process_group_id}

View File

@ -13,6 +13,8 @@ import {
Accordion,
AccordionItem,
Button,
Grid,
Column,
Stack,
ButtonSet,
Modal,
@ -33,15 +35,8 @@ import { ProcessFile, ProcessModel, RecentProcessModel } from '../interfaces';
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
const storeRecentProcessModelInLocalStorage = (
processModelForStorage: any,
params: any
processModelForStorage: ProcessModel
) => {
if (
params.process_group_id === undefined ||
params.process_model_id === undefined
) {
return;
}
// All values stored in localStorage are strings.
// Grab our recentProcessModels string from localStorage.
const stringFromLocalStorage = window.localStorage.getItem(
@ -58,16 +53,16 @@ const storeRecentProcessModelInLocalStorage = (
// Here's the value we want to add
const value = {
processGroupIdentifier: processModelForStorage.process_group_id,
processModelIdentifier: processModelForStorage.id,
processModelDisplayName: processModelForStorage.display_name,
};
// anything with a processGroupIdentifier is old and busted. leave it behind.
array = array.filter((item) => item.processGroupIdentifier === undefined);
// If our parsed/empty array doesn't already have this value in it...
const matchingItem = array.find(
(item) =>
item.processGroupIdentifier === value.processGroupIdentifier &&
item.processModelIdentifier === value.processModelIdentifier
(item) => item.processModelIdentifier === value.processModelIdentifier
);
if (matchingItem === undefined) {
// add the value to the beginning of the array
@ -77,13 +72,15 @@ const storeRecentProcessModelInLocalStorage = (
if (array.length > 3) {
array.pop();
}
// turn the array WITH THE NEW VALUE IN IT into a string to prepare it to be stored in localStorage
const stringRepresentingArray = JSON.stringify(array);
// and store it in localStorage as "recentProcessModels"
window.localStorage.setItem('recentProcessModels', stringRepresentingArray);
}
// once the old and busted serializations are gone, we can put these two statements inside the above if statement
// turn the array WITH THE NEW VALUE IN IT into a string to prepare it to be stored in localStorage
const stringRepresentingArray = JSON.stringify(array);
// and store it in localStorage as "recentProcessModels"
window.localStorage.setItem('recentProcessModels', stringRepresentingArray);
};
export default function ProcessModelShow() {
@ -106,13 +103,13 @@ export default function ProcessModelShow() {
const processResult = (result: ProcessModel) => {
setProcessModel(result);
setReloadModel(false);
storeRecentProcessModelInLocalStorage(result, params);
storeRecentProcessModelInLocalStorage(result);
};
HttpService.makeCallToBackend({
path: `/process-models/${modifiedProcessModelId}`,
successCallback: processResult,
});
}, [params, reloadModel, modifiedProcessModelId]);
}, [reloadModel, modifiedProcessModelId]);
const processModelRun = (processInstance: any) => {
setErrorMessage(null);
@ -233,17 +230,22 @@ export default function ProcessModelShow() {
});
};
const navigateToFileEdit = (processModelFile: ProcessFile) => {
const profileModelFileEditUrl = (processModelFile: ProcessFile) => {
if (processModel) {
if (processModelFile.name.match(/\.(dmn|bpmn)$/)) {
navigate(
`/admin/process-models/${modifiedProcessModelId}/files/${processModelFile.name}`
);
} else if (processModelFile.name.match(/\.(json|md)$/)) {
navigate(
`/admin/process-models/${modifiedProcessModelId}/form/${processModelFile.name}`
);
return `/admin/process-models/${modifiedProcessModelId}/files/${processModelFile.name}`;
}
if (processModelFile.name.match(/\.(json|md)$/)) {
return `/admin/process-models/${modifiedProcessModelId}/form/${processModelFile.name}`;
}
}
return null;
};
const navigateToFileEdit = (processModelFile: ProcessFile) => {
const url = profileModelFileEditUrl(processModelFile);
if (url) {
navigate(url);
}
};
@ -324,10 +326,15 @@ export default function ProcessModelShow() {
if (isPrimaryBpmnFile) {
primarySuffix = '- Primary File';
}
let fileLink = null;
const fileUrl = profileModelFileEditUrl(processModelFile);
if (fileUrl) {
fileLink = <Link to={fileUrl}>{processModelFile.name}</Link>;
}
constructedTag = (
<TableRow key={processModelFile.name}>
<TableCell key={`${processModelFile.name}-cell`}>
{processModelFile.name}
{fileLink}
{primarySuffix}
</TableCell>
{actionsTableCell}
@ -371,14 +378,6 @@ export default function ProcessModelShow() {
List
</Link>
</li>
<li>
<Link
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/reports`}
data-qa="process-instance-reports-link"
>
Reports
</Link>
</li>
</ul>
);
};
@ -440,63 +439,67 @@ export default function ProcessModelShow() {
return null;
}
return (
<Accordion>
<AccordionItem
data-qa="files-accordion"
title={
<Stack orientation="horizontal">
<span>
<Button size="sm" kind="ghost">
Files
<Grid fullWidth>
<Column md={5} lg={9} sm={3}>
<Accordion align="end">
<AccordionItem
data-qa="files-accordion"
title={
<Stack orientation="horizontal">
<span>
<Button size="sm" kind="ghost">
Files
</Button>
</span>
</Stack>
}
>
<ButtonSet>
<Button
renderIcon={Upload}
data-qa="upload-file-button"
onClick={() => setShowFileUploadModal(true)}
size="sm"
kind=""
className="button-white-background"
>
Upload File
</Button>
</span>
</Stack>
}
>
<ButtonSet>
<Button
renderIcon={Upload}
data-qa="upload-file-button"
onClick={() => setShowFileUploadModal(true)}
size="sm"
kind=""
className="button-white-background"
>
Upload File
</Button>
<Button
renderIcon={Add}
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=bpmn`}
size="sm"
>
New BPMN File
</Button>
<Button
renderIcon={Add}
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=dmn`}
size="sm"
>
New DMN File
</Button>
<Button
renderIcon={Add}
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=json`}
size="sm"
>
New JSON File
</Button>
<Button
renderIcon={Add}
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=md`}
size="sm"
>
New Markdown File
</Button>
</ButtonSet>
<br />
{processModelFileList()}
</AccordionItem>
</Accordion>
<Button
renderIcon={Add}
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=bpmn`}
size="sm"
>
New BPMN File
</Button>
<Button
renderIcon={Add}
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=dmn`}
size="sm"
>
New DMN File
</Button>
<Button
renderIcon={Add}
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=json`}
size="sm"
>
New JSON File
</Button>
<Button
renderIcon={Add}
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=md`}
size="sm"
>
New Markdown File
</Button>
</ButtonSet>
<br />
{processModelFileList()}
</AccordionItem>
</Accordion>
</Column>
</Grid>
);
};

View File

@ -153,9 +153,6 @@ export default function ReactFormEditor() {
return (
<main>
<ProcessBreadcrumb
processGroupId={params.process_group_id}
processModelId={params.process_model_id}
linkProcessModel
hotCrumbs={[
['Process Groups', '/admin'],
[
@ -169,10 +166,10 @@ export default function ReactFormEditor() {
[processModelFileName],
]}
/>
<h2>
<h1>
Process Model File{processModelFile ? ': ' : ''}
{processModelFileName}
</h2>
</h1>
{newFileNameBox()}
<Button onClick={saveFile} variant="danger" data-qa="file-save-button">
Save

View File

@ -95,7 +95,7 @@ export default function SecretList() {
if (pagination) {
return (
<div>
<h2>Secrets</h2>
<h1>Secrets</h1>
{SecretsDisplayArea()}
<Button href="/admin/secrets/new">Add a secret</Button>
</div>

View File

@ -46,7 +46,7 @@ export default function SecretNew() {
return (
<main style={{ padding: '1rem 0' }}>
<h2>Add Secret</h2>
<h1>Add Secret</h1>
<Form onSubmit={addSecret}>
<Form.Group className="mb-3" controlId="formDisplayName">
<Form.Label>

View File

@ -65,7 +65,7 @@ export default function SecretShow() {
if (secret) {
return (
<>
<h2>Secret Key: {secret.key}</h2>
<h1>Secret Key: {secret.key}</h1>
<Stack orientation="horizontal" gap={3}>
<ButtonWithConfirmation
description="Delete Secret?"