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
|
||||
- spiffdemo
|
||||
- GSA-TTS-fix-path-routing-in-generated-openid-urls
|
||||
- use-vite-to-build
|
||||
|
||||
jobs:
|
||||
create_frontend_docker_image:
|
||||
|
|
|
@ -2,6 +2,7 @@ import json
|
|||
import time
|
||||
|
||||
import flask.wrappers
|
||||
import sqlalchemy
|
||||
from flask import g
|
||||
from flask import jsonify
|
||||
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:
|
||||
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:
|
||||
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.commit()
|
||||
|
||||
active_user.last_seen_in_seconds = round(time.time())
|
||||
db.session.add(active_user)
|
||||
db.session.commit()
|
||||
try:
|
||||
db.session.commit()
|
||||
except sqlalchemy.exc.IntegrityError:
|
||||
# duplicate entry. two processes are trying to create the same entry at the same time. it is fine to drop one request.
|
||||
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
|
||||
active_users = (
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
# production
|
||||
/build
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
|
|
@ -9,12 +9,12 @@ WORKDIR /app
|
|||
# procps for debugging
|
||||
# vim ftw
|
||||
RUN apt-get update \
|
||||
&& apt-get clean -y \
|
||||
&& apt-get install -y -q \
|
||||
curl \
|
||||
procps \
|
||||
vim-tiny \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& apt-get clean -y \
|
||||
&& apt-get install -y -q \
|
||||
curl \
|
||||
procps \
|
||||
vim-tiny \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# this matches total memory on spiffworkflow-demo
|
||||
ENV NODE_OPTIONS=--max_old_space_size=2048
|
||||
|
@ -44,19 +44,17 @@ RUN ./bin/build
|
|||
|
||||
######################## - FINAL
|
||||
|
||||
# Final image without setup dependencies.
|
||||
FROM base AS final
|
||||
# Use nginx as the base image
|
||||
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.
|
||||
ENV PORT0=7001
|
||||
# Copy the nginx configuration file
|
||||
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/node_modules.justserve /app/node_modules
|
||||
|
||||
RUN chown -R node:node /app
|
||||
|
||||
USER node
|
||||
CMD ["/app/bin/boot_server_in_docker"]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
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"
|
||||
}
|
||||
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
|
||||
react_configs=$(env | grep -E "^SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG_" || echo '')
|
||||
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
|
||||
>&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
|
||||
fi
|
||||
|
||||
if ! command -v sed >/dev/null ; then
|
||||
>&2 echo "ERROR: sed command not found. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
||||
if ! command -v sed >/dev/null; then
|
||||
echo >&2 "ERROR: sed command not found. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v perl >/dev/null ; then
|
||||
>&2 echo "ERROR: perl command not found. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
||||
if ! command -v perl >/dev/null; then
|
||||
echo >&2 "ERROR: perl command not found. Cannot use SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG values without it."
|
||||
exit 1
|
||||
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}")
|
||||
|
||||
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
|
||||
fi
|
||||
|
||||
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
|
||||
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
|
||||
>&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
|
||||
fi
|
||||
done
|
||||
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
|
||||
version_info=$(cat version_info.json)
|
||||
export REACT_APP_VERSION_INFO="$version_info"
|
||||
export VITE_VERSION_INFO="$version_info"
|
||||
fi
|
||||
|
||||
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 */
|
||||
const { defineConfig } = require('cypress');
|
||||
const { rm } = require('fs/promises');
|
||||
import { defineConfig } from 'cypress';
|
||||
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
|
||||
const useVideoCompression = !!process.env.CYPRESS_RECORD_KEY;
|
||||
|
@ -40,7 +41,6 @@ const cypressConfig = {
|
|||
baseUrl: spiffWorkflowFrontendUrl,
|
||||
setupNodeEvents(on, config) {
|
||||
deleteVideosOnSuccess(on);
|
||||
require('@cypress/grep/src/plugin')(config);
|
||||
return config;
|
||||
},
|
||||
},
|
||||
|
@ -56,4 +56,4 @@ if (!process.env.CYPRESS_RECORD_KEY) {
|
|||
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">
|
||||
<head>
|
||||
<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="theme-color" content="#000000" />
|
||||
<meta name="version-info" content='%REACT_APP_VERSION_INFO%' />
|
||||
<meta name="version-info" content='%VITE_VERSION_INFO%' />
|
||||
<meta
|
||||
name="description"
|
||||
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
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/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`.
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<title>SpiffWorkflow</title>
|
||||
<script>
|
||||
window.spiffworkflowFrontendJsenv = {};
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
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",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.24.3",
|
||||
"@babel/plugin-transform-react-jsx": "^7.18.6",
|
||||
|
@ -15,6 +16,7 @@
|
|||
"@microsoft/fetch-event-source": "^2.0.1",
|
||||
"@monaco-editor/react": "^4.4.5",
|
||||
"@mui/material": "^5.10.14",
|
||||
"@prefresh/vite": "^2.4.5",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@rjsf/core": "5.0.0-beta.20",
|
||||
"@rjsf/mui": "5.0.0-beta.20",
|
||||
|
@ -26,15 +28,15 @@
|
|||
"@testing-library/react": "^14.2.1",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.12.6",
|
||||
"@types/react": "^18.0.17",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@uiw/react-md-editor": "^3.20.2",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"axios": "^0.27.2",
|
||||
"bpmn-js": "^13.2.2",
|
||||
"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",
|
||||
"craco": "^0.0.3",
|
||||
"date-fns": "^3.6.0",
|
||||
|
@ -55,11 +57,12 @@
|
|||
"react-jsonschema-form": "^1.8.1",
|
||||
"react-router": "^6.22.2",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-scripts": "^5.0.1",
|
||||
"serve": "^14.0.0",
|
||||
"timepicker": "^1.13.18",
|
||||
"typescript": "^4.7.4",
|
||||
"use-debounce": "^10.0.0",
|
||||
"vite": "^5.2.8",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"web-vitals": "^3.5.2"
|
||||
},
|
||||
"overrides": {
|
||||
|
@ -68,12 +71,10 @@
|
|||
}
|
||||
},
|
||||
"scripts": {
|
||||
"start": "ESLINT_NO_DEV_ERRORS=true PORT=7001 craco start",
|
||||
"docker:start": "ESLINT_NO_DEV_ERRORS=true craco start",
|
||||
"build": "craco build",
|
||||
"test": "react-scripts test --coverage",
|
||||
"t": "npm test -- --watchAll=false",
|
||||
"eject": "craco eject",
|
||||
"start": "VITE_VERSION_INFO='{\"version\":\"local\"}' vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview",
|
||||
"test": "vitest run --coverage",
|
||||
"format": "prettier --write src/**/*.[tj]s{,x}",
|
||||
"lint": "./node_modules/.bin/eslint src",
|
||||
"lint:fix": "./node_modules/.bin/eslint --fix src"
|
||||
|
@ -98,15 +99,19 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@cypress/grep": "^3.1.0",
|
||||
"@preact/preset-vite": "^2.8.2",
|
||||
"@tanstack/eslint-plugin-query": "^5.28.6",
|
||||
"@types/carbon__colors": "^10.31.3",
|
||||
"@types/cookie": "^0.6.0",
|
||||
"@types/lodash.merge": "^4.6.7",
|
||||
"@types/node": "^20.12.7",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.5",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"@vitest/coverage-v8": "^1.5.0",
|
||||
"cypress": "^13",
|
||||
"cypress-file-upload": "^5.0.8",
|
||||
"cypress-slow-down": "^1.3.1",
|
||||
"cypress-vite": "^1.5.0",
|
||||
"eslint": "^8.19.0",
|
||||
"eslint_d": "^12.2.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
|
@ -119,8 +124,11 @@
|
|||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-sonarjs": "^0.15.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"inherits-browser": "^0.0.1",
|
||||
"prettier": "^2.7.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
|
||||
);
|
||||
if (
|
||||
extensionUiSchema &&
|
||||
extensionUiSchema.ux_elements &&
|
||||
!extensionUiSchema.disabled
|
||||
) {
|
||||
|
|
|
@ -10,7 +10,7 @@ type OwnProps = {
|
|||
title?: string;
|
||||
confirmButtonLabel?: string;
|
||||
kind?: string;
|
||||
renderIcon?: boolean;
|
||||
renderIcon?: Element;
|
||||
iconDescription?: string | null;
|
||||
hasIconOnly?: boolean;
|
||||
classNameForModal?: string;
|
||||
|
@ -24,7 +24,7 @@ export default function ButtonWithConfirmation({
|
|||
title = 'Are you sure?',
|
||||
confirmButtonLabel = 'OK',
|
||||
kind = 'danger',
|
||||
renderIcon = false,
|
||||
renderIcon,
|
||||
iconDescription = null,
|
||||
hasIconOnly = false,
|
||||
classNameForModal,
|
||||
|
|
|
@ -4,14 +4,12 @@ type OwnProps = {
|
|||
displayLocation: string;
|
||||
elementCallback: Function;
|
||||
extensionUxElements?: UiSchemaUxElement[] | null;
|
||||
elementCallbackIfNotFound?: Function;
|
||||
};
|
||||
|
||||
export function ExtensionUxElementMap({
|
||||
displayLocation,
|
||||
elementCallback,
|
||||
extensionUxElements,
|
||||
elementCallbackIfNotFound,
|
||||
}: OwnProps) {
|
||||
if (!extensionUxElements) {
|
||||
return null;
|
||||
|
@ -23,15 +21,11 @@ export function ExtensionUxElementMap({
|
|||
return uxElement.display_location === displayLocation;
|
||||
}
|
||||
);
|
||||
const elementMap = elementsForDisplayLocation.map(
|
||||
return elementsForDisplayLocation.map(
|
||||
(uxElement: UiSchemaUxElement, index: number) => {
|
||||
return elementCallback(uxElement, index);
|
||||
}
|
||||
);
|
||||
if (elementMap.length === 0 && elementCallbackIfNotFound) {
|
||||
return elementCallbackIfNotFound();
|
||||
}
|
||||
return elementMap;
|
||||
};
|
||||
return mainElement();
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export default function Filters({
|
|||
elements.push(
|
||||
<Button
|
||||
onClick={copyReportLink}
|
||||
kind=""
|
||||
kind="secondary"
|
||||
renderIcon={LinkIcon}
|
||||
iconDescription="Copy shareable link"
|
||||
hasIconOnly
|
||||
|
|
|
@ -101,7 +101,11 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
|
||||
const extensionUserProfileElement = (uxElement: UiSchemaUxElement) => {
|
||||
const navItemPage = `/extensions${uxElement.page}`;
|
||||
return <Link to={navItemPage}>{uxElement.label}</Link>;
|
||||
return (
|
||||
<Link key={navItemPage} to={navItemPage}>
|
||||
{uxElement.label}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const profileToggletip = () => {
|
||||
|
@ -163,6 +167,7 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
<HeaderGlobalAction
|
||||
title={`The current SpiffWorkflow environment is: ${SPIFF_ENVIRONMENT}`}
|
||||
className="spiff-environment-header-text unclickable-text"
|
||||
aria-label="our-aria-label"
|
||||
>
|
||||
{SPIFF_ENVIRONMENT}
|
||||
</HeaderGlobalAction>
|
||||
|
@ -195,10 +200,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
return (
|
||||
<SpiffTooltip title="Manage Secrets and Authentication information for Service Tasks">
|
||||
<HeaderMenuItem
|
||||
element={Link}
|
||||
as={Link}
|
||||
to="/configuration"
|
||||
onClick={closeSideNavMenuIfExpanded}
|
||||
isCurrentPage={isActivePage('/configuration')}
|
||||
isActive={isActivePage('/configuration')}
|
||||
>
|
||||
Configuration
|
||||
</HeaderMenuItem>
|
||||
|
@ -221,11 +226,11 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
setActiveKey(navItemPage);
|
||||
}
|
||||
return (
|
||||
<SpiffTooltip title={uxElement?.tooltip}>
|
||||
<SpiffTooltip key={navItemPage} title={uxElement?.tooltip}>
|
||||
<HeaderMenuItem
|
||||
element={Link}
|
||||
as={Link}
|
||||
to={navItemPage}
|
||||
isCurrentPage={isActivePage(navItemPage)}
|
||||
isActive={isActivePage(navItemPage)}
|
||||
data-qa={`extension-${slugifyString(
|
||||
uxElement.label || uxElement.page
|
||||
)}`}
|
||||
|
@ -244,10 +249,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
<>
|
||||
<SpiffTooltip title="View and start Process Instances">
|
||||
<HeaderMenuItem<LinkProps>
|
||||
element={Link}
|
||||
as={Link}
|
||||
to="/"
|
||||
onClick={closeSideNavMenuIfExpanded}
|
||||
isCurrentPage={isActivePage('/')}
|
||||
isActive={isActivePage('/')}
|
||||
>
|
||||
<div>Home</div>
|
||||
</HeaderMenuItem>
|
||||
|
@ -256,10 +261,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
<Can I="GET" a={targetUris.processGroupListPath} ability={ability}>
|
||||
<SpiffTooltip title="Find and organize Process Groups and Process Models">
|
||||
<HeaderMenuItem
|
||||
element={Link}
|
||||
as={Link}
|
||||
to={processGroupPath}
|
||||
onClick={closeSideNavMenuIfExpanded}
|
||||
isCurrentPage={isActivePage(processGroupPath)}
|
||||
isActive={isActivePage(processGroupPath)}
|
||||
data-qa="header-nav-processes"
|
||||
>
|
||||
Processes
|
||||
|
@ -273,10 +278,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
>
|
||||
<SpiffTooltip title="List of active and completed Process Instances">
|
||||
<HeaderMenuItem
|
||||
element={Link}
|
||||
as={Link}
|
||||
to="/process-instances"
|
||||
onClick={closeSideNavMenuIfExpanded}
|
||||
isCurrentPage={isActivePage('/process-instances')}
|
||||
isActive={isActivePage('/process-instances')}
|
||||
>
|
||||
Process Instances
|
||||
</HeaderMenuItem>
|
||||
|
@ -285,10 +290,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
<Can I="GET" a={targetUris.messageInstanceListPath} ability={ability}>
|
||||
<SpiffTooltip title="Browse messages being sent and received">
|
||||
<HeaderMenuItem
|
||||
element={Link}
|
||||
as={Link}
|
||||
to="/messages"
|
||||
onClick={closeSideNavMenuIfExpanded}
|
||||
isCurrentPage={isActivePage('/messages')}
|
||||
isActive={isActivePage('/messages')}
|
||||
>
|
||||
Messages
|
||||
</HeaderMenuItem>
|
||||
|
@ -297,10 +302,10 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
<Can I="GET" a={targetUris.dataStoreListPath} ability={ability}>
|
||||
<SpiffTooltip title="Browse data that has been saved to Data Stores">
|
||||
<HeaderMenuItem
|
||||
element={Link}
|
||||
as={Link}
|
||||
to="/data-stores"
|
||||
onClick={closeSideNavMenuIfExpanded}
|
||||
isCurrentPage={isActivePage('/data-stores')}
|
||||
isActive={isActivePage('/data-stores')}
|
||||
>
|
||||
Data Stores
|
||||
</HeaderMenuItem>
|
||||
|
@ -322,12 +327,7 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
<HeaderContainer
|
||||
render={() => (
|
||||
<Header aria-label="IBM Platform Name" className="cds--g100">
|
||||
<HeaderName
|
||||
element={Link}
|
||||
to="/"
|
||||
prefix=""
|
||||
data-qa="spiffworkflow-logo"
|
||||
>
|
||||
<HeaderName as={Link} to="/" prefix="" data-qa="spiffworkflow-logo">
|
||||
<img src={logo} className="app-logo" alt="logo" />
|
||||
</HeaderName>
|
||||
</Header>
|
||||
|
@ -360,7 +360,7 @@ export default function NavigationBar({ extensionUxElements }: OwnProps) {
|
|||
isActive={isSideNavExpanded}
|
||||
/>
|
||||
<HeaderName
|
||||
element={Link}
|
||||
as={Link}
|
||||
to="/"
|
||||
onClick={closeSideNavMenuIfExpanded}
|
||||
prefix=""
|
||||
|
|
|
@ -77,7 +77,7 @@ export function Notification({
|
|||
className="cds--inline-notification__close-button"
|
||||
hasIconOnly
|
||||
size="sm"
|
||||
kind=""
|
||||
kind="ghost"
|
||||
onClick={onClose}
|
||||
/>
|
||||
)}
|
||||
|
@ -86,7 +86,7 @@ export function Notification({
|
|||
data-qa="close-publish-notification"
|
||||
className="cds--inline-notification__close-button"
|
||||
size="sm"
|
||||
kind=""
|
||||
kind="ghost"
|
||||
onClick={() => setShowMessage(!showMessage)}
|
||||
>
|
||||
{showMessage ? 'Hide' : 'Details'}
|
||||
|
|
|
@ -65,6 +65,7 @@ export default function ProcessGroupListTiles({
|
|||
return (
|
||||
<ClickableTile
|
||||
id={`process-group-tile-${row.id}`}
|
||||
key={`process-group-tile-${row.id}`}
|
||||
className="tile-process-group"
|
||||
onClick={() =>
|
||||
navigateToProcessGroup(
|
||||
|
|
|
@ -99,12 +99,13 @@ export default function ProcessInstanceListSaveAsReport({
|
|||
onRequestSubmit={addProcessInstanceReport}
|
||||
onRequestClose={handleSaveFormClose}
|
||||
hasScrollingContent
|
||||
aria-label="save perspective"
|
||||
>
|
||||
<p className="data-table-description">{descriptionText}</p>
|
||||
{textInputComponent}
|
||||
</Modal>
|
||||
<Button
|
||||
kind=""
|
||||
kind="tertiary"
|
||||
className={buttonClassName}
|
||||
onClick={() => {
|
||||
setIdentifier(processInstanceReportSelection?.identifier || '');
|
||||
|
|
|
@ -386,7 +386,7 @@ export default function ProcessInstanceListTable({
|
|||
return (
|
||||
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
|
||||
<td
|
||||
key={processInstance.id}
|
||||
key={`td-${columnAccessor}-${processInstance.id}`}
|
||||
onClick={() => navigateToProcessInstance(processInstance)}
|
||||
onKeyDown={() => navigateToProcessInstance(processInstance)}
|
||||
data-qa={`process-instance-show-link-${columnAccessor}`}
|
||||
|
@ -512,7 +512,7 @@ export default function ProcessInstanceListTable({
|
|||
if (hasAccessToCompleteTask && processInstance.task_id) {
|
||||
goButtonElement = (
|
||||
<Button
|
||||
kind="secondary"
|
||||
kind="primary"
|
||||
href={taskShowUrl}
|
||||
style={{ width: '60px' }}
|
||||
size="sm"
|
||||
|
|
|
@ -796,7 +796,7 @@ export default function ProcessInstanceListTableWithFilters({
|
|||
return (
|
||||
<ProcessInstanceListSaveAsReport
|
||||
onSuccess={onSaveReportSuccess}
|
||||
buttonClassName="button-white-background narrow-button"
|
||||
buttonClassName="narrow-button"
|
||||
buttonText="Save"
|
||||
processInstanceReportSelection={processInstanceReportSelection}
|
||||
reportMetadata={reportMetadata}
|
||||
|
@ -1040,6 +1040,7 @@ export default function ProcessInstanceListTableWithFilters({
|
|||
formElements.push(
|
||||
<Dropdown
|
||||
titleText="Display type"
|
||||
label="Display type"
|
||||
id="report-column-display-type"
|
||||
items={[''].concat(Object.values(filterDisplayTypes))}
|
||||
selectedItem={
|
||||
|
@ -1064,6 +1065,7 @@ export default function ProcessInstanceListTableWithFilters({
|
|||
formElements.push(
|
||||
<Dropdown
|
||||
titleText="Operator"
|
||||
label="Operator"
|
||||
id="report-column-condition-operator"
|
||||
items={Object.keys(filterOperatorMappings)}
|
||||
selectedItem={operator || null}
|
||||
|
@ -1110,6 +1112,7 @@ export default function ProcessInstanceListTableWithFilters({
|
|||
onRequestSubmit={handleUpdateReportColumn}
|
||||
onRequestClose={handleColumnFormClose}
|
||||
hasScrollingContent
|
||||
aria-label={modalHeading}
|
||||
>
|
||||
{formElements}
|
||||
</Modal>
|
||||
|
@ -1202,6 +1205,7 @@ export default function ProcessInstanceListTableWithFilters({
|
|||
<Dropdown
|
||||
id="system-report-dropdown"
|
||||
titleText="System report"
|
||||
label="System report"
|
||||
items={['', ...systemReportOptions]}
|
||||
itemToString={(item: any) => titleizeString(item)}
|
||||
selectedItem={systemReport}
|
||||
|
@ -1221,6 +1225,7 @@ export default function ProcessInstanceListTableWithFilters({
|
|||
<Dropdown
|
||||
id="user-group-dropdown"
|
||||
titleText="Assigned user group"
|
||||
label="Assigned user group"
|
||||
items={['', ...userGroups]}
|
||||
itemToString={(item: any) => item}
|
||||
selectedItem={selectedUserGroup}
|
||||
|
@ -1282,6 +1287,7 @@ export default function ProcessInstanceListTableWithFilters({
|
|||
onRequestSubmit={handleAdvancedOptionsClose}
|
||||
onRequestClose={handleAdvancedOptionsClose}
|
||||
hasScrollingContent
|
||||
aria-label="advanced filter options"
|
||||
size="lg"
|
||||
>
|
||||
{formElements}
|
||||
|
@ -1457,8 +1463,8 @@ export default function ProcessInstanceListTableWithFilters({
|
|||
<Column sm={4} md={4} lg={8}>
|
||||
<ButtonSet>
|
||||
<Button
|
||||
kind=""
|
||||
className="button-white-background narrow-button"
|
||||
kind="tertiary"
|
||||
className="narrow-button"
|
||||
onClick={clearFilters}
|
||||
>
|
||||
Clear
|
||||
|
|
|
@ -499,16 +499,16 @@ export default function ProcessInstanceLogList({
|
|||
<Column sm={4} md={4} lg={8}>
|
||||
<ButtonSet>
|
||||
<Button
|
||||
kind=""
|
||||
className="button-white-background narrow-button"
|
||||
kind="tertiary"
|
||||
className="narrow-button"
|
||||
onClick={resetFiltersAndRun}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
{shouldDisplayClearButton && (
|
||||
<Button
|
||||
kind=""
|
||||
className="button-white-background narrow-button"
|
||||
kind="tertiary"
|
||||
className="narrow-button"
|
||||
onClick={clearFilters}
|
||||
>
|
||||
Clear
|
||||
|
|
|
@ -333,8 +333,7 @@ export default function ProcessModelForm({
|
|||
<Button
|
||||
data-qa="add-notification-address-button"
|
||||
renderIcon={AddAlt}
|
||||
className="button-white-background"
|
||||
kind=""
|
||||
kind="tertiary"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
addBlankNotificationAddress();
|
||||
|
@ -365,8 +364,7 @@ export default function ProcessModelForm({
|
|||
<Button
|
||||
data-qa="add-metadata-extraction-path-button"
|
||||
renderIcon={AddAlt}
|
||||
className="button-white-background"
|
||||
kind=""
|
||||
kind="tertiary"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
addBlankMetadataExtractionPath();
|
||||
|
@ -383,7 +381,7 @@ export default function ProcessModelForm({
|
|||
|
||||
const formButtons = () => {
|
||||
return (
|
||||
<Button kind="secondary" type="submit">
|
||||
<Button kind="primary" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
);
|
||||
|
|
|
@ -155,18 +155,13 @@ export default function ReactDiagramEditor({
|
|||
if (diagramType === 'dmn') {
|
||||
modeler = (diagramModelerState as any).getActiveViewer();
|
||||
}
|
||||
try {
|
||||
if (modeler) {
|
||||
if (amount === 0) {
|
||||
const canvas = modeler.get('canvas');
|
||||
canvas.zoom(FitViewport, 'auto');
|
||||
} else {
|
||||
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') {
|
||||
newDiagramFileName = 'new_dmn_diagram.dmn';
|
||||
}
|
||||
fetchDiagramFromURL(`${process.env.PUBLIC_URL}/${newDiagramFileName}`);
|
||||
fetchDiagramFromURL(`/${newDiagramFileName}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,53 +8,77 @@ import {
|
|||
Button,
|
||||
} from '@carbon/react';
|
||||
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[] = [];
|
||||
examples.push({
|
||||
schema: require('../../resources/json_schema_examples/text-schema.json'), // eslint-disable-line global-require
|
||||
ui: require('../../resources/json_schema_examples/text-uischema.json'), // eslint-disable-line global-require
|
||||
data: {},
|
||||
});
|
||||
examples.push({
|
||||
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: {},
|
||||
});
|
||||
examples.push({
|
||||
schema: require('../../resources/json_schema_examples/checkbox-schema.json'), // eslint-disable-line global-require
|
||||
ui: {},
|
||||
data: {},
|
||||
});
|
||||
examples.push({
|
||||
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: {},
|
||||
});
|
||||
examples.push({
|
||||
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
|
||||
});
|
||||
examples.push({
|
||||
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: {},
|
||||
});
|
||||
examples.push({
|
||||
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: {},
|
||||
});
|
||||
examples.push({
|
||||
schema: require('../../resources/json_schema_examples/nested-schema.json'), // eslint-disable-line global-require
|
||||
ui: {},
|
||||
data: {},
|
||||
});
|
||||
examples.push({
|
||||
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: {},
|
||||
});
|
||||
|
||||
examples.push(
|
||||
{
|
||||
schema: textSchema,
|
||||
ui: textUiSchema,
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
schema: textareaSchema,
|
||||
ui: textareaUiSchema,
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
schema: checkboxSchema,
|
||||
ui: {},
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
schema: dateSchema,
|
||||
ui: dateUiSchema,
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
schema: dropdownSchema,
|
||||
ui: {},
|
||||
data: dropdownData,
|
||||
},
|
||||
{
|
||||
schema: choiceSchema,
|
||||
ui: choiceUiSchema,
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
schema: passwordSchema,
|
||||
ui: passwordUiSchema,
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
schema: nestedSchema,
|
||||
ui: {},
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
schema: typeaheadSchema,
|
||||
ui: typeaheadUiSchema,
|
||||
data: {},
|
||||
}
|
||||
);
|
||||
|
||||
type OwnProps = {
|
||||
onSelect: Function;
|
||||
|
@ -72,11 +96,7 @@ export default function ExamplesTable({ onSelect }: OwnProps) {
|
|||
<td>{example.schema.title}</td>
|
||||
<td>{example.schema.description}</td>
|
||||
<td>
|
||||
<Button
|
||||
kind="secondary"
|
||||
size="sm"
|
||||
onClick={() => selectExample(index)}
|
||||
>
|
||||
<Button kind="primary" size="sm" onClick={() => selectExample(index)}>
|
||||
Load
|
||||
</Button>
|
||||
</td>
|
||||
|
|
|
@ -2,7 +2,6 @@ import { useEffect, useState } from 'react';
|
|||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { Tabs, TabList, Tab } from '@carbon/react';
|
||||
import { SpiffTab } from '../interfaces';
|
||||
import SpiffTooltip from './SpiffTooltip';
|
||||
|
||||
type OwnProps = {
|
||||
tabs: SpiffTab[];
|
||||
|
@ -10,7 +9,7 @@ type OwnProps = {
|
|||
|
||||
export default function SpiffTabs({ tabs }: OwnProps) {
|
||||
const location = useLocation();
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState<number>(0);
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState<number | null>(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -25,20 +24,19 @@ export default function SpiffTabs({ tabs }: OwnProps) {
|
|||
|
||||
const tabComponents = tabs.map((spiffTab: SpiffTab) => {
|
||||
return (
|
||||
<SpiffTooltip title={spiffTab?.tooltip}>
|
||||
<Tab onClick={() => navigate(spiffTab.path)}>
|
||||
{spiffTab.display_name}
|
||||
</Tab>
|
||||
</SpiffTooltip>
|
||||
<Tab onClick={() => navigate(spiffTab.path)}>{spiffTab.display_name}</Tab>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs selectedIndex={selectedTabIndex}>
|
||||
<TabList aria-label="List of tabs">{tabComponents}</TabList>
|
||||
</Tabs>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
if (selectedTabIndex !== null && tabComponents.length > selectedTabIndex) {
|
||||
return (
|
||||
<>
|
||||
<Tabs selectedIndex={selectedTabIndex}>
|
||||
<TabList aria-label="List of tabs">{tabComponents}</TabList>
|
||||
</Tabs>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
declare const window: Window & typeof globalThis;
|
||||
|
||||
const { port, hostname } = window.location;
|
||||
let protocol = 'https';
|
||||
|
||||
|
@ -56,23 +58,16 @@ if (!backendBaseUrl) {
|
|||
}
|
||||
|
||||
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')) {
|
||||
backendBaseUrl += '/v1.0';
|
||||
}
|
||||
|
||||
export const BACKEND_BASE_URL = backendBaseUrl;
|
||||
export const DOCUMENTATION_URL = documentationUrl;
|
||||
const BACKEND_BASE_URL = backendBaseUrl;
|
||||
const DOCUMENTATION_URL = documentationUrl;
|
||||
|
||||
export const PROCESS_STATUSES = [
|
||||
const PROCESS_STATUSES = [
|
||||
'complete',
|
||||
'error',
|
||||
'not_started',
|
||||
|
@ -122,11 +117,23 @@ const carbonDateFormat = generalDateFormat
|
|||
.replace(/\bMMM\b/, 'M')
|
||||
.replace(/\bMMMM\b/, 'F')
|
||||
.replace(/\bdd\b/, 'd');
|
||||
export const DATE_TIME_FORMAT = `${generalDateFormat} HH:mm:ss`;
|
||||
export const TIME_FORMAT_HOURS_MINUTES = 'HH:mm';
|
||||
export const DATE_FORMAT = generalDateFormat;
|
||||
export const DATE_FORMAT_CARBON = carbonDateFormat;
|
||||
export const DATE_FORMAT_FOR_DISPLAY = generalDateFormat.toLowerCase();
|
||||
export const DATE_RANGE_DELIMITER = ':::';
|
||||
const DATE_TIME_FORMAT = `${generalDateFormat} HH:mm:ss`;
|
||||
const TIME_FORMAT_HOURS_MINUTES = 'HH:mm';
|
||||
const DATE_FORMAT = generalDateFormat;
|
||||
const DATE_FORMAT_CARBON = carbonDateFormat;
|
||||
const DATE_FORMAT_FOR_DISPLAY = generalDateFormat.toLowerCase();
|
||||
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');
|
||||
if (
|
||||
versionInfoContentString &&
|
||||
versionInfoContentString !== '%REACT_APP_VERSION_INFO%'
|
||||
versionInfoContentString !== '%VITE_VERSION_INFO%'
|
||||
) {
|
||||
versionInfo = JSON.parse(versionInfoContentString);
|
||||
}
|
||||
|
|
|
@ -144,17 +144,69 @@ h3 {
|
|||
* so they match our normal scheme better
|
||||
*/
|
||||
.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;
|
||||
background-color: #393939;
|
||||
}
|
||||
.cds--btn--tertiary:hover {
|
||||
color: white;
|
||||
.cds--modal-footer .cds--btn--secondary:visited {
|
||||
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;
|
||||
background-color: #474747;
|
||||
}
|
||||
.cds--btn--tertiary:visited:hover {
|
||||
color: white;
|
||||
.cds--modal-footer .cds--btn--secondary:visited:hover {
|
||||
color: #ffffff;
|
||||
border-color: #474747;
|
||||
background-color: #474747;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
// )
|
||||
// );
|
||||
|
||||
@use '@carbon/react';
|
||||
@use '@carbon/react' with (
|
||||
$font-path: '@ibm/plex'
|
||||
);
|
||||
@use '@carbon/styles';
|
||||
// @include grid.flex-grid();
|
||||
|
||||
|
|
|
@ -146,6 +146,7 @@ export default function BaseInputTemplate<
|
|||
<TextInput
|
||||
id={id}
|
||||
className="text-input"
|
||||
labelText=""
|
||||
helperText={commonAttributes.helperText}
|
||||
invalid={commonAttributes.invalid}
|
||||
invalidText={commonAttributes.errorMessageForField}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
// @ts-ignore
|
||||
import { Table } from '@carbon/react';
|
||||
import { AuthenticationItem } from '../interfaces';
|
||||
import HttpService from '../services/HttpService';
|
||||
|
@ -92,10 +91,10 @@ export default function AuthenticationList() {
|
|||
return (
|
||||
<>
|
||||
{buildTable()}
|
||||
{AuthenticationConfiguration()}
|
||||
<AuthenticationConfiguration />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return <main />;
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ export default function BaseRoutes({ extensionUxElements }: OwnProps) {
|
|||
return (
|
||||
<Route
|
||||
path={uxElement.page}
|
||||
key={uxElement.page}
|
||||
element={<Extension pageIdentifier={uxElement.page} />}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -74,7 +74,7 @@ export default function ProcessGroupList() {
|
|||
<ProcessBreadcrumb hotCrumbs={[['Process Groups']]} />
|
||||
<Stack orientation="horizontal" gap={3}>
|
||||
<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
|
||||
</Button>
|
||||
</Can>
|
||||
|
|
|
@ -915,7 +915,7 @@ export default function ProcessModelEditDiagram() {
|
|||
)}
|
||||
<Button
|
||||
className="m-top-10"
|
||||
kind="secondary"
|
||||
kind="primary"
|
||||
onClick={() => handleProcessScriptAssist()}
|
||||
disabled={scriptAssistLoading}
|
||||
>
|
||||
|
|
|
@ -64,7 +64,7 @@ export default function ProcessModelNewExperimental() {
|
|||
setProcessModelDescriptiveText(event.target.value)
|
||||
}
|
||||
/>
|
||||
<Button kind="secondary" type="submit">
|
||||
<Button kind="primary" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Form>
|
||||
|
|
|
@ -339,7 +339,7 @@ export default function ProcessModelShow() {
|
|||
let actionsTableCell = null;
|
||||
if (processModelFile.name.match(/\.(dmn|bpmn|json|md)$/)) {
|
||||
actionsTableCell = (
|
||||
<TableCell key={`${processModelFile.name}-cell`} align="right">
|
||||
<TableCell key={`${processModelFile.name}-action`} align="right">
|
||||
{renderButtonElements(processModelFile, isPrimaryBpmnFile)}
|
||||
</TableCell>
|
||||
);
|
||||
|
|
|
@ -71,11 +71,7 @@ export default function SecretNew() {
|
|||
}}
|
||||
/>
|
||||
<ButtonSet>
|
||||
<Button
|
||||
kind=""
|
||||
className="button-white-background"
|
||||
onClick={navigateToSecrets}
|
||||
>
|
||||
<Button kind="tertiary" onClick={navigateToSecrets}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button kind="primary" type="submit">
|
||||
|
|
|
@ -159,6 +159,7 @@ export default function SecretShow() {
|
|||
<TextInput
|
||||
id="secret_value"
|
||||
name="secret_value"
|
||||
labelText="Secret value"
|
||||
value={secret.value}
|
||||
onChange={handleSecretValueChange}
|
||||
disabled={
|
||||
|
|
|
@ -360,7 +360,7 @@ export default function TaskShow() {
|
|||
id="close-button"
|
||||
onClick={handleCloseButton}
|
||||
disabled={formButtonsDisabled}
|
||||
kind="secondary"
|
||||
kind="primary"
|
||||
title="Save data as draft and close the form."
|
||||
>
|
||||
Save and close
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
|
@ -0,0 +1 @@
|
|||
import '@testing-library/jest-dom';
|
|
@ -3,11 +3,18 @@
|
|||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "react-jsx",
|
||||
"module": "commonjs",
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "es2021",
|
||||
"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