Use vite to build (#1390)
* some base updates for vite w/ burnettk * i can log in w/ burnettk * a couple more fixes w/ burnettk * make sure selectedTabIndex has been set before using it w/ burnettk * fixed active-users db issue, added type module to package json to fix prerender issues, and various other issues w/ burnettk * fixed issues with building and running from compiled w/ burnettk * pyl * eslint fix is running and removed both inferno and navigationBar warnings * vim likes the Dockerfile suffix by default * use process.env.HOME * probably do not need alias * a little clean up and fixed font warnings w/ burnettk * updated elements to remove warnings in the console w/ burnettk * fixed es lint issues w/ burnettk * update docker build in frontend w/ burnettk * set the specific tag of nginx w/ burnettk * build docker imgaes for this branch to test w/ burnettk * added vitest and updated Dockerfile to be nginx w/ burnettk * tests are passing w/ burnettk * add prefresh and more keys * added cypress-vite to attempt to get cypress working again * some coderabbit suggestions * hopefully there is no reason to use PUBLIC_URL at all when using vite * use the correct location of the index file in the docker image * spaces are fine in index.html file variable declaration --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com> Co-authored-by: burnettk <burnettk@users.noreply.github.com>
This commit is contained in:
parent
fd11e627f2
commit
9147a8db8c
|
@ -32,6 +32,7 @@ on:
|
||||||
- main
|
- main
|
||||||
- spiffdemo
|
- spiffdemo
|
||||||
- GSA-TTS-fix-path-routing-in-generated-openid-urls
|
- GSA-TTS-fix-path-routing-in-generated-openid-urls
|
||||||
|
- use-vite-to-build
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
create_frontend_docker_image:
|
create_frontend_docker_image:
|
||||||
|
|
|
@ -2,6 +2,7 @@ import json
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import flask.wrappers
|
import flask.wrappers
|
||||||
|
import sqlalchemy
|
||||||
from flask import g
|
from flask import g
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from flask import make_response
|
from flask import make_response
|
||||||
|
@ -13,17 +14,30 @@ from spiffworkflow_backend.models.user import UserModel
|
||||||
|
|
||||||
|
|
||||||
def active_user_updates(last_visited_identifier: str) -> Response:
|
def active_user_updates(last_visited_identifier: str) -> Response:
|
||||||
active_user = ActiveUserModel.query.filter_by(user_id=g.user.id, last_visited_identifier=last_visited_identifier).first()
|
current_time = round(time.time())
|
||||||
|
query_args = {"user_id": g.user.id, "last_visited_identifier": last_visited_identifier}
|
||||||
|
active_user = ActiveUserModel.query.filter_by(**query_args).first()
|
||||||
|
|
||||||
if active_user is None:
|
if active_user is None:
|
||||||
active_user = ActiveUserModel(
|
active_user = ActiveUserModel(
|
||||||
user_id=g.user.id, last_visited_identifier=last_visited_identifier, last_seen_in_seconds=round(time.time())
|
user_id=g.user.id, last_visited_identifier=last_visited_identifier, last_seen_in_seconds=current_time
|
||||||
)
|
)
|
||||||
db.session.add(active_user)
|
db.session.add(active_user)
|
||||||
db.session.commit()
|
try:
|
||||||
|
db.session.commit()
|
||||||
active_user.last_seen_in_seconds = round(time.time())
|
except sqlalchemy.exc.IntegrityError:
|
||||||
db.session.add(active_user)
|
# duplicate entry. two processes are trying to create the same entry at the same time. it is fine to drop one request.
|
||||||
db.session.commit()
|
db.session.rollback()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
db.session.query(ActiveUserModel).filter_by(**query_args).update({"last_seen_in_seconds": current_time})
|
||||||
|
db.session.commit()
|
||||||
|
except sqlalchemy.exc.OperationalError as exception:
|
||||||
|
if "Deadlock" in str(exception):
|
||||||
|
# two processes are trying to update the same entry at the same time. it is fine to drop one request.
|
||||||
|
db.session.rollback()
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
cutoff_time_in_seconds = time.time() - 30
|
cutoff_time_in_seconds = time.time() - 30
|
||||||
active_users = (
|
active_users = (
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
# production
|
# production
|
||||||
/build
|
/build
|
||||||
|
/dist
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
@ -9,12 +9,12 @@ WORKDIR /app
|
||||||
# procps for debugging
|
# procps for debugging
|
||||||
# vim ftw
|
# vim ftw
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get clean -y \
|
&& apt-get clean -y \
|
||||||
&& apt-get install -y -q \
|
&& apt-get install -y -q \
|
||||||
curl \
|
curl \
|
||||||
procps \
|
procps \
|
||||||
vim-tiny \
|
vim-tiny \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# this matches total memory on spiffworkflow-demo
|
# this matches total memory on spiffworkflow-demo
|
||||||
ENV NODE_OPTIONS=--max_old_space_size=2048
|
ENV NODE_OPTIONS=--max_old_space_size=2048
|
||||||
|
@ -44,19 +44,17 @@ RUN ./bin/build
|
||||||
|
|
||||||
######################## - FINAL
|
######################## - FINAL
|
||||||
|
|
||||||
# Final image without setup dependencies.
|
# Use nginx as the base image
|
||||||
FROM base AS final
|
FROM nginx:1.25.4-bookworm
|
||||||
|
|
||||||
LABEL description="Frontend component of SpiffWorkflow, a software development platform for building, running, and monitoring executable diagrams"
|
# Remove default nginx configuration
|
||||||
|
RUN rm -rf /etc/nginx/conf.d/*
|
||||||
|
|
||||||
# WARNING: On localhost frontend assumes backend is one port lower.
|
# Copy the nginx configuration file
|
||||||
ENV PORT0=7001
|
COPY docker_build/nginx.conf.template /var/tmp
|
||||||
|
|
||||||
COPY --from=setup /app/build /app/build
|
# Copy the built static files into the nginx directory
|
||||||
|
COPY --from=setup /app/dist /usr/share/nginx/html
|
||||||
COPY --from=setup /app/bin /app/bin
|
COPY --from=setup /app/bin /app/bin
|
||||||
COPY --from=setup /app/node_modules.justserve /app/node_modules
|
|
||||||
|
|
||||||
RUN chown -R node:node /app
|
|
||||||
|
|
||||||
USER node
|
|
||||||
CMD ["/app/bin/boot_server_in_docker"]
|
CMD ["/app/bin/boot_server_in_docker"]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
function error_handler() {
|
function error_handler() {
|
||||||
>&2 echo "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}."
|
echo >&2 "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}."
|
||||||
exit "$2"
|
exit "$2"
|
||||||
}
|
}
|
||||||
trap 'error_handler ${LINENO} $?' ERR
|
trap 'error_handler ${LINENO} $?' ERR
|
||||||
|
@ -10,19 +10,19 @@ set -o errtrace -o errexit -o nounset -o pipefail
|
||||||
# sort of like https://lithic.tech/blog/2020-05/react-dynamic-config, but without golang
|
# sort of like https://lithic.tech/blog/2020-05/react-dynamic-config, but without golang
|
||||||
react_configs=$(env | grep -E "^SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG_" || echo '')
|
react_configs=$(env | grep -E "^SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG_" || echo '')
|
||||||
if [[ -n "$react_configs" ]]; then
|
if [[ -n "$react_configs" ]]; then
|
||||||
index_html_file="./build/index.html"
|
index_html_file="/usr/share/nginx/html/index.html"
|
||||||
if [[ ! -f "$index_html_file" ]]; then
|
if [[ ! -f "$index_html_file" ]]; then
|
||||||
>&2 echo "ERROR: Could not find '${index_html_file}'. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
echo >&2 "ERROR: Could not find '${index_html_file}'. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v sed >/dev/null ; then
|
if ! command -v sed >/dev/null; then
|
||||||
>&2 echo "ERROR: sed command not found. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
echo >&2 "ERROR: sed command not found. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v perl >/dev/null ; then
|
if ! command -v perl >/dev/null; then
|
||||||
>&2 echo "ERROR: perl command not found. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
echo >&2 "ERROR: perl command not found. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -30,19 +30,25 @@ if [[ -n "$react_configs" ]]; then
|
||||||
react_config_without_prefix=$(sed -E 's/^SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG_([^=]*)=(.*)/\1=\\"\2\\"/' <<<"${react_config}")
|
react_config_without_prefix=$(sed -E 's/^SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG_([^=]*)=(.*)/\1=\\"\2\\"/' <<<"${react_config}")
|
||||||
|
|
||||||
if [[ -z "$react_config_without_prefix" ]]; then
|
if [[ -z "$react_config_without_prefix" ]]; then
|
||||||
>&2 echo "ERROR: Could not parse react config line: '${react_config}'."
|
echo >&2 "ERROR: Could not parse react config line: '${react_config}'."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
escaped_react_config=$(sed -E 's|/|\\/|g' <<<"${react_config_without_prefix}")
|
escaped_react_config=$(sed -E 's|/|\\/|g' <<<"${react_config_without_prefix}")
|
||||||
# actually do the search and replace to add the js config to the html page
|
# actually do the search and replace to add the js config to the html page
|
||||||
perl -pi -e "s/(window.spiffworkflowFrontendJsenv=\{\})/\1;window.spiffworkflowFrontendJsenv.${escaped_react_config}/" "$index_html_file"
|
perl -pi -e "s/(window.spiffworkflowFrontendJsenv *= *\{\})/\1;window.spiffworkflowFrontendJsenv.${escaped_react_config}/" "$index_html_file"
|
||||||
|
|
||||||
if ! grep -Eq "${react_config_without_prefix}" "$index_html_file"; then
|
if ! grep -Eq "${react_config_without_prefix}" "$index_html_file"; then
|
||||||
>&2 echo "ERROR: Could not find '${react_config_without_prefix}' in '${index_html_file}' after search and replace. It is likely that the assumptions in boot_server_in_docker about the contents of the html page have changed. Fix the glitch in boot_server_in_docker."
|
echo >&2 "ERROR: Could not find '${react_config_without_prefix}' in '${index_html_file}' after search and replace. It is likely that the assumptions in boot_server_in_docker about the contents of the html page have changed. Fix the glitch in boot_server_in_docker."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec ./node_modules/.bin/serve -s build -l "$PORT0"
|
port_to_use="${PORT0:-80}"
|
||||||
|
if [[ -n "${SPIFFWORKFLOW_FRONTEND_INTERNAL_PORT:-}" ]]; then
|
||||||
|
port_to_use="$SPIFFWORKFLOW_FRONTEND_INTERNAL_PORT"
|
||||||
|
fi
|
||||||
|
perl -p -e "s/{{SPIFFWORKFLOW_FRONTEND_INTERNAL_PORT}}/${port_to_use}/" /var/tmp/nginx.conf.template >/etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
exec nginx -g "daemon off;"
|
||||||
|
|
|
@ -9,7 +9,7 @@ set -o errtrace -o errexit -o nounset -o pipefail
|
||||||
|
|
||||||
if [[ -f "version_info.json" ]]; then
|
if [[ -f "version_info.json" ]]; then
|
||||||
version_info=$(cat version_info.json)
|
version_info=$(cat version_info.json)
|
||||||
export REACT_APP_VERSION_INFO="$version_info"
|
export VITE_VERSION_INFO="$version_info"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
npm run build
|
npm run build
|
||||||
|
|
Binary file not shown.
|
@ -1,63 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.m?[jt]sx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
plugins: [
|
|
||||||
[
|
|
||||||
'@babel/plugin-transform-react-jsx',
|
|
||||||
{
|
|
||||||
pragma: 'h',
|
|
||||||
pragmaFrag: 'Fragment',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@babel/preset-react',
|
|
||||||
'@babel/plugin-transform-typescript',
|
|
||||||
{
|
|
||||||
importSource: '@bpmn-io/properties-panel/preact',
|
|
||||||
runtime: 'automatic',
|
|
||||||
},
|
|
||||||
'@babel/plugin-proposal-class-properties',
|
|
||||||
{ loose: true },
|
|
||||||
'@babel/plugin-proposal-private-methods',
|
|
||||||
{ loose: true },
|
|
||||||
'@babel/plugin-proposal-private-property-in-object',
|
|
||||||
{ loose: true },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
webpack: {
|
|
||||||
configure: {
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
inferno:
|
|
||||||
process.env.NODE_ENV !== 'production'
|
|
||||||
? 'inferno/dist/index.dev.esm.js'
|
|
||||||
: 'inferno/dist/index.esm.js',
|
|
||||||
react: 'preact/compat',
|
|
||||||
'react-dom/test-utils': 'preact/test-utils',
|
|
||||||
'react-dom': 'preact/compat', // Must be below test-utils
|
|
||||||
'react/jsx-runtime': 'preact/jsx-runtime',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
babel: {
|
|
||||||
presets: [
|
|
||||||
'@babel/preset-env',
|
|
||||||
['@babel/preset-react', { runtime: 'automatic' }],
|
|
||||||
'@babel/preset-typescript',
|
|
||||||
],
|
|
||||||
// plugins: [],
|
|
||||||
loaderOptions: (babelLoaderOptions) => {
|
|
||||||
return babelLoaderOptions;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
const { defineConfig } = require('cypress');
|
import { defineConfig } from 'cypress';
|
||||||
const { rm } = require('fs/promises');
|
import { rm } from 'fs/promises';
|
||||||
|
import config from '@cypress/grep/src/plugin';
|
||||||
|
|
||||||
// yes use video compression in CI, where we will set the env var so we upload to cypress dashboard
|
// yes use video compression in CI, where we will set the env var so we upload to cypress dashboard
|
||||||
const useVideoCompression = !!process.env.CYPRESS_RECORD_KEY;
|
const useVideoCompression = !!process.env.CYPRESS_RECORD_KEY;
|
||||||
|
@ -40,7 +41,6 @@ const cypressConfig = {
|
||||||
baseUrl: spiffWorkflowFrontendUrl,
|
baseUrl: spiffWorkflowFrontendUrl,
|
||||||
setupNodeEvents(on, config) {
|
setupNodeEvents(on, config) {
|
||||||
deleteVideosOnSuccess(on);
|
deleteVideosOnSuccess(on);
|
||||||
require('@cypress/grep/src/plugin')(config);
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -56,4 +56,4 @@ if (!process.env.CYPRESS_RECORD_KEY) {
|
||||||
cypressConfig.videoCompression = false;
|
cypressConfig.videoCompression = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = defineConfig(cypressConfig);
|
export default defineConfig(cypressConfig);
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
server {
|
||||||
|
listen {{SPIFFWORKFLOW_FRONTEND_INTERNAL_PORT}};
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,38 +2,29 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="version-info" content='%REACT_APP_VERSION_INFO%' />
|
<meta name="version-info" content='%VITE_VERSION_INFO%' />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="A turnkey solution for building and executing the workflows that drive your business"
|
content="A turnkey solution for building and executing the workflows that drive your business"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="/logo192.png" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<!--
|
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
|
||||||
-->
|
|
||||||
<title>SpiffWorkflow</title>
|
<title>SpiffWorkflow</title>
|
||||||
<script>
|
<script>
|
||||||
window.spiffworkflowFrontendJsenv = {};
|
window.spiffworkflowFrontendJsenv = {};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
<!--
|
<!--
|
||||||
This HTML file is a template.
|
This HTML file is a template.
|
||||||
If you open it directly in the browser, you will see an empty page.
|
If you open it directly in the browser, you will see an empty page.
|
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,7 @@
|
||||||
"name": "spiffworkflow-frontend",
|
"name": "spiffworkflow-frontend",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.24.3",
|
"@babel/core": "^7.24.3",
|
||||||
"@babel/plugin-transform-react-jsx": "^7.18.6",
|
"@babel/plugin-transform-react-jsx": "^7.18.6",
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
"@microsoft/fetch-event-source": "^2.0.1",
|
"@microsoft/fetch-event-source": "^2.0.1",
|
||||||
"@monaco-editor/react": "^4.4.5",
|
"@monaco-editor/react": "^4.4.5",
|
||||||
"@mui/material": "^5.10.14",
|
"@mui/material": "^5.10.14",
|
||||||
|
"@prefresh/vite": "^2.4.5",
|
||||||
"@react-icons/all-files": "^4.1.0",
|
"@react-icons/all-files": "^4.1.0",
|
||||||
"@rjsf/core": "5.0.0-beta.20",
|
"@rjsf/core": "5.0.0-beta.20",
|
||||||
"@rjsf/mui": "5.0.0-beta.20",
|
"@rjsf/mui": "5.0.0-beta.20",
|
||||||
|
@ -26,15 +28,15 @@
|
||||||
"@testing-library/react": "^14.2.1",
|
"@testing-library/react": "^14.2.1",
|
||||||
"@testing-library/user-event": "^14.5.2",
|
"@testing-library/user-event": "^14.5.2",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/node": "^20.12.6",
|
|
||||||
"@types/react": "^18.0.17",
|
"@types/react": "^18.0.17",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@uiw/react-md-editor": "^3.20.2",
|
"@uiw/react-md-editor": "^3.20.2",
|
||||||
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"autoprefixer": "^10.4.13",
|
"autoprefixer": "^10.4.13",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"bpmn-js": "^13.2.2",
|
"bpmn-js": "^13.2.2",
|
||||||
"bpmn-js-properties-panel": "^1.22.0",
|
"bpmn-js-properties-panel": "^1.22.0",
|
||||||
"bpmn-js-spiffworkflow": "github:sartography/bpmn-js-spiffworkflow#main",
|
"bpmn-js-spiffworkflow": "github:sartography/bpmn-js-spiffworkflow#vite-support",
|
||||||
"cookie": "^0.6.0",
|
"cookie": "^0.6.0",
|
||||||
"craco": "^0.0.3",
|
"craco": "^0.0.3",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
|
@ -55,11 +57,12 @@
|
||||||
"react-jsonschema-form": "^1.8.1",
|
"react-jsonschema-form": "^1.8.1",
|
||||||
"react-router": "^6.22.2",
|
"react-router": "^6.22.2",
|
||||||
"react-router-dom": "^6.22.3",
|
"react-router-dom": "^6.22.3",
|
||||||
"react-scripts": "^5.0.1",
|
|
||||||
"serve": "^14.0.0",
|
"serve": "^14.0.0",
|
||||||
"timepicker": "^1.13.18",
|
"timepicker": "^1.13.18",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
"use-debounce": "^10.0.0",
|
"use-debounce": "^10.0.0",
|
||||||
|
"vite": "^5.2.8",
|
||||||
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
"web-vitals": "^3.5.2"
|
"web-vitals": "^3.5.2"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
@ -68,12 +71,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "ESLINT_NO_DEV_ERRORS=true PORT=7001 craco start",
|
"start": "VITE_VERSION_INFO='{\"version\":\"local\"}' vite",
|
||||||
"docker:start": "ESLINT_NO_DEV_ERRORS=true craco start",
|
"build": "vite build",
|
||||||
"build": "craco build",
|
"serve": "vite preview",
|
||||||
"test": "react-scripts test --coverage",
|
"test": "vitest run --coverage",
|
||||||
"t": "npm test -- --watchAll=false",
|
|
||||||
"eject": "craco eject",
|
|
||||||
"format": "prettier --write src/**/*.[tj]s{,x}",
|
"format": "prettier --write src/**/*.[tj]s{,x}",
|
||||||
"lint": "./node_modules/.bin/eslint src",
|
"lint": "./node_modules/.bin/eslint src",
|
||||||
"lint:fix": "./node_modules/.bin/eslint --fix src"
|
"lint:fix": "./node_modules/.bin/eslint --fix src"
|
||||||
|
@ -98,15 +99,19 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cypress/grep": "^3.1.0",
|
"@cypress/grep": "^3.1.0",
|
||||||
|
"@preact/preset-vite": "^2.8.2",
|
||||||
"@tanstack/eslint-plugin-query": "^5.28.6",
|
"@tanstack/eslint-plugin-query": "^5.28.6",
|
||||||
"@types/carbon__colors": "^10.31.3",
|
"@types/carbon__colors": "^10.31.3",
|
||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
"@types/lodash.merge": "^4.6.7",
|
"@types/lodash.merge": "^4.6.7",
|
||||||
|
"@types/node": "^20.12.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.30.5",
|
"@typescript-eslint/eslint-plugin": "^5.30.5",
|
||||||
"@typescript-eslint/parser": "^5.62.0",
|
"@typescript-eslint/parser": "^5.62.0",
|
||||||
|
"@vitest/coverage-v8": "^1.5.0",
|
||||||
"cypress": "^13",
|
"cypress": "^13",
|
||||||
"cypress-file-upload": "^5.0.8",
|
"cypress-file-upload": "^5.0.8",
|
||||||
"cypress-slow-down": "^1.3.1",
|
"cypress-slow-down": "^1.3.1",
|
||||||
|
"cypress-vite": "^1.5.0",
|
||||||
"eslint": "^8.19.0",
|
"eslint": "^8.19.0",
|
||||||
"eslint_d": "^12.2.0",
|
"eslint_d": "^12.2.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
|
@ -119,8 +124,11 @@
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-sonarjs": "^0.15.0",
|
"eslint-plugin-sonarjs": "^0.15.0",
|
||||||
"eslint-plugin-unused-imports": "^2.0.0",
|
"eslint-plugin-unused-imports": "^2.0.0",
|
||||||
|
"inherits-browser": "^0.0.1",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"safe-regex": "^2.1.1",
|
"safe-regex": "^2.1.1",
|
||||||
"ts-migrate": "^0.1.30"
|
"tiny-svg": "^2.2.3",
|
||||||
|
"ts-migrate": "^0.1.30",
|
||||||
|
"vitest": "^1.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ export default function ContainerForExtensions() {
|
||||||
extensionUiSchemaFile.file_contents
|
extensionUiSchemaFile.file_contents
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
|
extensionUiSchema &&
|
||||||
extensionUiSchema.ux_elements &&
|
extensionUiSchema.ux_elements &&
|
||||||
!extensionUiSchema.disabled
|
!extensionUiSchema.disabled
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ type OwnProps = {
|
||||||
title?: string;
|
title?: string;
|
||||||
confirmButtonLabel?: string;
|
confirmButtonLabel?: string;
|
||||||
kind?: string;
|
kind?: string;
|
||||||
renderIcon?: boolean;
|
renderIcon?: Element;
|
||||||
iconDescription?: string | null;
|
iconDescription?: string | null;
|
||||||
hasIconOnly?: boolean;
|
hasIconOnly?: boolean;
|
||||||
classNameForModal?: string;
|
classNameForModal?: string;
|
||||||
|
@ -24,7 +24,7 @@ export default function ButtonWithConfirmation({
|
||||||
title = 'Are you sure?',
|
title = 'Are you sure?',
|
||||||
confirmButtonLabel = 'OK',
|
confirmButtonLabel = 'OK',
|
||||||
kind = 'danger',
|
kind = 'danger',
|
||||||
renderIcon = false,
|
renderIcon,
|
||||||
iconDescription = null,
|
iconDescription = null,
|
||||||
hasIconOnly = false,
|
hasIconOnly = false,
|
||||||
classNameForModal,
|
classNameForModal,
|
||||||
|
|
|
@ -4,14 +4,12 @@ type OwnProps = {
|
||||||
displayLocation: string;
|
displayLocation: string;
|
||||||
elementCallback: Function;
|
elementCallback: Function;
|
||||||
extensionUxElements?: UiSchemaUxElement[] | null;
|
extensionUxElements?: UiSchemaUxElement[] | null;
|
||||||
elementCallbackIfNotFound?: Function;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ExtensionUxElementMap({
|
export function ExtensionUxElementMap({
|
||||||
displayLocation,
|
displayLocation,
|
||||||
elementCallback,
|
elementCallback,
|
||||||
extensionUxElements,
|
extensionUxElements,
|
||||||
elementCallbackIfNotFound,
|
|
||||||
}: OwnProps) {
|
}: OwnProps) {
|
||||||
if (!extensionUxElements) {
|
if (!extensionUxElements) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -23,15 +21,11 @@ export function ExtensionUxElementMap({
|
||||||
return uxElement.display_location === displayLocation;
|
return uxElement.display_location === displayLocation;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const elementMap = elementsForDisplayLocation.map(
|
return elementsForDisplayLocation.map(
|
||||||
(uxElement: UiSchemaUxElement, index: number) => {
|
(uxElement: UiSchemaUxElement, index: number) => {
|
||||||
return elementCallback(uxElement, index);
|
return elementCallback(uxElement, index);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (elementMap.length === 0 && elementCallbackIfNotFound) {
|
|
||||||
return elementCallbackIfNotFound();
|
|
||||||
}
|
|
||||||
return elementMap;
|
|
||||||
};
|
};
|
||||||
return mainElement();
|
return mainElement();
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ export default function Filters({
|
||||||
elements.push(
|
elements.push(
|
||||||
<Button
|
<Button
|
||||||
onClick={copyReportLink}
|
onClick={copyReportLink}
|
||||||
kind=""
|
kind="secondary"
|
||||||
renderIcon={LinkIcon}
|
renderIcon={LinkIcon}
|
||||||
iconDescription="Copy shareable link"
|
iconDescription="Copy shareable link"
|
||||||
hasIconOnly
|
hasIconOnly
|
||||||
|
|
|
@ -101,7 +101,11 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
|
|
||||||
const extensionUserProfileElement = (uxElement: UiSchemaUxElement) => {
|
const extensionUserProfileElement = (uxElement: UiSchemaUxElement) => {
|
||||||
const navItemPage = `/extensions${uxElement.page}`;
|
const navItemPage = `/extensions${uxElement.page}`;
|
||||||
return <Link to={navItemPage}>{uxElement.label}</Link>;
|
return (
|
||||||
|
<Link key={navItemPage} to={navItemPage}>
|
||||||
|
{uxElement.label}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const profileToggletip = () => {
|
const profileToggletip = () => {
|
||||||
|
@ -163,6 +167,7 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
<HeaderGlobalAction
|
<HeaderGlobalAction
|
||||||
title={`The current SpiffWorkflow environment is: ${SPIFF_ENVIRONMENT}`}
|
title={`The current SpiffWorkflow environment is: ${SPIFF_ENVIRONMENT}`}
|
||||||
className="spiff-environment-header-text unclickable-text"
|
className="spiff-environment-header-text unclickable-text"
|
||||||
|
aria-label="our-aria-label"
|
||||||
>
|
>
|
||||||
{SPIFF_ENVIRONMENT}
|
{SPIFF_ENVIRONMENT}
|
||||||
</HeaderGlobalAction>
|
</HeaderGlobalAction>
|
||||||
|
@ -195,10 +200,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
return (
|
return (
|
||||||
<SpiffTooltip title="Manage Secrets and Authentication information for Service Tasks">
|
<SpiffTooltip title="Manage Secrets and Authentication information for Service Tasks">
|
||||||
<HeaderMenuItem
|
<HeaderMenuItem
|
||||||
element={Link}
|
as={Link}
|
||||||
to="/configuration"
|
to="/configuration"
|
||||||
onClick={closeSideNavMenuIfExpanded}
|
onClick={closeSideNavMenuIfExpanded}
|
||||||
isCurrentPage={isActivePage('/configuration')}
|
isActive={isActivePage('/configuration')}
|
||||||
>
|
>
|
||||||
Configuration
|
Configuration
|
||||||
</HeaderMenuItem>
|
</HeaderMenuItem>
|
||||||
|
@ -221,11 +226,11 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
setActiveKey(navItemPage);
|
setActiveKey(navItemPage);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<SpiffTooltip title={uxElement?.tooltip}>
|
<SpiffTooltip key={navItemPage} title={uxElement?.tooltip}>
|
||||||
<HeaderMenuItem
|
<HeaderMenuItem
|
||||||
element={Link}
|
as={Link}
|
||||||
to={navItemPage}
|
to={navItemPage}
|
||||||
isCurrentPage={isActivePage(navItemPage)}
|
isActive={isActivePage(navItemPage)}
|
||||||
data-qa={`extension-${slugifyString(
|
data-qa={`extension-${slugifyString(
|
||||||
uxElement.label || uxElement.page
|
uxElement.label || uxElement.page
|
||||||
)}`}
|
)}`}
|
||||||
|
@ -244,10 +249,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
<>
|
<>
|
||||||
<SpiffTooltip title="View and start Process Instances">
|
<SpiffTooltip title="View and start Process Instances">
|
||||||
<HeaderMenuItem<LinkProps>
|
<HeaderMenuItem<LinkProps>
|
||||||
element={Link}
|
as={Link}
|
||||||
to="/"
|
to="/"
|
||||||
onClick={closeSideNavMenuIfExpanded}
|
onClick={closeSideNavMenuIfExpanded}
|
||||||
isCurrentPage={isActivePage('/')}
|
isActive={isActivePage('/')}
|
||||||
>
|
>
|
||||||
<div>Home</div>
|
<div>Home</div>
|
||||||
</HeaderMenuItem>
|
</HeaderMenuItem>
|
||||||
|
@ -256,10 +261,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
<Can I="GET" a={targetUris.processGroupListPath} ability={ability}>
|
<Can I="GET" a={targetUris.processGroupListPath} ability={ability}>
|
||||||
<SpiffTooltip title="Find and organize Process Groups and Process Models">
|
<SpiffTooltip title="Find and organize Process Groups and Process Models">
|
||||||
<HeaderMenuItem
|
<HeaderMenuItem
|
||||||
element={Link}
|
as={Link}
|
||||||
to={processGroupPath}
|
to={processGroupPath}
|
||||||
onClick={closeSideNavMenuIfExpanded}
|
onClick={closeSideNavMenuIfExpanded}
|
||||||
isCurrentPage={isActivePage(processGroupPath)}
|
isActive={isActivePage(processGroupPath)}
|
||||||
data-qa="header-nav-processes"
|
data-qa="header-nav-processes"
|
||||||
>
|
>
|
||||||
Processes
|
Processes
|
||||||
|
@ -273,10 +278,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
>
|
>
|
||||||
<SpiffTooltip title="List of active and completed Process Instances">
|
<SpiffTooltip title="List of active and completed Process Instances">
|
||||||
<HeaderMenuItem
|
<HeaderMenuItem
|
||||||
element={Link}
|
as={Link}
|
||||||
to="/process-instances"
|
to="/process-instances"
|
||||||
onClick={closeSideNavMenuIfExpanded}
|
onClick={closeSideNavMenuIfExpanded}
|
||||||
isCurrentPage={isActivePage('/process-instances')}
|
isActive={isActivePage('/process-instances')}
|
||||||
>
|
>
|
||||||
Process Instances
|
Process Instances
|
||||||
</HeaderMenuItem>
|
</HeaderMenuItem>
|
||||||
|
@ -285,10 +290,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
<Can I="GET" a={targetUris.messageInstanceListPath} ability={ability}>
|
<Can I="GET" a={targetUris.messageInstanceListPath} ability={ability}>
|
||||||
<SpiffTooltip title="Browse messages being sent and received">
|
<SpiffTooltip title="Browse messages being sent and received">
|
||||||
<HeaderMenuItem
|
<HeaderMenuItem
|
||||||
element={Link}
|
as={Link}
|
||||||
to="/messages"
|
to="/messages"
|
||||||
onClick={closeSideNavMenuIfExpanded}
|
onClick={closeSideNavMenuIfExpanded}
|
||||||
isCurrentPage={isActivePage('/messages')}
|
isActive={isActivePage('/messages')}
|
||||||
>
|
>
|
||||||
Messages
|
Messages
|
||||||
</HeaderMenuItem>
|
</HeaderMenuItem>
|
||||||
|
@ -297,10 +302,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
<Can I="GET" a={targetUris.dataStoreListPath} ability={ability}>
|
<Can I="GET" a={targetUris.dataStoreListPath} ability={ability}>
|
||||||
<SpiffTooltip title="Browse data that has been saved to Data Stores">
|
<SpiffTooltip title="Browse data that has been saved to Data Stores">
|
||||||
<HeaderMenuItem
|
<HeaderMenuItem
|
||||||
element={Link}
|
as={Link}
|
||||||
to="/data-stores"
|
to="/data-stores"
|
||||||
onClick={closeSideNavMenuIfExpanded}
|
onClick={closeSideNavMenuIfExpanded}
|
||||||
isCurrentPage={isActivePage('/data-stores')}
|
isActive={isActivePage('/data-stores')}
|
||||||
>
|
>
|
||||||
Data Stores
|
Data Stores
|
||||||
</HeaderMenuItem>
|
</HeaderMenuItem>
|
||||||
|
@ -322,12 +327,7 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
<HeaderContainer
|
<HeaderContainer
|
||||||
render={() => (
|
render={() => (
|
||||||
<Header aria-label="IBM Platform Name" className="cds--g100">
|
<Header aria-label="IBM Platform Name" className="cds--g100">
|
||||||
<HeaderName
|
<HeaderName as={Link} to="/" prefix="" data-qa="spiffworkflow-logo">
|
||||||
element={Link}
|
|
||||||
to="/"
|
|
||||||
prefix=""
|
|
||||||
data-qa="spiffworkflow-logo"
|
|
||||||
>
|
|
||||||
<img src={logo} className="app-logo" alt="logo" />
|
<img src={logo} className="app-logo" alt="logo" />
|
||||||
</HeaderName>
|
</HeaderName>
|
||||||
</Header>
|
</Header>
|
||||||
|
@ -360,7 +360,7 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
||||||
isActive={isSideNavExpanded}
|
isActive={isSideNavExpanded}
|
||||||
/>
|
/>
|
||||||
<HeaderName
|
<HeaderName
|
||||||
element={Link}
|
as={Link}
|
||||||
to="/"
|
to="/"
|
||||||
onClick={closeSideNavMenuIfExpanded}
|
onClick={closeSideNavMenuIfExpanded}
|
||||||
prefix=""
|
prefix=""
|
||||||
|
|
|
@ -77,7 +77,7 @@ export function Notification({
|
||||||
className="cds--inline-notification__close-button"
|
className="cds--inline-notification__close-button"
|
||||||
hasIconOnly
|
hasIconOnly
|
||||||
size="sm"
|
size="sm"
|
||||||
kind=""
|
kind="ghost"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -86,7 +86,7 @@ export function Notification({
|
||||||
data-qa="close-publish-notification"
|
data-qa="close-publish-notification"
|
||||||
className="cds--inline-notification__close-button"
|
className="cds--inline-notification__close-button"
|
||||||
size="sm"
|
size="sm"
|
||||||
kind=""
|
kind="ghost"
|
||||||
onClick={() => setShowMessage(!showMessage)}
|
onClick={() => setShowMessage(!showMessage)}
|
||||||
>
|
>
|
||||||
{showMessage ? 'Hide' : 'Details'}
|
{showMessage ? 'Hide' : 'Details'}
|
||||||
|
|
|
@ -65,6 +65,7 @@ export default function ProcessGroupListTiles({
|
||||||
return (
|
return (
|
||||||
<ClickableTile
|
<ClickableTile
|
||||||
id={`process-group-tile-${row.id}`}
|
id={`process-group-tile-${row.id}`}
|
||||||
|
key={`process-group-tile-${row.id}`}
|
||||||
className="tile-process-group"
|
className="tile-process-group"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigateToProcessGroup(
|
navigateToProcessGroup(
|
||||||
|
|
|
@ -99,12 +99,13 @@ export default function ProcessInstanceListSaveAsReport({
|
||||||
onRequestSubmit={addProcessInstanceReport}
|
onRequestSubmit={addProcessInstanceReport}
|
||||||
onRequestClose={handleSaveFormClose}
|
onRequestClose={handleSaveFormClose}
|
||||||
hasScrollingContent
|
hasScrollingContent
|
||||||
|
aria-label="save perspective"
|
||||||
>
|
>
|
||||||
<p className="data-table-description">{descriptionText}</p>
|
<p className="data-table-description">{descriptionText}</p>
|
||||||
{textInputComponent}
|
{textInputComponent}
|
||||||
</Modal>
|
</Modal>
|
||||||
<Button
|
<Button
|
||||||
kind=""
|
kind="tertiary"
|
||||||
className={buttonClassName}
|
className={buttonClassName}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIdentifier(processInstanceReportSelection?.identifier || '');
|
setIdentifier(processInstanceReportSelection?.identifier || '');
|
||||||
|
|
|
@ -386,7 +386,7 @@ export default function ProcessInstanceListTable({
|
||||||
return (
|
return (
|
||||||
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
|
||||||
<td
|
<td
|
||||||
key={processInstance.id}
|
key={`td-${columnAccessor}-${processInstance.id}`}
|
||||||
onClick={() => navigateToProcessInstance(processInstance)}
|
onClick={() => navigateToProcessInstance(processInstance)}
|
||||||
onKeyDown={() => navigateToProcessInstance(processInstance)}
|
onKeyDown={() => navigateToProcessInstance(processInstance)}
|
||||||
data-qa={`process-instance-show-link-${columnAccessor}`}
|
data-qa={`process-instance-show-link-${columnAccessor}`}
|
||||||
|
@ -512,7 +512,7 @@ export default function ProcessInstanceListTable({
|
||||||
if (hasAccessToCompleteTask && processInstance.task_id) {
|
if (hasAccessToCompleteTask && processInstance.task_id) {
|
||||||
goButtonElement = (
|
goButtonElement = (
|
||||||
<Button
|
<Button
|
||||||
kind="secondary"
|
kind="primary"
|
||||||
href={taskShowUrl}
|
href={taskShowUrl}
|
||||||
style={{ width: '60px' }}
|
style={{ width: '60px' }}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
|
@ -796,7 +796,7 @@ export default function ProcessInstanceListTableWithFilters({
|
||||||
return (
|
return (
|
||||||
<ProcessInstanceListSaveAsReport
|
<ProcessInstanceListSaveAsReport
|
||||||
onSuccess={onSaveReportSuccess}
|
onSuccess={onSaveReportSuccess}
|
||||||
buttonClassName="button-white-background narrow-button"
|
buttonClassName="narrow-button"
|
||||||
buttonText="Save"
|
buttonText="Save"
|
||||||
processInstanceReportSelection={processInstanceReportSelection}
|
processInstanceReportSelection={processInstanceReportSelection}
|
||||||
reportMetadata={reportMetadata}
|
reportMetadata={reportMetadata}
|
||||||
|
@ -1040,6 +1040,7 @@ export default function ProcessInstanceListTableWithFilters({
|
||||||
formElements.push(
|
formElements.push(
|
||||||
<Dropdown
|
<Dropdown
|
||||||
titleText="Display type"
|
titleText="Display type"
|
||||||
|
label="Display type"
|
||||||
id="report-column-display-type"
|
id="report-column-display-type"
|
||||||
items={[''].concat(Object.values(filterDisplayTypes))}
|
items={[''].concat(Object.values(filterDisplayTypes))}
|
||||||
selectedItem={
|
selectedItem={
|
||||||
|
@ -1064,6 +1065,7 @@ export default function ProcessInstanceListTableWithFilters({
|
||||||
formElements.push(
|
formElements.push(
|
||||||
<Dropdown
|
<Dropdown
|
||||||
titleText="Operator"
|
titleText="Operator"
|
||||||
|
label="Operator"
|
||||||
id="report-column-condition-operator"
|
id="report-column-condition-operator"
|
||||||
items={Object.keys(filterOperatorMappings)}
|
items={Object.keys(filterOperatorMappings)}
|
||||||
selectedItem={operator || null}
|
selectedItem={operator || null}
|
||||||
|
@ -1110,6 +1112,7 @@ export default function ProcessInstanceListTableWithFilters({
|
||||||
onRequestSubmit={handleUpdateReportColumn}
|
onRequestSubmit={handleUpdateReportColumn}
|
||||||
onRequestClose={handleColumnFormClose}
|
onRequestClose={handleColumnFormClose}
|
||||||
hasScrollingContent
|
hasScrollingContent
|
||||||
|
aria-label={modalHeading}
|
||||||
>
|
>
|
||||||
{formElements}
|
{formElements}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -1202,6 +1205,7 @@ export default function ProcessInstanceListTableWithFilters({
|
||||||
<Dropdown
|
<Dropdown
|
||||||
id="system-report-dropdown"
|
id="system-report-dropdown"
|
||||||
titleText="System report"
|
titleText="System report"
|
||||||
|
label="System report"
|
||||||
items={['', ...systemReportOptions]}
|
items={['', ...systemReportOptions]}
|
||||||
itemToString={(item: any) => titleizeString(item)}
|
itemToString={(item: any) => titleizeString(item)}
|
||||||
selectedItem={systemReport}
|
selectedItem={systemReport}
|
||||||
|
@ -1221,6 +1225,7 @@ export default function ProcessInstanceListTableWithFilters({
|
||||||
<Dropdown
|
<Dropdown
|
||||||
id="user-group-dropdown"
|
id="user-group-dropdown"
|
||||||
titleText="Assigned user group"
|
titleText="Assigned user group"
|
||||||
|
label="Assigned user group"
|
||||||
items={['', ...userGroups]}
|
items={['', ...userGroups]}
|
||||||
itemToString={(item: any) => item}
|
itemToString={(item: any) => item}
|
||||||
selectedItem={selectedUserGroup}
|
selectedItem={selectedUserGroup}
|
||||||
|
@ -1282,6 +1287,7 @@ export default function ProcessInstanceListTableWithFilters({
|
||||||
onRequestSubmit={handleAdvancedOptionsClose}
|
onRequestSubmit={handleAdvancedOptionsClose}
|
||||||
onRequestClose={handleAdvancedOptionsClose}
|
onRequestClose={handleAdvancedOptionsClose}
|
||||||
hasScrollingContent
|
hasScrollingContent
|
||||||
|
aria-label="advanced filter options"
|
||||||
size="lg"
|
size="lg"
|
||||||
>
|
>
|
||||||
{formElements}
|
{formElements}
|
||||||
|
@ -1457,8 +1463,8 @@ export default function ProcessInstanceListTableWithFilters({
|
||||||
<Column sm={4} md={4} lg={8}>
|
<Column sm={4} md={4} lg={8}>
|
||||||
<ButtonSet>
|
<ButtonSet>
|
||||||
<Button
|
<Button
|
||||||
kind=""
|
kind="tertiary"
|
||||||
className="button-white-background narrow-button"
|
className="narrow-button"
|
||||||
onClick={clearFilters}
|
onClick={clearFilters}
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
|
|
|
@ -499,16 +499,16 @@ export default function ProcessInstanceLogList({
|
||||||
<Column sm={4} md={4} lg={8}>
|
<Column sm={4} md={4} lg={8}>
|
||||||
<ButtonSet>
|
<ButtonSet>
|
||||||
<Button
|
<Button
|
||||||
kind=""
|
kind="tertiary"
|
||||||
className="button-white-background narrow-button"
|
className="narrow-button"
|
||||||
onClick={resetFiltersAndRun}
|
onClick={resetFiltersAndRun}
|
||||||
>
|
>
|
||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
{shouldDisplayClearButton && (
|
{shouldDisplayClearButton && (
|
||||||
<Button
|
<Button
|
||||||
kind=""
|
kind="tertiary"
|
||||||
className="button-white-background narrow-button"
|
className="narrow-button"
|
||||||
onClick={clearFilters}
|
onClick={clearFilters}
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
|
|
|
@ -333,8 +333,7 @@ export default function ProcessModelForm({
|
||||||
<Button
|
<Button
|
||||||
data-qa="add-notification-address-button"
|
data-qa="add-notification-address-button"
|
||||||
renderIcon={AddAlt}
|
renderIcon={AddAlt}
|
||||||
className="button-white-background"
|
kind="tertiary"
|
||||||
kind=""
|
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addBlankNotificationAddress();
|
addBlankNotificationAddress();
|
||||||
|
@ -365,8 +364,7 @@ export default function ProcessModelForm({
|
||||||
<Button
|
<Button
|
||||||
data-qa="add-metadata-extraction-path-button"
|
data-qa="add-metadata-extraction-path-button"
|
||||||
renderIcon={AddAlt}
|
renderIcon={AddAlt}
|
||||||
className="button-white-background"
|
kind="tertiary"
|
||||||
kind=""
|
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addBlankMetadataExtractionPath();
|
addBlankMetadataExtractionPath();
|
||||||
|
@ -383,7 +381,7 @@ export default function ProcessModelForm({
|
||||||
|
|
||||||
const formButtons = () => {
|
const formButtons = () => {
|
||||||
return (
|
return (
|
||||||
<Button kind="secondary" type="submit">
|
<Button kind="primary" type="submit">
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
|
@ -155,18 +155,13 @@ export default function ReactDiagramEditor({
|
||||||
if (diagramType === 'dmn') {
|
if (diagramType === 'dmn') {
|
||||||
modeler = (diagramModelerState as any).getActiveViewer();
|
modeler = (diagramModelerState as any).getActiveViewer();
|
||||||
}
|
}
|
||||||
try {
|
if (modeler) {
|
||||||
if (amount === 0) {
|
if (amount === 0) {
|
||||||
const canvas = modeler.get('canvas');
|
const canvas = modeler.get('canvas');
|
||||||
canvas.zoom(FitViewport, 'auto');
|
canvas.zoom(FitViewport, 'auto');
|
||||||
} else {
|
} else {
|
||||||
modeler.get('zoomScroll').stepZoom(amount);
|
modeler.get('zoomScroll').stepZoom(amount);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
console.error(
|
|
||||||
'zoom failed, certain modes in DMN do not support zooming.',
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -595,7 +590,7 @@ export default function ReactDiagramEditor({
|
||||||
if (diagramType === 'dmn') {
|
if (diagramType === 'dmn') {
|
||||||
newDiagramFileName = 'new_dmn_diagram.dmn';
|
newDiagramFileName = 'new_dmn_diagram.dmn';
|
||||||
}
|
}
|
||||||
fetchDiagramFromURL(`${process.env.PUBLIC_URL}/${newDiagramFileName}`);
|
fetchDiagramFromURL(`/${newDiagramFileName}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,53 +8,77 @@ import {
|
||||||
Button,
|
Button,
|
||||||
} from '@carbon/react';
|
} from '@carbon/react';
|
||||||
import { JsonSchemaExample } from '../../interfaces';
|
import { JsonSchemaExample } from '../../interfaces';
|
||||||
|
import textSchema from '../../resources/json_schema_examples/text-schema.json';
|
||||||
|
import textUiSchema from '../../resources/json_schema_examples/text-uischema.json';
|
||||||
|
|
||||||
|
import textareaSchema from '../../resources/json_schema_examples/textarea-schema.json';
|
||||||
|
import textareaUiSchema from '../../resources/json_schema_examples/textarea-uischema.json';
|
||||||
|
|
||||||
|
import dateSchema from '../../resources/json_schema_examples/date-schema.json';
|
||||||
|
import dateUiSchema from '../../resources/json_schema_examples/date-uischema.json';
|
||||||
|
|
||||||
|
import choiceSchema from '../../resources/json_schema_examples/multiple-choice-schema.json';
|
||||||
|
import choiceUiSchema from '../../resources/json_schema_examples/multiple-choice-uischema.json';
|
||||||
|
|
||||||
|
import passwordSchema from '../../resources/json_schema_examples/password-schema.json';
|
||||||
|
import passwordUiSchema from '../../resources/json_schema_examples/password-uischema.json';
|
||||||
|
import typeaheadSchema from '../../resources/json_schema_examples/typeahead-schema.json';
|
||||||
|
import typeaheadUiSchema from '../../resources/json_schema_examples/typeahead-uischema.json';
|
||||||
|
|
||||||
|
import checkboxSchema from '../../resources/json_schema_examples/checkbox-schema.json';
|
||||||
|
import dropdownSchema from '../../resources/json_schema_examples/dropdown-schema.json';
|
||||||
|
import dropdownData from '../../resources/json_schema_examples/dropdown-exampledata.json';
|
||||||
|
import nestedSchema from '../../resources/json_schema_examples/nested-schema.json';
|
||||||
|
|
||||||
const examples: JsonSchemaExample[] = [];
|
const examples: JsonSchemaExample[] = [];
|
||||||
examples.push({
|
|
||||||
schema: require('../../resources/json_schema_examples/text-schema.json'), // eslint-disable-line global-require
|
examples.push(
|
||||||
ui: require('../../resources/json_schema_examples/text-uischema.json'), // eslint-disable-line global-require
|
{
|
||||||
data: {},
|
schema: textSchema,
|
||||||
});
|
ui: textUiSchema,
|
||||||
examples.push({
|
data: {},
|
||||||
schema: require('../../resources/json_schema_examples/textarea-schema.json'), // eslint-disable-line global-require
|
},
|
||||||
ui: require('../../resources/json_schema_examples/textarea-uischema.json'), // eslint-disable-line global-require
|
{
|
||||||
data: {},
|
schema: textareaSchema,
|
||||||
});
|
ui: textareaUiSchema,
|
||||||
examples.push({
|
data: {},
|
||||||
schema: require('../../resources/json_schema_examples/checkbox-schema.json'), // eslint-disable-line global-require
|
},
|
||||||
ui: {},
|
{
|
||||||
data: {},
|
schema: checkboxSchema,
|
||||||
});
|
ui: {},
|
||||||
examples.push({
|
data: {},
|
||||||
schema: require('../../resources/json_schema_examples/date-schema.json'), // eslint-disable-line global-require
|
},
|
||||||
ui: require('../../resources/json_schema_examples/date-uischema.json'), // eslint-disable-line global-require
|
{
|
||||||
data: {},
|
schema: dateSchema,
|
||||||
});
|
ui: dateUiSchema,
|
||||||
examples.push({
|
data: {},
|
||||||
schema: require('../../resources/json_schema_examples/dropdown-schema.json'), // eslint-disable-line global-require
|
},
|
||||||
ui: {},
|
{
|
||||||
data: require('../../resources/json_schema_examples/dropdown-exampledata.json'), // eslint-disable-line global-require
|
schema: dropdownSchema,
|
||||||
});
|
ui: {},
|
||||||
examples.push({
|
data: dropdownData,
|
||||||
schema: require('../../resources/json_schema_examples/multiple-choice-schema.json'), // eslint-disable-line global-require
|
},
|
||||||
ui: require('../../resources/json_schema_examples/multiple-choice-uischema.json'), // eslint-disable-line global-require
|
{
|
||||||
data: {},
|
schema: choiceSchema,
|
||||||
});
|
ui: choiceUiSchema,
|
||||||
examples.push({
|
data: {},
|
||||||
schema: require('../../resources/json_schema_examples/password-schema.json'), // eslint-disable-line global-require
|
},
|
||||||
ui: require('../../resources/json_schema_examples/password-uischema.json'), // eslint-disable-line global-require
|
{
|
||||||
data: {},
|
schema: passwordSchema,
|
||||||
});
|
ui: passwordUiSchema,
|
||||||
examples.push({
|
data: {},
|
||||||
schema: require('../../resources/json_schema_examples/nested-schema.json'), // eslint-disable-line global-require
|
},
|
||||||
ui: {},
|
{
|
||||||
data: {},
|
schema: nestedSchema,
|
||||||
});
|
ui: {},
|
||||||
examples.push({
|
data: {},
|
||||||
schema: require('../../resources/json_schema_examples/typeahead-schema.json'), // eslint-disable-line global-require
|
},
|
||||||
ui: require('../../resources/json_schema_examples/typeahead-uischema.json'), // eslint-disable-line global-require
|
{
|
||||||
data: {},
|
schema: typeaheadSchema,
|
||||||
});
|
ui: typeaheadUiSchema,
|
||||||
|
data: {},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
onSelect: Function;
|
onSelect: Function;
|
||||||
|
@ -72,11 +96,7 @@ export default function ExamplesTable({ onSelect }: OwnProps) {
|
||||||
<td>{example.schema.title}</td>
|
<td>{example.schema.title}</td>
|
||||||
<td>{example.schema.description}</td>
|
<td>{example.schema.description}</td>
|
||||||
<td>
|
<td>
|
||||||
<Button
|
<Button kind="primary" size="sm" onClick={() => selectExample(index)}>
|
||||||
kind="secondary"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => selectExample(index)}
|
|
||||||
>
|
|
||||||
Load
|
Load
|
||||||
</Button>
|
</Button>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { useEffect, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { Tabs, TabList, Tab } from '@carbon/react';
|
import { Tabs, TabList, Tab } from '@carbon/react';
|
||||||
import { SpiffTab } from '../interfaces';
|
import { SpiffTab } from '../interfaces';
|
||||||
import SpiffTooltip from './SpiffTooltip';
|
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
tabs: SpiffTab[];
|
tabs: SpiffTab[];
|
||||||
|
@ -10,7 +9,7 @@ type OwnProps = {
|
||||||
|
|
||||||
export default function SpiffTabs({ tabs }: OwnProps) {
|
export default function SpiffTabs({ tabs }: OwnProps) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [selectedTabIndex, setSelectedTabIndex] = useState<number>(0);
|
const [selectedTabIndex, setSelectedTabIndex] = useState<number | null>(null);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -25,20 +24,19 @@ export default function SpiffTabs({ tabs }: OwnProps) {
|
||||||
|
|
||||||
const tabComponents = tabs.map((spiffTab: SpiffTab) => {
|
const tabComponents = tabs.map((spiffTab: SpiffTab) => {
|
||||||
return (
|
return (
|
||||||
<SpiffTooltip title={spiffTab?.tooltip}>
|
<Tab onClick={() => navigate(spiffTab.path)}>{spiffTab.display_name}</Tab>
|
||||||
<Tab onClick={() => navigate(spiffTab.path)}>
|
|
||||||
{spiffTab.display_name}
|
|
||||||
</Tab>
|
|
||||||
</SpiffTooltip>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
if (selectedTabIndex !== null && tabComponents.length > selectedTabIndex) {
|
||||||
<>
|
return (
|
||||||
<Tabs selectedIndex={selectedTabIndex}>
|
<>
|
||||||
<TabList aria-label="List of tabs">{tabComponents}</TabList>
|
<Tabs selectedIndex={selectedTabIndex}>
|
||||||
</Tabs>
|
<TabList aria-label="List of tabs">{tabComponents}</TabList>
|
||||||
<br />
|
</Tabs>
|
||||||
</>
|
<br />
|
||||||
);
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
declare const window: Window & typeof globalThis;
|
||||||
|
|
||||||
const { port, hostname } = window.location;
|
const { port, hostname } = window.location;
|
||||||
let protocol = 'https';
|
let protocol = 'https';
|
||||||
|
|
||||||
|
@ -56,23 +58,16 @@ if (!backendBaseUrl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
backendBaseUrl = `${protocol}://${hostAndPortAndPathPrefix}/v1.0`;
|
backendBaseUrl = `${protocol}://${hostAndPortAndPathPrefix}/v1.0`;
|
||||||
|
|
||||||
// this can only ever work locally since this is a static site.
|
|
||||||
// use spiffworkflowFrontendJsenv if you want to inject env vars
|
|
||||||
// that can be read by the static site.
|
|
||||||
if (process.env.REACT_APP_BACKEND_BASE_URL) {
|
|
||||||
backendBaseUrl = process.env.REACT_APP_BACKEND_BASE_URL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!backendBaseUrl.endsWith('/v1.0')) {
|
if (!backendBaseUrl.endsWith('/v1.0')) {
|
||||||
backendBaseUrl += '/v1.0';
|
backendBaseUrl += '/v1.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BACKEND_BASE_URL = backendBaseUrl;
|
const BACKEND_BASE_URL = backendBaseUrl;
|
||||||
export const DOCUMENTATION_URL = documentationUrl;
|
const DOCUMENTATION_URL = documentationUrl;
|
||||||
|
|
||||||
export const PROCESS_STATUSES = [
|
const PROCESS_STATUSES = [
|
||||||
'complete',
|
'complete',
|
||||||
'error',
|
'error',
|
||||||
'not_started',
|
'not_started',
|
||||||
|
@ -122,11 +117,23 @@ const carbonDateFormat = generalDateFormat
|
||||||
.replace(/\bMMM\b/, 'M')
|
.replace(/\bMMM\b/, 'M')
|
||||||
.replace(/\bMMMM\b/, 'F')
|
.replace(/\bMMMM\b/, 'F')
|
||||||
.replace(/\bdd\b/, 'd');
|
.replace(/\bdd\b/, 'd');
|
||||||
export const DATE_TIME_FORMAT = `${generalDateFormat} HH:mm:ss`;
|
const DATE_TIME_FORMAT = `${generalDateFormat} HH:mm:ss`;
|
||||||
export const TIME_FORMAT_HOURS_MINUTES = 'HH:mm';
|
const TIME_FORMAT_HOURS_MINUTES = 'HH:mm';
|
||||||
export const DATE_FORMAT = generalDateFormat;
|
const DATE_FORMAT = generalDateFormat;
|
||||||
export const DATE_FORMAT_CARBON = carbonDateFormat;
|
const DATE_FORMAT_CARBON = carbonDateFormat;
|
||||||
export const DATE_FORMAT_FOR_DISPLAY = generalDateFormat.toLowerCase();
|
const DATE_FORMAT_FOR_DISPLAY = generalDateFormat.toLowerCase();
|
||||||
export const DATE_RANGE_DELIMITER = ':::';
|
const DATE_RANGE_DELIMITER = ':::';
|
||||||
|
|
||||||
export const SPIFF_ENVIRONMENT = spiffEnvironment;
|
const SPIFF_ENVIRONMENT = spiffEnvironment;
|
||||||
|
export {
|
||||||
|
DATE_TIME_FORMAT,
|
||||||
|
TIME_FORMAT_HOURS_MINUTES,
|
||||||
|
DATE_FORMAT,
|
||||||
|
DATE_FORMAT_CARBON,
|
||||||
|
DATE_FORMAT_FOR_DISPLAY,
|
||||||
|
DATE_RANGE_DELIMITER,
|
||||||
|
BACKEND_BASE_URL,
|
||||||
|
DOCUMENTATION_URL,
|
||||||
|
PROCESS_STATUSES,
|
||||||
|
SPIFF_ENVIRONMENT,
|
||||||
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ const appVersionInfo = () => {
|
||||||
versionInfoFromHtmlMetaTag.getAttribute('content');
|
versionInfoFromHtmlMetaTag.getAttribute('content');
|
||||||
if (
|
if (
|
||||||
versionInfoContentString &&
|
versionInfoContentString &&
|
||||||
versionInfoContentString !== '%REACT_APP_VERSION_INFO%'
|
versionInfoContentString !== '%VITE_VERSION_INFO%'
|
||||||
) {
|
) {
|
||||||
versionInfo = JSON.parse(versionInfoContentString);
|
versionInfo = JSON.parse(versionInfoContentString);
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,17 +144,69 @@ h3 {
|
||||||
* so they match our normal scheme better
|
* so they match our normal scheme better
|
||||||
*/
|
*/
|
||||||
.cds--btn--tertiary:focus {
|
.cds--btn--tertiary:focus {
|
||||||
color: white;
|
color: #161616;
|
||||||
|
border-color: #161616;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
.cds--btn--tertiary:hover {
|
||||||
|
color: #161616;
|
||||||
|
border-color: #161616;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
.cds--btn--tertiary:visited:hover {
|
||||||
|
color: #161616;
|
||||||
|
border-color: #161616;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cds--btn--secondary {
|
||||||
|
color: #161616;
|
||||||
|
border-color: #efefef;
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
.cds--btn--secondary:visited {
|
||||||
|
color: #161616;
|
||||||
|
border-color: #efefef;
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
.cds--btn--secondary:focus {
|
||||||
|
color: #161616;
|
||||||
|
border-color: #efefef;
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
.cds--btn--secondary:hover {
|
||||||
|
color: #161616;
|
||||||
|
border-color: #dddddd;
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
.cds--btn--secondary:visited:hover {
|
||||||
|
color: #161616;
|
||||||
|
border-color: #dddddd;
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cds--modal-footer .cds--btn--secondary {
|
||||||
|
color: #ffffff;
|
||||||
border-color: #393939;
|
border-color: #393939;
|
||||||
background-color: #393939;
|
background-color: #393939;
|
||||||
}
|
}
|
||||||
.cds--btn--tertiary:hover {
|
.cds--modal-footer .cds--btn--secondary:visited {
|
||||||
color: white;
|
color: #ffffff;
|
||||||
|
border-color: #393939;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
.cds--modal-footer .cds--btn--secondary:focus {
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: #393939;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
.cds--modal-footer .cds--btn--secondary:hover {
|
||||||
|
color: #ffffff;
|
||||||
border-color: #474747;
|
border-color: #474747;
|
||||||
background-color: #474747;
|
background-color: #474747;
|
||||||
}
|
}
|
||||||
.cds--btn--tertiary:visited:hover {
|
.cds--modal-footer .cds--btn--secondary:visited:hover {
|
||||||
color: white;
|
color: #ffffff;
|
||||||
border-color: #474747;
|
border-color: #474747;
|
||||||
background-color: #474747;
|
background-color: #474747;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
// )
|
// )
|
||||||
// );
|
// );
|
||||||
|
|
||||||
@use '@carbon/react';
|
@use '@carbon/react' with (
|
||||||
|
$font-path: '@ibm/plex'
|
||||||
|
);
|
||||||
@use '@carbon/styles';
|
@use '@carbon/styles';
|
||||||
// @include grid.flex-grid();
|
// @include grid.flex-grid();
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,7 @@ export default function BaseInputTemplate<
|
||||||
<TextInput
|
<TextInput
|
||||||
id={id}
|
id={id}
|
||||||
className="text-input"
|
className="text-input"
|
||||||
|
labelText=""
|
||||||
helperText={commonAttributes.helperText}
|
helperText={commonAttributes.helperText}
|
||||||
invalid={commonAttributes.invalid}
|
invalid={commonAttributes.invalid}
|
||||||
invalidText={commonAttributes.errorMessageForField}
|
invalidText={commonAttributes.errorMessageForField}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
// @ts-ignore
|
|
||||||
import { Table } from '@carbon/react';
|
import { Table } from '@carbon/react';
|
||||||
import { AuthenticationItem } from '../interfaces';
|
import { AuthenticationItem } from '../interfaces';
|
||||||
import HttpService from '../services/HttpService';
|
import HttpService from '../services/HttpService';
|
||||||
|
@ -92,10 +91,10 @@ export default function AuthenticationList() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{buildTable()}
|
{buildTable()}
|
||||||
{AuthenticationConfiguration()}
|
<AuthenticationConfiguration />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <main />;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ export default function BaseRoutes({ extensionUxElements }: OwnProps) {
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
path={uxElement.page}
|
path={uxElement.page}
|
||||||
|
key={uxElement.page}
|
||||||
element={<Extension pageIdentifier={uxElement.page} />}
|
element={<Extension pageIdentifier={uxElement.page} />}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -74,7 +74,7 @@ export default function ProcessGroupList() {
|
||||||
<ProcessBreadcrumb hotCrumbs={[['Process Groups']]} />
|
<ProcessBreadcrumb hotCrumbs={[['Process Groups']]} />
|
||||||
<Stack orientation="horizontal" gap={3}>
|
<Stack orientation="horizontal" gap={3}>
|
||||||
<Can I="POST" a={targetUris.processGroupListPath} ability={ability}>
|
<Can I="POST" a={targetUris.processGroupListPath} ability={ability}>
|
||||||
<Button kind="secondary" href="/process-groups/new">
|
<Button kind="primary" href="/process-groups/new">
|
||||||
Add a process group
|
Add a process group
|
||||||
</Button>
|
</Button>
|
||||||
</Can>
|
</Can>
|
||||||
|
|
|
@ -915,7 +915,7 @@ export default function ProcessModelEditDiagram() {
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
className="m-top-10"
|
className="m-top-10"
|
||||||
kind="secondary"
|
kind="primary"
|
||||||
onClick={() => handleProcessScriptAssist()}
|
onClick={() => handleProcessScriptAssist()}
|
||||||
disabled={scriptAssistLoading}
|
disabled={scriptAssistLoading}
|
||||||
>
|
>
|
||||||
|
|
|
@ -64,7 +64,7 @@ export default function ProcessModelNewExperimental() {
|
||||||
setProcessModelDescriptiveText(event.target.value)
|
setProcessModelDescriptiveText(event.target.value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Button kind="secondary" type="submit">
|
<Button kind="primary" type="submit">
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -339,7 +339,7 @@ export default function ProcessModelShow() {
|
||||||
let actionsTableCell = null;
|
let actionsTableCell = null;
|
||||||
if (processModelFile.name.match(/\.(dmn|bpmn|json|md)$/)) {
|
if (processModelFile.name.match(/\.(dmn|bpmn|json|md)$/)) {
|
||||||
actionsTableCell = (
|
actionsTableCell = (
|
||||||
<TableCell key={`${processModelFile.name}-cell`} align="right">
|
<TableCell key={`${processModelFile.name}-action`} align="right">
|
||||||
{renderButtonElements(processModelFile, isPrimaryBpmnFile)}
|
{renderButtonElements(processModelFile, isPrimaryBpmnFile)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
);
|
);
|
||||||
|
|
|
@ -71,11 +71,7 @@ export default function SecretNew() {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ButtonSet>
|
<ButtonSet>
|
||||||
<Button
|
<Button kind="tertiary" onClick={navigateToSecrets}>
|
||||||
kind=""
|
|
||||||
className="button-white-background"
|
|
||||||
onClick={navigateToSecrets}
|
|
||||||
>
|
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button kind="primary" type="submit">
|
<Button kind="primary" type="submit">
|
||||||
|
|
|
@ -159,6 +159,7 @@ export default function SecretShow() {
|
||||||
<TextInput
|
<TextInput
|
||||||
id="secret_value"
|
id="secret_value"
|
||||||
name="secret_value"
|
name="secret_value"
|
||||||
|
labelText="Secret value"
|
||||||
value={secret.value}
|
value={secret.value}
|
||||||
onChange={handleSecretValueChange}
|
onChange={handleSecretValueChange}
|
||||||
disabled={
|
disabled={
|
||||||
|
|
|
@ -360,7 +360,7 @@ export default function TaskShow() {
|
||||||
id="close-button"
|
id="close-button"
|
||||||
onClick={handleCloseButton}
|
onClick={handleCloseButton}
|
||||||
disabled={formButtonsDisabled}
|
disabled={formButtonsDisabled}
|
||||||
kind="secondary"
|
kind="primary"
|
||||||
title="Save data as draft and close the form."
|
title="Save data as draft and close the form."
|
||||||
>
|
>
|
||||||
Save and close
|
Save and close
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="vite/client" />
|
|
@ -0,0 +1 @@
|
||||||
|
import '@testing-library/jest-dom';
|
|
@ -3,11 +3,18 @@
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"module": "commonjs",
|
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "es2021",
|
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"types": ["vite/client", "node", "vitest/globals"],
|
||||||
|
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
|
||||||
|
"isolatedModules": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"]
|
"include": ["src", "test/vitest.setup.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import preact from '@preact/preset-vite';
|
||||||
|
import prefresh from '@prefresh/vite';
|
||||||
|
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
// import react from '@vitejs/plugin-react';
|
||||||
|
|
||||||
|
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
// depending on your application, base can also be "/"
|
||||||
|
base: '/',
|
||||||
|
plugins: [
|
||||||
|
// react(),
|
||||||
|
// seems to replace preact. hot module replacement doesn't work, so commented out. also causes errors when navigating with TabList:
|
||||||
|
// Cannot read properties of undefined (reading 'disabled')
|
||||||
|
// prefresh(),
|
||||||
|
// we need preact for bpmn-js-spiffworkflow. see https://forum.bpmn.io/t/custom-prop-for-service-tasks-typeerror-cannot-add-property-object-is-not-extensible/8487
|
||||||
|
preact(),
|
||||||
|
viteTsconfigPaths(),
|
||||||
|
],
|
||||||
|
// for prefresh, from https://github.com/preactjs/prefresh/issues/454#issuecomment-1456491801, not working
|
||||||
|
// optimizeDeps: {
|
||||||
|
// include: ['preact/hooks', 'preact/compat', 'preact']
|
||||||
|
// },
|
||||||
|
server: {
|
||||||
|
// this ensures that the browser DOES NOT open upon server start
|
||||||
|
open: false,
|
||||||
|
port: 7001,
|
||||||
|
},
|
||||||
|
preview: {
|
||||||
|
port: 7001,
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
inferno:
|
||||||
|
process.env.NODE_ENV !== 'production'
|
||||||
|
? 'inferno/dist/index.dev.esm.js'
|
||||||
|
: 'inferno/dist/index.esm.js',
|
||||||
|
},
|
||||||
|
preserveSymlinks: true,
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
include: ['./src/**/*.test.ts', './src/**/*.test.tsx'],
|
||||||
|
setupFiles: ['test/vitest.setup.ts'],
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue