mirror of
https://github.com/sartography/spiff-arena.git
synced 2025-02-23 06:38:24 +00:00
updated data stores w/ burnettk
This commit is contained in:
parent
d18c8982b3
commit
6d2bf9d510
@ -0,0 +1,294 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
TextField,
|
||||
Select,
|
||||
MenuItem,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
TextareaAutosize,
|
||||
Stack,
|
||||
} from '@mui/material';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { DataStore, DataStoreType } from '../interfaces';
|
||||
import {
|
||||
modifyProcessIdentifierForPathParam,
|
||||
truncateString,
|
||||
} from '../helpers';
|
||||
|
||||
type OwnProps = {
|
||||
mode: string;
|
||||
dataStore: DataStore;
|
||||
setDataStore: (..._args: any[]) => any;
|
||||
};
|
||||
|
||||
export default function DataStoreForm({
|
||||
mode,
|
||||
dataStore,
|
||||
setDataStore,
|
||||
}: OwnProps) {
|
||||
const [identifierInvalid, setIdentifierInvalid] = useState<boolean>(false);
|
||||
const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] =
|
||||
useState<boolean>(false);
|
||||
const [nameInvalid, setNameInvalid] = useState<boolean>(false);
|
||||
const [typeInvalid, setTypeInvalid] = useState<boolean>(false);
|
||||
const [schemaInvalid, setSchemaInvalid] = useState<boolean>(false);
|
||||
const [dataStoreTypes, setDataStoreTypes] = useState<[DataStoreType] | []>(
|
||||
[],
|
||||
);
|
||||
const [selectedDataStoreType, setSelectedDataStoreType] =
|
||||
useState<DataStoreType | null>(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const dataStoreLocation = () => {
|
||||
const searchParams = new URLSearchParams(document.location.search);
|
||||
const parentGroupId = searchParams.get('parentGroupId');
|
||||
|
||||
return parentGroupId ?? '/';
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleSetDataStoreTypesCallback = (result: any) => {
|
||||
const dataStoreType = result.find((item: any) => {
|
||||
return item.type === dataStore.type;
|
||||
});
|
||||
setDataStoreTypes(result);
|
||||
setSelectedDataStoreType(dataStoreType ?? null);
|
||||
};
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path: '/data-stores/types',
|
||||
successCallback: handleSetDataStoreTypesCallback,
|
||||
httpMethod: 'GET',
|
||||
});
|
||||
}, [dataStore, setDataStoreTypes]);
|
||||
|
||||
const navigateToDataStores = (_result: any) => {
|
||||
const location = dataStoreLocation();
|
||||
if (location !== '/') {
|
||||
navigate(
|
||||
`/process-groups/${modifyProcessIdentifierForPathParam(location)}`,
|
||||
);
|
||||
} else {
|
||||
navigate(`/process-groups`);
|
||||
}
|
||||
};
|
||||
|
||||
const hasValidIdentifier = (identifierToCheck: string) => {
|
||||
return identifierToCheck.match(/^[a-z][0-9a-z_]*[a-z0-9]$/);
|
||||
};
|
||||
|
||||
const handleFormSubmission = (event: any) => {
|
||||
const searchParams = new URLSearchParams(document.location.search);
|
||||
const parentGroupId = searchParams.get('parentGroupId');
|
||||
|
||||
event.preventDefault();
|
||||
let hasErrors = false;
|
||||
if (mode === 'new' && !hasValidIdentifier(dataStore.id)) {
|
||||
setIdentifierInvalid(true);
|
||||
hasErrors = true;
|
||||
}
|
||||
if (dataStore.name === '') {
|
||||
setNameInvalid(true);
|
||||
hasErrors = true;
|
||||
}
|
||||
if (selectedDataStoreType === null) {
|
||||
setTypeInvalid(true);
|
||||
hasErrors = true;
|
||||
}
|
||||
if (dataStore.schema === '') {
|
||||
setSchemaInvalid(true);
|
||||
hasErrors = true;
|
||||
}
|
||||
if (hasErrors) {
|
||||
return;
|
||||
}
|
||||
const path = '/data-stores';
|
||||
let httpMethod = 'POST';
|
||||
if (mode === 'edit') {
|
||||
httpMethod = 'PUT';
|
||||
}
|
||||
const postBody = {
|
||||
id: dataStore.id,
|
||||
name: dataStore.name,
|
||||
description: dataStore.description,
|
||||
type: dataStore.type,
|
||||
schema: dataStore.schema,
|
||||
location: parentGroupId ?? '/',
|
||||
};
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path,
|
||||
successCallback: navigateToDataStores,
|
||||
httpMethod,
|
||||
postBody,
|
||||
});
|
||||
};
|
||||
|
||||
const updateDataStore = (newValues: any) => {
|
||||
const dataStoreToCopy = {
|
||||
...dataStore,
|
||||
};
|
||||
Object.assign(dataStoreToCopy, newValues);
|
||||
setDataStore(dataStoreToCopy);
|
||||
};
|
||||
|
||||
const makeIdentifier = (str: any) => {
|
||||
return str
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[^\w\s-]/g, '')
|
||||
.replace(/[\s-]+/g, '_')
|
||||
.replace(/^[-\d]+/g, '')
|
||||
.replace(/-+$/g, '');
|
||||
};
|
||||
|
||||
const onNameChanged = (newName: any) => {
|
||||
setNameInvalid(false);
|
||||
const updateDict = { name: newName };
|
||||
if (!idHasBeenUpdatedByUser && mode === 'new') {
|
||||
Object.assign(updateDict, { id: makeIdentifier(newName) });
|
||||
}
|
||||
updateDataStore(updateDict);
|
||||
};
|
||||
|
||||
const onTypeChanged = (event: any) => {
|
||||
setTypeInvalid(false);
|
||||
const newTypeSelection = event.target.value;
|
||||
if (newTypeSelection) {
|
||||
const updateDict = { type: newTypeSelection };
|
||||
updateDataStore(updateDict);
|
||||
}
|
||||
setSelectedDataStoreType(newTypeSelection);
|
||||
};
|
||||
|
||||
const onSchemaChanged = (newSchema: any) => {
|
||||
setSchemaInvalid(false);
|
||||
const updateDict = { schema: newSchema };
|
||||
updateDataStore(updateDict);
|
||||
};
|
||||
|
||||
const dataStoreTypeDisplayString = (
|
||||
dataStoreType: DataStoreType | null,
|
||||
): string => {
|
||||
if (dataStoreType) {
|
||||
return `${dataStoreType.name} (${truncateString(
|
||||
dataStoreType.description,
|
||||
75,
|
||||
)})`;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const formElements = () => {
|
||||
const textInputs = [
|
||||
<TextField
|
||||
id="data-store-name"
|
||||
data-qa="data-store-name-input"
|
||||
name="name"
|
||||
error={nameInvalid}
|
||||
helperText={nameInvalid ? "Name is required." : ""}
|
||||
label="Name*"
|
||||
value={dataStore.name}
|
||||
onChange={(event: any) => onNameChanged(event.target.value)}
|
||||
/>,
|
||||
];
|
||||
|
||||
textInputs.push(
|
||||
<TextField
|
||||
id="data-store-identifier"
|
||||
name="id"
|
||||
InputProps={{
|
||||
readOnly: mode === 'edit',
|
||||
}}
|
||||
error={identifierInvalid}
|
||||
helperText={identifierInvalid ? "Identifier is required and must be all lowercase characters and hyphens." : ""}
|
||||
label="Identifier*"
|
||||
value={dataStore.id}
|
||||
onChange={(event: any) => {
|
||||
updateDataStore({ id: event.target.value });
|
||||
if (identifierInvalid && hasValidIdentifier(event.target.value)) {
|
||||
setIdentifierInvalid(false);
|
||||
}
|
||||
setIdHasBeenUpdatedByUser(true);
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
if (mode === 'edit') {
|
||||
textInputs.push(
|
||||
<TextField
|
||||
id="data-store-type"
|
||||
name="data-store-type"
|
||||
InputProps={{
|
||||
readOnly: true,
|
||||
}}
|
||||
label="Type*"
|
||||
value={dataStoreTypeDisplayString(selectedDataStoreType)}
|
||||
/>,
|
||||
);
|
||||
} else {
|
||||
textInputs.push(
|
||||
<FormControl fullWidth error={typeInvalid}>
|
||||
<InputLabel id="data-store-type-select-label">Type*</InputLabel>
|
||||
<Select
|
||||
labelId="data-store-type-select-label"
|
||||
id="data-store-type-select"
|
||||
value={selectedDataStoreType ? selectedDataStoreType.type : ''}
|
||||
onChange={onTypeChanged}
|
||||
label="Type*"
|
||||
>
|
||||
{dataStoreTypes.map((type) => (
|
||||
<MenuItem key={type.type} value={type.type}>
|
||||
{dataStoreTypeDisplayString(type)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
|
||||
textInputs.push(
|
||||
<TextField
|
||||
id="data-store-schema"
|
||||
name="schema"
|
||||
error={schemaInvalid}
|
||||
helperText={schemaInvalid ? "Schema is required and must be valid JSON." : ""}
|
||||
label="Schema*"
|
||||
multiline
|
||||
minRows={3}
|
||||
value={dataStore.schema}
|
||||
onChange={(event: any) => onSchemaChanged(event.target.value)}
|
||||
/>,
|
||||
);
|
||||
|
||||
textInputs.push(
|
||||
<TextareaAutosize
|
||||
id="data-store-description"
|
||||
name="description"
|
||||
aria-label="Description"
|
||||
placeholder="Description"
|
||||
value={dataStore.description}
|
||||
onChange={(event: any) =>
|
||||
updateDataStore({ description: event.target.value })
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
return textInputs;
|
||||
};
|
||||
|
||||
const formButtons = () => {
|
||||
return <Button type="submit" variant="contained">Submit</Button>;
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleFormSubmission}>
|
||||
<Stack spacing={2}>
|
||||
{formElements()}
|
||||
{formButtons()}
|
||||
</Stack>
|
||||
</form>
|
||||
);
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
Table,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TablePagination,
|
||||
Paper,
|
||||
MenuItem,
|
||||
Select,
|
||||
InputLabel,
|
||||
FormControl,
|
||||
} from '@mui/material';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { DataStore, DataStoreRecords, PaginationObject } from '../interfaces';
|
||||
import PaginationForTable from './PaginationForTable';
|
||||
import { getPageInfoFromSearchParams } from '../helpers';
|
||||
|
||||
export default function DataStoreListTable() {
|
||||
const [dataStores, setDataStores] = useState<DataStore[]>([]);
|
||||
const [dataStore, setDataStore] = useState<DataStore | null>(null);
|
||||
const [pagination, setPagination] = useState<PaginationObject | null>(null);
|
||||
const [results, setResults] = useState<any[]>([]);
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/data-stores`,
|
||||
successCallback: (newStores: DataStore[]) => {
|
||||
setDataStores(newStores);
|
||||
},
|
||||
});
|
||||
}, []); // Do this once so we have a list of data stores to select from.
|
||||
|
||||
useEffect(() => {
|
||||
const { page, perPage } = getPageInfoFromSearchParams(
|
||||
searchParams,
|
||||
10,
|
||||
1,
|
||||
'datastore',
|
||||
);
|
||||
const dataStoreType = searchParams.get('type') || '';
|
||||
const dataStoreIdentifier = searchParams.get('identifier') || '';
|
||||
const dataStoreLocation = searchParams.get('location') || '';
|
||||
|
||||
if (dataStoreType === '' || dataStoreIdentifier === '') {
|
||||
return;
|
||||
}
|
||||
if (dataStores && dataStoreIdentifier && dataStoreType) {
|
||||
dataStores.forEach((ds) => {
|
||||
if (
|
||||
ds.id === dataStoreIdentifier &&
|
||||
ds.type === dataStoreType &&
|
||||
ds.location === dataStoreLocation
|
||||
) {
|
||||
setDataStore(ds);
|
||||
}
|
||||
});
|
||||
}
|
||||
const queryParamString = `per_page=${perPage}&page=${page}&location=${dataStoreLocation}`;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/data-stores/${dataStoreType}/${dataStoreIdentifier}/items?${queryParamString}`,
|
||||
successCallback: (response: DataStoreRecords) => {
|
||||
setResults(response.results);
|
||||
setPagination(response.pagination);
|
||||
},
|
||||
});
|
||||
}, [dataStores, searchParams]);
|
||||
|
||||
const getCell = (value: any) => {
|
||||
const valueToUse =
|
||||
typeof value === 'object' ? (
|
||||
<pre>
|
||||
<code>{JSON.stringify(value, null, 4)}</code>
|
||||
</pre>
|
||||
) : (
|
||||
value
|
||||
);
|
||||
|
||||
return <TableCell>{valueToUse}</TableCell>;
|
||||
};
|
||||
|
||||
const getTable = () => {
|
||||
if (results.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const firstResult = results[0];
|
||||
const tableHeaders: any[] = [];
|
||||
const keys = Object.keys(firstResult);
|
||||
keys.forEach((key) => tableHeaders.push(<TableCell>{key}</TableCell>));
|
||||
|
||||
return (
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>{tableHeaders}</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{results.map((object) => {
|
||||
return (
|
||||
<TableRow>
|
||||
{keys.map((key) => {
|
||||
return getCell(object[key]);
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const locationDescription = (ds: DataStore) => {
|
||||
return ds.location ? ` @ ${ds.location}` : '';
|
||||
};
|
||||
|
||||
const { page, perPage } = getPageInfoFromSearchParams(
|
||||
searchParams,
|
||||
10,
|
||||
1,
|
||||
'datastore',
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="data-store-dropdown-label">Select Data Store</InputLabel>
|
||||
<Select
|
||||
labelId="data-store-dropdown-label"
|
||||
id="data-store-dropdown"
|
||||
value={dataStore ? dataStore.id : ''}
|
||||
onChange={(event) => {
|
||||
const selectedDataStore = dataStores.find(ds => ds.id === event.target.value);
|
||||
if (selectedDataStore) {
|
||||
setDataStore(selectedDataStore);
|
||||
searchParams.set('datastore_page', '1');
|
||||
searchParams.set('datastore_per_page', '10');
|
||||
searchParams.set('type', selectedDataStore.type);
|
||||
searchParams.set('identifier', selectedDataStore.id);
|
||||
searchParams.set('location', selectedDataStore.location);
|
||||
setSearchParams(searchParams);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{dataStores.map((ds) => (
|
||||
<MenuItem key={ds.id} value={ds.id}>
|
||||
{`${ds.name} (${ds.type}${locationDescription(ds)})`}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={getTable()}
|
||||
paginationQueryParamPrefix="datastore"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
@ -162,6 +162,7 @@ function SideNav({
|
||||
{[
|
||||
{ text: 'HOME', icon: <Home /> },
|
||||
{ text: 'START NEW PROCESS', icon: <Add /> },
|
||||
{ text: 'DATA STORES' },
|
||||
].map((item, index) => (
|
||||
<ListItem
|
||||
button
|
||||
@ -172,6 +173,8 @@ function SideNav({
|
||||
navigate('/newui');
|
||||
} else if (index === 1) {
|
||||
navigate('/newui/startprocess');
|
||||
} else if (item.text === 'DATA STORES') {
|
||||
navigate('/newui/data-stores');
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
|
@ -0,0 +1,59 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import DataStoreForm from '../components/DataStoreForm';
|
||||
import { DataStore, HotCrumbItem } from '../interfaces';
|
||||
import { setPageTitle } from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
|
||||
export default function DataStoreEdit() {
|
||||
const params = useParams();
|
||||
const [searchParams] = useSearchParams();
|
||||
const parentGroupId = searchParams.get('parentGroupId');
|
||||
const dataStoreType = searchParams.get('type');
|
||||
const dataStoreIdentifier = params.data_store_identifier;
|
||||
const [dataStore, setDataStore] = useState<DataStore>({
|
||||
id: '',
|
||||
name: '',
|
||||
type: '',
|
||||
schema: '',
|
||||
description: '',
|
||||
});
|
||||
useEffect(() => {
|
||||
setPageTitle(['Edit Data Store']);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const setDataStoreFromResult = (result: any) => {
|
||||
const schema = JSON.stringify(result.schema);
|
||||
setDataStore({ ...result, schema });
|
||||
};
|
||||
|
||||
const queryParams = `?process_group_identifier=${parentGroupId}`;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/data-stores/${dataStoreType}/${dataStoreIdentifier}${queryParams}`,
|
||||
successCallback: setDataStoreFromResult,
|
||||
});
|
||||
}, [dataStoreIdentifier, parentGroupId, dataStoreType]);
|
||||
|
||||
const hotCrumbs: HotCrumbItem[] = [['Process Groups', '/process-groups']];
|
||||
if (parentGroupId) {
|
||||
hotCrumbs.push({
|
||||
entityToExplode: parentGroupId,
|
||||
entityType: 'process-group-id',
|
||||
linkLastItem: true,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProcessBreadcrumb hotCrumbs={hotCrumbs} />
|
||||
<h1>Edit Data Store</h1>
|
||||
<DataStoreForm
|
||||
mode="edit"
|
||||
dataStore={dataStore}
|
||||
setDataStore={setDataStore}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import DataStoreListTable from '../components/DataStoreListTable';
|
||||
import { setPageTitle } from '../helpers';
|
||||
import { Typography } from '@mui/material';
|
||||
|
||||
export default function DataStoreList() {
|
||||
setPageTitle(['Data Stores']);
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h1">Data Stores</Typography>
|
||||
<DataStoreListTable />
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import Breadcrumbs from '@mui/material/Breadcrumbs';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Link from '@mui/material/Link';
|
||||
import DataStoreForm from '../components/DataStoreForm';
|
||||
import { DataStore, HotCrumbItem } from '../interfaces';
|
||||
import { setPageTitle } from '../helpers';
|
||||
|
||||
export default function DataStoreNew() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const parentGroupId = searchParams.get('parentGroupId');
|
||||
const [dataStore, setDataStore] = useState<DataStore>({
|
||||
id: '',
|
||||
name: '',
|
||||
type: '',
|
||||
schema: '{}',
|
||||
description: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setPageTitle(['New Data Store']);
|
||||
}, []);
|
||||
|
||||
const hotCrumbs: HotCrumbItem[] = [['Process Groups', '/process-groups']];
|
||||
if (parentGroupId) {
|
||||
hotCrumbs.push({
|
||||
entityToExplode: parentGroupId,
|
||||
entityType: 'process-group-id',
|
||||
linkLastItem: true,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
{hotCrumbs.map((crumb, index) => (
|
||||
<Link
|
||||
key={index}
|
||||
color="inherit"
|
||||
href={typeof crumb === 'string' ? crumb[1] : ''}
|
||||
>
|
||||
{typeof crumb === 'string' ? crumb[0] : crumb.entityToExplode}
|
||||
</Link>
|
||||
))}
|
||||
</Breadcrumbs>
|
||||
<Typography variant="h4" component="h1" gutterBottom>
|
||||
Add Data Store
|
||||
</Typography>
|
||||
<DataStoreForm
|
||||
mode="new"
|
||||
dataStore={dataStore}
|
||||
setDataStore={setDataStore}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import DataStoreList from './DataStoreList';
|
||||
import DataStoreNew from './DataStoreNew';
|
||||
import DataStoreEdit from './DataStoreEdit';
|
||||
|
||||
export default function DataStoreRoutes() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<DataStoreList />} />
|
||||
<Route path=":data_store_identifier/edit" element={<DataStoreEdit />} />
|
||||
<Route path="new" element={<DataStoreNew />} />
|
||||
</Routes>
|
||||
);
|
||||
}
|
@ -29,6 +29,9 @@ import About from '../a-spiffui-v3/views/About';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
import ComingSoon from '../components/ComingSoon';
|
||||
import MessageListPage from '../a-spiffui-v3/views/MessageListPage';
|
||||
import DataStoreRoutes from '../a-spiffui-v3/views/DataStoreRoutes';
|
||||
import DataStoreNew from '../a-spiffui-v3/views/DataStoreNew';
|
||||
import DataStoreList from '../a-spiffui-v3/views/DataStoreList'; // Import the DataStoreList component
|
||||
|
||||
const fadeIn = 'fadeIn';
|
||||
const fadeOutImmediate = 'fadeOutImmediate';
|
||||
@ -249,6 +252,13 @@ export default function SpiffUIV3() {
|
||||
{/* element={<ProcessInstanceProgressPage variant="all" />} */}
|
||||
{/* /> */}
|
||||
<Route path="/messages" element={<MessageListPage />} />
|
||||
<Route path="/data-stores/*" element={<DataStoreRoutes />} />
|
||||
<Route path="/data-store/new" element={<DataStoreNew />} />
|
||||
<Route
|
||||
path="/data-storelist"
|
||||
element={<DataStoreList />}
|
||||
/>{' '}
|
||||
{/* Add route for DataStoreList */}
|
||||
</Routes>
|
||||
</Box>
|
||||
</Box>
|
||||
|
Loading…
x
Reference in New Issue
Block a user