refactor(web): replace CRA with Vite

This commit is contained in:
Ali BARIN
2025-04-28 16:16:11 +00:00
parent 1f6010bdea
commit f9772b6305
74 changed files with 2054 additions and 7400 deletions

View File

@@ -1,4 +0,0 @@
node_modules
build
source
.eslintrc.js

View File

@@ -1,10 +0,0 @@
module.exports = {
extends: [
'react-app',
'plugin:@tanstack/eslint-plugin-query/recommended',
'prettier',
],
rules: {
'react/prop-types': 'warn',
},
};

View File

@@ -1,6 +1,4 @@
# Getting Started with Create React App # Getting Started
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts ## Available Scripts
@@ -9,16 +7,11 @@ In the project directory, you can run:
### `yarn start` ### `yarn start`
Runs the app in the development mode.\ Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser. Open [http://localhost:3001](http://localhost:3001) to view it in the browser.
The page will reload if you make edits.\ The page will reload if you make edits.\
You will also see any lint errors in the console. You will also see any lint errors in the console.
### `yarn test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build` ### `yarn build`
Builds the app for production to the `build` folder.\ Builds the app for production to the `build` folder.\
@@ -28,19 +21,3 @@ The build is minified and the filenames include the hashes.\
Your app is ready to be deployed! Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).

View File

@@ -0,0 +1,39 @@
import js from '@eslint/js';
import prettier from 'eslint-config-prettier';
import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import globals from 'globals';
export default [
js.configs.recommended,
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
document: 'readonly',
window: 'readonly',
console: 'readonly',
JSX: true,
},
},
plugins: {
react: reactPlugin,
'react-hooks': reactHooksPlugin,
},
rules: {
...reactPlugin.configs.recommended.rules,
...reactHooksPlugin.configs.recommended.rules,
'react/prop-types': 'warn',
'react/react-in-jsx-scope': 'off',
},
},
prettier,
];

View File

@@ -71,7 +71,7 @@
transform: translateY(-40px); transform: translateY(-40px);
} }
</style> </style>
</head> <script type="module" src="src/index"></script></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>

View File

@@ -1,6 +1,17 @@
{ {
"compilerOptions": { "compilerOptions": {
"baseUrl": "src" "baseUrl": "src",
"paths": {
"components/*": ["components/*"],
"config/*": ["config/*"],
"contexts/*": ["contexts/*"],
"helpers/*": ["helpers/*"],
"hooks/*": ["hooks/*"],
"locales/*": ["locales/*"],
"pages/*": ["pages/*"],
"propTypes/*": ["propTypes/*"],
"styles/*": ["styles/*"]
}
}, },
"include": ["src"] "include": ["src"]
} }

View File

@@ -16,9 +16,6 @@
"@mui/material": "^5.11.10", "@mui/material": "^5.11.10",
"@mui/x-date-pickers": "^7.28.0", "@mui/x-date-pickers": "^7.28.0",
"@tanstack/react-query": "^5.24.1", "@tanstack/react-query": "^5.24.1",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@xyflow/react": "^12.4.4", "@xyflow/react": "^12.4.4",
"axios": "^1.6.0", "axios": "^1.6.0",
"clipboard-copy": "^4.0.1", "clipboard-copy": "^4.0.1",
@@ -29,29 +26,26 @@
"notistack": "^3.0.1", "notistack": "^3.0.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.45.2", "react-hook-form": "7.53.2",
"react-intl": "^5.20.12", "react-intl": "^5.20.12",
"react-json-tree": "^0.16.2", "react-json-tree": "^0.16.2",
"react-router-dom": "^6.0.2", "react-router-dom": "^6.0.2",
"react-scripts": "5.0.0",
"react-window": "^1.8.9", "react-window": "^1.8.9",
"slate": "^0.94.1", "slate": "^0.94.1",
"slate-history": "^0.93.0", "slate-history": "^0.93.0",
"slate-react": "^0.94.2", "slate-react": "^0.94.2",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"web-vitals": "^1.0.1",
"yup": "^0.32.11" "yup": "^0.32.11"
}, },
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"dev": "react-scripts start", "dev": "vite",
"build": "react-scripts build", "build": "vite build",
"build:watch": "yarn nodemon --exec react-scripts build --watch 'src/**/*.ts' --watch 'public/**/*' --ext ts,html", "build:watch": "yarn nodemon --exec vite build --watch 'src/**/*.ts' --watch 'public/**/*' --ext ts,html",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint src --ext .js,.jsx", "lint": "eslint src --ext .js,.jsx",
"prepack": "yarn build" "prepack": "yarn build",
"preview": "vite preview"
}, },
"files": [ "files": [
"/build" "/build"
@@ -85,16 +79,24 @@
"access": "public" "access": "public"
}, },
"devDependencies": { "devDependencies": {
"@tanstack/eslint-plugin-query": "^5.20.1", "@emotion/babel-plugin": "^11.13.5",
"@svgr/core": "^8.1.0",
"@svgr/plugin-jsx": "^8.1.0",
"@tanstack/react-query-devtools": "^5.24.1", "@tanstack/react-query-devtools": "^5.24.1",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@vitejs/plugin-react": "^4.3.4",
"@welldone-software/why-did-you-render": "^8",
"eslint": "^9.25.1",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-config-react-app": "^7.0.1", "eslint-config-react-app": "^7.0.1",
"prettier": "^3.2.5" "eslint-plugin-react-hooks": "^5.2.0",
}, "globals": "^16.0.0",
"eslintConfig": { "prettier": "^3.2.5",
"extends": [ "vite": "^6.1.0",
"./.eslintrc.js" "vite-plugin-eslint": "^1.8.1",
] "vite-tsconfig-paths": "^4.3.2"
}, },
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
} }

View File

@@ -69,7 +69,7 @@ AccountDropdownMenu.propTypes = {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
anchorEl: PropTypes.oneOfType([ anchorEl: PropTypes.oneOfType([
PropTypes.func, PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }), PropTypes.shape({ current: PropTypes.instanceOf(window.Element) }),
]), ]),
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
}; };

View File

@@ -43,7 +43,7 @@ function AdminApplicationSettings({ appKey }) {
'data-test': 'snackbar-save-admin-apps-settings-success', 'data-test': 'snackbar-save-admin-apps-settings-success',
}, },
}); });
} catch (error) { } catch {
throw new Error('Failed while saving!'); throw new Error('Failed while saving!');
} }
}; };

View File

@@ -37,18 +37,17 @@ function AdminApplicationUpdateOAuthClient(props) {
if (!adminOAuthClient) { if (!adminOAuthClient) {
return; return;
} }
const { name, active, ...formattedAuthDefaults } = values;
setAuthDefaultsUpdatePending(true); setAuthDefaultsUpdatePending(true);
await updateOAuthClient({
formattedAuthDefaults, await updateOAuthClient(values.formattedAuthDefaults).finally(() => {
}).finally(() => {
setAuthDefaultsUpdatePending(false); setAuthDefaultsUpdatePending(false);
}); });
setDefaultValues((prev) => ({ setDefaultValues((prev) => ({
name: prev.name, name: prev.name,
active: prev.active, active: prev.active,
...formattedAuthDefaults, ...values.formattedAuthDefaults,
})); }));
enqueueSnackbar(formatMessage('updateOAuthClient.success'), { enqueueSnackbar(formatMessage('updateOAuthClient.success'), {

View File

@@ -24,7 +24,6 @@ import useCurrentUserAbility from 'hooks/useCurrentUserAbility';
import Footer from './Footer'; import Footer from './Footer';
function createDrawerLinks({ function createDrawerLinks({
canCreateFlows,
canReadRole, canReadRole,
canReadUser, canReadUser,
canUpdateConfig, canUpdateConfig,

View File

@@ -57,7 +57,7 @@ AdminTemplateContextMenu.propTypes = {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
anchorEl: PropTypes.oneOfType([ anchorEl: PropTypes.oneOfType([
PropTypes.func, PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }), PropTypes.shape({ current: PropTypes.instanceOf(window.Element) }),
]).isRequired, ]).isRequired,
}; };

View File

@@ -100,7 +100,7 @@ ContextMenu.propTypes = {
onMenuItemClick: PropTypes.func.isRequired, onMenuItemClick: PropTypes.func.isRequired,
anchorEl: PropTypes.oneOfType([ anchorEl: PropTypes.oneOfType([
PropTypes.func, PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }), PropTypes.shape({ current: PropTypes.instanceOf(window.Element) }),
]), ]),
}; };

View File

@@ -43,7 +43,7 @@ function AppConnectionRow(props) {
{ connectionId: id }, { connectionId: id },
{ {
onSettled: () => { onSettled: () => {
setTimeout(() => setVerificationVisible(false), 3000); window.setTimeout(() => setVerificationVisible(false), 3000);
}, },
}, },
); );

View File

@@ -17,8 +17,9 @@ import FlowSubstepTitle from 'components/FlowSubstepTitle';
import { StepPropType, SubstepPropType } from 'propTypes/propTypes'; import { StepPropType, SubstepPropType } from 'propTypes/propTypes';
import useTriggers from 'hooks/useTriggers'; import useTriggers from 'hooks/useTriggers';
import useActions from 'hooks/useActions'; import useActions from 'hooks/useActions';
import appConfig from 'config/app.js';
const useNewFlowEditor = process.env.REACT_APP_USE_NEW_FLOW_EDITOR === 'true'; const useNewFlowEditor = appConfig.useNewFlowEditor;
const optionGenerator = (app) => ({ const optionGenerator = (app) => ({
label: app.name, label: app.name,

View File

@@ -24,8 +24,9 @@ import useAppConnections from 'hooks/useAppConnections';
import useTestConnection from 'hooks/useTestConnection'; import useTestConnection from 'hooks/useTestConnection';
import useOAuthClients from 'hooks/useOAuthClients'; import useOAuthClients from 'hooks/useOAuthClients';
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar'; import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
import appConfig from 'config/app.js';
const useNewFlowEditor = process.env.REACT_APP_USE_NEW_FLOW_EDITOR === 'true'; const useNewFlowEditor = appConfig.useNewFlowEditor;
const ADD_CONNECTION_VALUE = 'ADD_CONNECTION'; const ADD_CONNECTION_VALUE = 'ADD_CONNECTION';
const ADD_SHARED_CONNECTION_VALUE = 'ADD_SHARED_CONNECTION'; const ADD_SHARED_CONNECTION_VALUE = 'ADD_SHARED_CONNECTION';

View File

@@ -20,7 +20,7 @@ function CodeEditor(props) {
'data-test': dataTest, 'data-test': dataTest,
} = props; } = props;
const handleEditorOnMount = (editor, monaco) => { const handleEditorOnMount = (editor) => {
editorRef.current = editor; editorRef.current = editor;
editor.onDidContentSizeChange((event) => { editor.onDidContentSizeChange((event) => {

View File

@@ -78,7 +78,7 @@ CustomOptions.propTypes = {
open: PropTypes.bool.isRequired, open: PropTypes.bool.isRequired,
anchorEl: PropTypes.oneOfType([ anchorEl: PropTypes.oneOfType([
PropTypes.func, PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }), PropTypes.shape({ current: PropTypes.instanceOf(window.Element) }),
]), ]),
data: PropTypes.arrayOf( data: PropTypes.arrayOf(
PropTypes.shape({ PropTypes.shape({

View File

@@ -55,9 +55,10 @@ Item.propTypes = {
onOptionClick: PropTypes.func.isRequired, onOptionClick: PropTypes.func.isRequired,
}; };
const renderItemFactory = const renderItemFactory = ({ onOptionClick }) =>
({ onOptionClick }) => function RenderItem(props) {
(props) => <Item onOptionClick={onOptionClick} {...props} />; return <Item onOptionClick={onOptionClick} {...props} />;
};
const Options = (props) => { const Options = (props) => {
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();

View File

@@ -89,7 +89,7 @@ function ControlledCustomAutocomplete(props) {
}; };
const resizeObserver = React.useMemo(function syncCustomOptionsPosition() { const resizeObserver = React.useMemo(function syncCustomOptionsPosition() {
return new ResizeObserver(() => { return new window.ResizeObserver(() => {
forceUpdate(); forceUpdate();
}); });
}, []); }, []);

View File

@@ -4,8 +4,6 @@ import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import useFormatMessage from 'hooks/useFormatMessage';
export default function DatePickerInput({ export default function DatePickerInput({
onChange, onChange,
defaultValue = '', defaultValue = '',
@@ -15,7 +13,6 @@ export default function DatePickerInput({
maxDate, maxDate,
}) { }) {
const intl = useIntl(); const intl = useIntl();
const formatMessage = useFormatMessage();
const props = { const props = {
label, label,

View File

@@ -39,7 +39,9 @@ function DeleteApiTokenButton(props) {
}, },
}, },
); );
} catch {} } catch (error) {
console.error(error);
}
}, [deleteApiToken]); }, [deleteApiToken]);
const handleClose = () => { const handleClose = () => {

View File

@@ -43,7 +43,9 @@ function DeleteRoleButton(props) {
'data-test': 'snackbar-delete-role-success', 'data-test': 'snackbar-delete-role-success',
}, },
}); });
} catch {} } catch (error) {
console.error(error);
}
}, [deleteRole, enqueueSnackbar, formatMessage]); }, [deleteRole, enqueueSnackbar, formatMessage]);
const handleClose = () => { const handleClose = () => {

View File

@@ -39,7 +39,9 @@ function DeleteUserButton(props) {
'data-test': 'snackbar-delete-user-success', 'data-test': 'snackbar-delete-user-success',
}, },
}); });
} catch {} } catch (error) {
console.error(error);
}
}, [deleteUser]); }, [deleteUser]);
const handleClose = () => { const handleClose = () => {

View File

@@ -12,7 +12,7 @@ import { Drawer as BaseDrawer } from './style';
const iOS = const iOS =
typeof navigator !== 'undefined' && typeof navigator !== 'undefined' &&
/iPad|iPhone|iPod/.test(navigator.userAgent); /iPad|iPhone|iPod/.test(window.navigator.userAgent);
function Drawer(props) { function Drawer(props) {
const { links = [], bottomLinks = [], ...drawerProps } = props; const { links = [], bottomLinks = [], ...drawerProps } = props;

View File

@@ -27,8 +27,9 @@ import useUpdateFlow from 'hooks/useUpdateFlow';
import useUpdateFlowStatus from 'hooks/useUpdateFlowStatus'; import useUpdateFlowStatus from 'hooks/useUpdateFlowStatus';
import FlowFolder from './FlowFolder'; import FlowFolder from './FlowFolder';
import { TopBar } from './style'; import { TopBar } from './style';
import appConfig from 'config/app.js';
const useNewFlowEditor = process.env.REACT_APP_USE_NEW_FLOW_EDITOR === 'true'; const useNewFlowEditor = appConfig.useNewFlowEditor;
export default function EditorLayout() { export default function EditorLayout() {
const { flowId } = useParams(); const { flowId } = useParams();
@@ -48,7 +49,7 @@ export default function EditorLayout() {
}); });
}; };
const onExportFlow = async (name) => { const onExportFlow = async () => {
const flowExport = await exportFlow(); const flowExport = await exportFlow();
downloadJsonAsFile({ downloadJsonAsFile({

View File

@@ -17,7 +17,7 @@ export default function Edge({
const { flowActive, onStepAdd, isCreateStepPending } = const { flowActive, onStepAdd, isCreateStepPending } =
useContext(EdgesContext); useContext(EdgesContext);
const [edgePath, labelX, labelY] = getStraightPath({ const [, labelX, labelY] = getStraightPath({
sourceX, sourceX,
sourceY, sourceY,
targetX, targetX,

View File

@@ -8,7 +8,7 @@ export const NodeWrapper = styled(Box)(({ theme }) => ({
padding: theme.spacing(0, 2.5), padding: theme.spacing(0, 2.5),
})); }));
export const NodeInnerWrapper = styled(Box)(({ theme }) => ({ export const NodeInnerWrapper = styled(Box)(() => ({
maxWidth: 900, maxWidth: 900,
flex: 1, flex: 1,
})); }));

View File

@@ -1,7 +1,7 @@
import { Stack } from '@mui/material'; import { Stack } from '@mui/material';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
export const EditorWrapper = styled(Stack)(({ theme }) => ({ export const EditorWrapper = styled(Stack)(() => ({
flexGrow: 1, flexGrow: 1,
'& > div': { '& > div': {
flexGrow: 1, flexGrow: 1,

View File

@@ -7,20 +7,16 @@ import {
InputLabel, InputLabel,
MenuItem, MenuItem,
Select, Select,
Typography,
useMediaQuery, useMediaQuery,
} from '@mui/material'; } from '@mui/material';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import { DateTime } from 'luxon';
import { useState } from 'react'; import { useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import Can from 'components/Can';
import DatePickerInput from 'components/DatePickerInput'; import DatePickerInput from 'components/DatePickerInput';
import useExecutionFilters from 'hooks/useExecutionFilters'; import useExecutionFilters from 'hooks/useExecutionFilters';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
export default function ExecutionFilters({ onFilterChange }) { export default function ExecutionFilters() {
const theme = useTheme(); const theme = useTheme();
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();
const isMobile = useMediaQuery(theme.breakpoints.down('md')); const isMobile = useMediaQuery(theme.breakpoints.down('md'));

View File

@@ -185,7 +185,7 @@ ContextMenu.propTypes = {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
anchorEl: PropTypes.oneOfType([ anchorEl: PropTypes.oneOfType([
PropTypes.func, PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }), PropTypes.shape({ current: PropTypes.instanceOf(window.Element) }),
]).isRequired, ]).isRequired,
onDuplicateFlow: PropTypes.func, onDuplicateFlow: PropTypes.func,
appKey: PropTypes.string, appKey: PropTypes.string,

View File

@@ -6,19 +6,17 @@ import {
InputLabel, InputLabel,
MenuItem, MenuItem,
Select, Select,
Typography,
useMediaQuery, useMediaQuery,
Collapse, Collapse,
} from '@mui/material'; } from '@mui/material';
import FilterAltIcon from '@mui/icons-material/FilterAlt'; import FilterAltIcon from '@mui/icons-material/FilterAlt';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import Can from 'components/Can';
import useCurrentUserRuleConditions from 'hooks/useCurrentUserRuleConditions'; import useCurrentUserRuleConditions from 'hooks/useCurrentUserRuleConditions';
import useFlowFilters from 'hooks/useFlowFilters'; import useFlowFilters from 'hooks/useFlowFilters';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
export default function FlowFilters({ onFilterChange }) { export default function FlowFilters() {
const theme = useTheme(); const theme = useTheme();
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();
const isMobile = useMediaQuery(theme.breakpoints.down('md')); const isMobile = useMediaQuery(theme.breakpoints.down('md'));

View File

@@ -43,8 +43,9 @@ import useActions from 'hooks/useActions';
import useTriggerSubsteps from 'hooks/useTriggerSubsteps'; import useTriggerSubsteps from 'hooks/useTriggerSubsteps';
import useActionSubsteps from 'hooks/useActionSubsteps'; import useActionSubsteps from 'hooks/useActionSubsteps';
import useStepWithTestExecutions from 'hooks/useStepWithTestExecutions'; import useStepWithTestExecutions from 'hooks/useStepWithTestExecutions';
import appConfig from 'config/app.js';
const useNewFlowEditor = process.env.REACT_APP_USE_NEW_FLOW_EDITOR === 'true'; const useNewFlowEditor = appConfig.useNewFlowEditor;
const validIcon = <CheckCircleIcon color="success" />; const validIcon = <CheckCircleIcon color="success" />;
const errorIcon = <ErrorIcon color="error" />; const errorIcon = <ErrorIcon color="error" />;

View File

@@ -48,7 +48,7 @@ FlowStepContextMenu.propTypes = {
onDelete: PropTypes.func, onDelete: PropTypes.func,
anchorEl: PropTypes.oneOfType([ anchorEl: PropTypes.oneOfType([
PropTypes.func, PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }), PropTypes.shape({ current: PropTypes.instanceOf(window.Element) }),
]), ]),
deletable: PropTypes.bool.isRequired, deletable: PropTypes.bool.isRequired,
flowId: PropTypes.string.isRequired, flowId: PropTypes.string.isRequired,

View File

@@ -10,8 +10,9 @@ import FlowSubstepTitle from 'components/FlowSubstepTitle';
import InputCreator from 'components/InputCreator'; import InputCreator from 'components/InputCreator';
import FilterConditions from './FilterConditions'; import FilterConditions from './FilterConditions';
import { StepPropType, SubstepPropType } from 'propTypes/propTypes'; import { StepPropType, SubstepPropType } from 'propTypes/propTypes';
import appConfig from 'config/app.js';
const useNewFlowEditor = process.env.REACT_APP_USE_NEW_FLOW_EDITOR === 'true'; const useNewFlowEditor = appConfig.useNewFlowEditor;
function FlowSubstep(props) { function FlowSubstep(props) {
const { const {

View File

@@ -3,7 +3,6 @@ import { Link, useSearchParams, useNavigate } from 'react-router-dom';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import Card from '@mui/material/Card'; import Card from '@mui/material/Card';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from '@mui/icons-material/Delete';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
@@ -24,7 +23,6 @@ import useFormatMessage from 'hooks/useFormatMessage';
import useFolders from 'hooks/useFolders'; import useFolders from 'hooks/useFolders';
import useDeleteFolder from 'hooks/useDeleteFolder'; import useDeleteFolder from 'hooks/useDeleteFolder';
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar'; import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
import objectifyUrlSearchParams from 'helpers/objectifyUrlSearchParams';
import useFlowFilters from 'hooks/useFlowFilters'; import useFlowFilters from 'hooks/useFlowFilters';
import { ListItemIcon } from './style'; import { ListItemIcon } from './style';

View File

@@ -87,7 +87,7 @@ function Form(props) {
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>
<form <form
onSubmit={methods.handleSubmit(async (data, event) => { onSubmit={methods.handleSubmit(async (data) => {
try { try {
return await onSubmit?.(data); return await onSubmit?.(data);
} catch (errors) { } catch (errors) {

View File

@@ -55,10 +55,10 @@ function ImportFlowDialog(props) {
} }
}; };
const handleImportFlow = (event) => { const handleImportFlow = () => {
if (!selectedFile) return; if (!selectedFile) return;
const fileReader = new FileReader(); const fileReader = new window.FileReader();
fileReader.onload = async function readFileLoaded(e) { fileReader.onload = async function readFileLoaded(e) {
const flowData = parseFlowFile(e.target.result); const flowData = parseFlowFile(e.target.result);

View File

@@ -6,7 +6,7 @@ import englishMessages from 'locales/en.json';
const IntlProvider = ({ children }) => { const IntlProvider = ({ children }) => {
return ( return (
<BaseIntlProvider <BaseIntlProvider
locale={navigator.language.split('-')[0]} locale={window.navigator.language.split('-')[0]}
defaultLocale="en" defaultLocale="en"
messages={englishMessages} messages={englishMessages}
> >

View File

@@ -2,13 +2,10 @@ import styled from '@emotion/styled';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import Link from '@mui/material/Link'; import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import SvgIcon from '@mui/material/SvgIcon';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import useAutomatischConfig from 'hooks/useAutomatischConfig'; import useAutomatischConfig from 'hooks/useAutomatischConfig';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
import useVersion from 'hooks/useVersion';
const LogoImage = styled('img')(() => ({ const LogoImage = styled('img')(() => ({
maxWidth: 'auto', maxWidth: 'auto',
@@ -16,7 +13,7 @@ const LogoImage = styled('img')(() => ({
})); }));
const LayoutFooter = () => { const LayoutFooter = () => {
const { data: config, isPending: isConfigPending } = useAutomatischConfig(); const { data: config } = useAutomatischConfig();
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();
if (config?.data.enableFooter !== true) return null; if (config?.data.enableFooter !== true) return null;
@@ -34,22 +31,20 @@ const LayoutFooter = () => {
href: config.data.footerTosUrl, href: config.data.footerTosUrl,
text: formatMessage('footer.tosLinkText'), text: formatMessage('footer.tosLinkText'),
}, },
{ {
key: 'privacy-policy', key: 'privacy-policy',
show: !!config.data.footerPrivacyPolicyUrl, show: !!config.data.footerPrivacyPolicyUrl,
href: config.data.footerPrivacyPolicyUrl, href: config.data.footerPrivacyPolicyUrl,
text: formatMessage('footer.privacyPolicyLinkText'), text: formatMessage('footer.privacyPolicyLinkText'),
}, },
{ {
key: 'imprint', key: 'imprint',
show: !!config.data.footerImprintUrl, show: !!config.data.footerImprintUrl,
href: config.data.footerImprintUrl, href: config.data.footerImprintUrl,
text: formatMessage('footer.imprintLinkText'), text: formatMessage('footer.imprintLinkText'),
}, },
,
]; ];
return ( return (
<Box mt="auto" position="sticky" bottom={0}> <Box mt="auto" position="sticky" bottom={0}>
<Box bgcolor="common.white" mt={4}> <Box bgcolor="common.white" mt={4}>

View File

@@ -15,7 +15,7 @@ function ListItemLink(props) {
React.forwardRef(function InLineLink(linkProps, ref) { React.forwardRef(function InLineLink(linkProps, ref) {
try { try {
// challenge the link to check if it's absolute URL // challenge the link to check if it's absolute URL
new URL(to); // should throw an error if it's not an absolute URL new window.URL(to); // should throw an error if it's not an absolute URL
return ( return (
<a <a
{...linkProps} {...linkProps}

View File

@@ -40,7 +40,9 @@ function LoginForm() {
}); });
const { token } = data; const { token } = data;
authentication.updateToken(token); authentication.updateToken(token);
} catch {} } catch (error) {
console.error(error);
}
}; };
const renderError = () => { const renderError = () => {
@@ -49,7 +51,7 @@ function LoginForm() {
]; ];
return errors.map((error) => ( return errors.map((error) => (
<Alert severity="error" sx={{ mt: 2 }}> <Alert key={error} severity="error" sx={{ mt: 2 }}>
{error} {error}
</Alert> </Alert>
)); ));

View File

@@ -1,8 +1,8 @@
import * as React from 'react'; import * as React from 'react';
import { ReactComponent as MationLogoSvg } from './assets/mation-logo.svg'; import MationLogoSvg from './assets/mation-logo.svg';
const MationLogo = () => { const MationLogo = () => {
return <MationLogoSvg />; return <img src={MationLogoSvg} alt="Mation Logo" />;
}; };
export default MationLogo; export default MationLogo;

View File

@@ -3,22 +3,11 @@ import { useFormContext } from 'react-hook-form';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ControlledCheckbox from 'components/ControlledCheckbox'; import ControlledCheckbox from 'components/ControlledCheckbox';
const AllEntitiesPermissions = ({ const AllEntitiesPermissions = ({ action, subject, disabled, name }) => {
action, const { getValues, resetField } = useFormContext();
subject,
disabled,
name,
syncIsCreator,
}) => {
const { getValues, formState, resetField } = useFormContext();
const fieldName = `${name}.${subject.key}.${action.key}.allEntities`; const fieldName = `${name}.${subject.key}.${action.key}.allEntities`;
const defaultValue =
formState.defaultValues?.[name]?.[subject.key]?.[action.key].allEntities;
const ownEntitiesFieldName = `${name}.${subject.key}.${action.key}.ownEntities`; const ownEntitiesFieldName = `${name}.${subject.key}.${action.key}.ownEntities`;
const ownEntitiesFieldTouched =
formState.touchedFields?.[name]?.[subject.key]?.[action.key]
?.ownEntities === true;
const currentValue = getValues(fieldName); const currentValue = getValues(fieldName);
@@ -28,16 +17,6 @@ const AllEntitiesPermissions = ({
} }
}, [ownEntitiesFieldName, currentValue]); }, [ownEntitiesFieldName, currentValue]);
const handleSyncIsCreator = (newValue) => {
if (syncIsCreator && defaultValue === false && !ownEntitiesFieldTouched) {
resetField(ownEntitiesFieldName, { defaultValue: newValue });
}
if (newValue === true) {
resetField(ownEntitiesFieldName, { defaultValue: true });
}
};
return ( return (
<ControlledCheckbox <ControlledCheckbox
disabled={disabled} disabled={disabled}

View File

@@ -42,7 +42,7 @@ Popper.propTypes = {
open: PropTypes.bool.isRequired, open: PropTypes.bool.isRequired,
anchorEl: PropTypes.oneOfType([ anchorEl: PropTypes.oneOfType([
PropTypes.func, PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }), PropTypes.shape({ current: PropTypes.instanceOf(window.Element) }),
]), ]),
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,
onSuggestionClick: PropTypes.func, onSuggestionClick: PropTypes.func,

View File

@@ -28,11 +28,10 @@ const getPartialArray = (array, length = array.length) => {
return array.slice(0, length); return array.slice(0, length);
}; };
const renderItemFactory = const renderItemFactory = ({ onSuggestionClick }) =>
({ onSuggestionClick }) => function RenderItem(props) {
(props) => ( return <SuggestionItem {...props} onSuggestionClick={onSuggestionClick} />;
<SuggestionItem {...props} onSuggestionClick={onSuggestionClick} /> };
);
const Suggestions = (props) => { const Suggestions = (props) => {
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();

View File

@@ -50,7 +50,9 @@ export default function ResetPasswordForm() {
}, },
}); });
navigate(URLS.LOGIN); navigate(URLS.LOGIN);
} catch {} } catch (error) {
console.error(error);
}
}; };
const renderError = () => { const renderError = () => {
@@ -63,7 +65,7 @@ export default function ResetPasswordForm() {
]; ];
return errors.map((error) => ( return errors.map((error) => (
<Alert severity="error" sx={{ mt: 2 }}> <Alert key={error} severity="error" sx={{ mt: 2 }}>
{error} {error}
</Alert> </Alert>
)); ));

View File

@@ -23,7 +23,7 @@ export default function SplitButton(props) {
setOpen((prevOpen) => !prevOpen); setOpen((prevOpen) => !prevOpen);
}; };
const handleClose = (event) => { const handleClose = () => {
setOpen(false); setOpen(false);
}; };

View File

@@ -15,8 +15,9 @@ import WebhookUrlInfo from 'components/WebhookUrlInfo';
import FlowSubstepTitle from 'components/FlowSubstepTitle'; import FlowSubstepTitle from 'components/FlowSubstepTitle';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { StepPropType, SubstepPropType } from 'propTypes/propTypes'; import { StepPropType, SubstepPropType } from 'propTypes/propTypes';
import appConfig from 'config/app.js';
const useNewFlowEditor = process.env.REACT_APP_USE_NEW_FLOW_EDITOR === 'true'; const useNewFlowEditor = appConfig.useNewFlowEditor;
function TestSubstep(props) { function TestSubstep(props) {
const { const {

View File

@@ -1,12 +1,12 @@
const backendUrl = process.env.REACT_APP_BACKEND_URL; const backendUrl = import.meta.env.VITE_BACKEND_URL;
const computeUrl = (url, backendUrl) => { const computeUrl = (url, backendUrl) => {
/** /**
* In case `backendUrl` is a host, we append the url to it. * In case `backendUrl` is a host, we append the url to it.
**/ **/
try { try {
return new URL(url, backendUrl).toString(); return new window.URL(url, backendUrl).toString();
} catch (e) { } catch {
/* /*
* In case `backendUrl` is not qualified, we utilize `url` alone. * In case `backendUrl` is not qualified, we utilize `url` alone.
**/ **/
@@ -15,8 +15,9 @@ const computeUrl = (url, backendUrl) => {
}; };
const config = { const config = {
baseUrl: process.env.REACT_APP_BASE_URL, baseUrl: import.meta.env.VITE_BASE_URL,
restApiUrl: computeUrl('/internal/api', backendUrl), restApiUrl: computeUrl('/internal/api', backendUrl),
useNewFlowEditor: import.meta.env.VITE_USE_NEW_FLOW_EDITOR === 'true',
supportEmailAddress: 'support@automatisch.io', supportEmailAddress: 'support@automatisch.io',
}; };

View File

@@ -1,6 +1,8 @@
const parseUrlSearchParams = (event) => { const parseUrlSearchParams = (event) => {
const searchParams = new URLSearchParams(event.data.payload.search); const searchParams = new window.URLSearchParams(event.data.payload.search);
const hashParams = new URLSearchParams(event.data.payload.hash.substring(1)); const hashParams = new window.URLSearchParams(
event.data.payload.hash.substring(1),
);
const searchParamsObject = getObjectOfEntries(searchParams.entries()); const searchParamsObject = getObjectOfEntries(searchParams.entries());
const hashParamsObject = getObjectOfEntries(hashParams.entries()); const hashParamsObject = getObjectOfEntries(hashParams.entries());
@@ -33,9 +35,9 @@ export const processPopupMessage = (popup) => {
let closeCheckIntervalId; let closeCheckIntervalId;
if (popup) { if (popup) {
closeCheckIntervalId = setInterval(() => { closeCheckIntervalId = window.setInterval(() => {
if (popup.closed) { if (popup.closed) {
clearInterval(closeCheckIntervalId); window.clearInterval(closeCheckIntervalId);
reject({ message: 'Error occured while verifying credentials!' }); reject({ message: 'Error occured while verifying credentials!' });
} }
@@ -51,7 +53,7 @@ export const processPopupMessage = (popup) => {
window.removeEventListener('message', messageHandler); window.removeEventListener('message', messageHandler);
if (closeCheckIntervalId) { if (closeCheckIntervalId) {
clearInterval(closeCheckIntervalId); window.clearInterval(closeCheckIntervalId);
} }
resolve(data); resolve(data);

View File

@@ -2,13 +2,13 @@ const NAMESPACE = 'automatisch';
const makeKey = (key) => `${NAMESPACE}.${key}`; const makeKey = (key) => `${NAMESPACE}.${key}`;
export const setItem = (key, value) => { export const setItem = (key, value) => {
return localStorage.setItem(makeKey(key), value); return window.localStorage.setItem(makeKey(key), value);
}; };
export const getItem = (key) => { export const getItem = (key) => {
return localStorage.getItem(makeKey(key)); return window.localStorage.getItem(makeKey(key));
}; };
export const removeItem = (key) => { export const removeItem = (key) => {
return localStorage.removeItem(makeKey(key)); return window.localStorage.removeItem(makeKey(key));
}; };

View File

@@ -1,16 +1,22 @@
import { Link as RouterLink } from 'react-router-dom'; import { Link as RouterLink } from 'react-router-dom';
import Link from '@mui/material/Link'; import Link from '@mui/material/Link';
export const generateInternalLink = (link) => (str) => ( export const generateInternalLink = (link) =>
<Link component={RouterLink} to={link}> function LinkVariable(str) {
{str} return (
</Link> <Link component={RouterLink} to={link}>
); {str}
</Link>
);
};
export const generateExternalLink = (link) => (str) => ( export const generateExternalLink = (link) =>
<Link href={link} target="_blank"> function LinkVariable(str) {
{str} return (
</Link> <Link href={link} target="_blank">
); {str}
</Link>
);
};
export const makeBold = (str) => <strong>{str}</strong>; export const makeBold = (str) => <strong>{str}</strong>;

View File

@@ -5,13 +5,13 @@ export default function useAdminDeleteRole(roleId) {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const query = useMutation({ const query = useMutation({
mutationFn: async (payload) => { mutationFn: async () => {
const { data } = await api.delete(`/v1/admin/roles/${roleId}`); const { data } = await api.delete(`/v1/admin/roles/${roleId}`);
return data; return data;
}, },
onSuccess: () => { onSuccess: async () => {
queryClient.invalidateQueries({ await queryClient.invalidateQueries({
queryKey: ['admin', 'roles'], queryKey: ['admin', 'roles'],
}); });
}, },

View File

@@ -10,7 +10,7 @@ const appendTrailingSlash = (url) => {
} }
return url; return url;
} };
/** /**
* Per instance, there may be different documentation. However, the paths are assumed the same. * Per instance, there may be different documentation. However, the paths are assumed the same.
@@ -18,10 +18,12 @@ const appendTrailingSlash = (url) => {
*/ */
export default function useDocsUrl(path) { export default function useDocsUrl(path) {
const { data: automatischInfo } = useAutomatischInfo(); const { data: automatischInfo } = useAutomatischInfo();
const docsUrlWithTrailingSlash = appendTrailingSlash(automatischInfo?.docsUrl); const docsUrlWithTrailingSlash = appendTrailingSlash(
automatischInfo?.docsUrl,
);
const docsUrl = docsUrlWithTrailingSlash || 'https://automatisch.io/docs/'; const docsUrl = docsUrlWithTrailingSlash || 'https://automatisch.io/docs/';
const absoluteUrl = new URL(path, docsUrl).toString(); const absoluteUrl = new window.URL(path, docsUrl).toString();
return absoluteUrl; return absoluteUrl;
} }

View File

@@ -12,11 +12,11 @@ export default function useDownloadJsonAsFile() {
replacement: '-', replacement: '-',
}); });
const fileBlob = new Blob([stringifiedContents], { const fileBlob = new window.Blob([stringifiedContents], {
type: 'application/json', type: 'application/json',
}); });
const fileObjectUrl = URL.createObjectURL(fileBlob); const fileObjectUrl = window.URL.createObjectURL(fileBlob);
const temporaryDownloadLink = document.createElement('a'); const temporaryDownloadLink = document.createElement('a');
temporaryDownloadLink.href = fileObjectUrl; temporaryDownloadLink.href = fileObjectUrl;

View File

@@ -92,7 +92,7 @@ function useDynamicData(stepId, schema) {
lastComputedVariables.current = variables; lastComputedVariables.current = variables;
return variables; return variables;
} catch (err) { } catch {
return null; return null;
} }
} }

View File

@@ -61,7 +61,7 @@ function useDynamicFields(stepId, schema) {
} }
lastComputedVariables.current = variables; lastComputedVariables.current = variables;
return variables; return variables;
} catch (err) { } catch {
return null; return null;
} }
} }

View File

@@ -1,8 +1,6 @@
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { useMutation } from '@tanstack/react-query';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import api from 'helpers/api';
import objectifyUrlSearchParams from 'helpers/objectifyUrlSearchParams'; import objectifyUrlSearchParams from 'helpers/objectifyUrlSearchParams';
export default function useExecutionFilters() { export default function useExecutionFilters() {
@@ -21,7 +19,8 @@ export default function useExecutionFilters() {
const endDateTime = parseInt(endDateTimeString, 10); const endDateTime = parseInt(endDateTimeString, 10);
const filterByStatus = (status) => { const filterByStatus = (status) => {
setSearchParams((current) => { setSearchParams(() => {
// eslint-disable-next-line no-unused-vars
const { status: currentStatus, ...rest } = searchParamsObject; const { status: currentStatus, ...rest } = searchParamsObject;
if (status) { if (status) {
@@ -35,7 +34,8 @@ export default function useExecutionFilters() {
const filterByStartDateTime = (startDateTime) => { const filterByStartDateTime = (startDateTime) => {
const startDateTimeString = startDateTime?.toMillis(); const startDateTimeString = startDateTime?.toMillis();
setSearchParams((current) => { setSearchParams(() => {
// eslint-disable-next-line no-unused-vars
const { startDateTime: currentStartDateTime, ...rest } = const { startDateTime: currentStartDateTime, ...rest } =
searchParamsObject; searchParamsObject;
@@ -50,7 +50,8 @@ export default function useExecutionFilters() {
const filterByEndDateTime = (endDateTime) => { const filterByEndDateTime = (endDateTime) => {
const endDateTimeString = endDateTime?.endOf('day').toMillis(); const endDateTimeString = endDateTime?.endOf('day').toMillis();
setSearchParams((current) => { setSearchParams(() => {
// eslint-disable-next-line no-unused-vars
const { endDateTime: currentEndDateTime, ...rest } = searchParamsObject; const { endDateTime: currentEndDateTime, ...rest } = searchParamsObject;
if (endDateTimeString) { if (endDateTimeString) {
@@ -65,13 +66,14 @@ export default function useExecutionFilters() {
const searchParamsObject = objectifyUrlSearchParams(searchParams); const searchParamsObject = objectifyUrlSearchParams(searchParams);
if (value === undefined) { if (value === undefined) {
// eslint-disable-next-line no-unused-vars
const { [key]: keyToRemove, ...remainingSearchParams } = const { [key]: keyToRemove, ...remainingSearchParams } =
searchParamsObject; searchParamsObject;
return new URLSearchParams(remainingSearchParams).toString(); return new window.URLSearchParams(remainingSearchParams).toString();
} }
return new URLSearchParams({ return new window.URLSearchParams({
...searchParamsObject, ...searchParamsObject,
[key]: value, [key]: value,
}).toString(); }).toString();

View File

@@ -1,7 +1,5 @@
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { useMutation } from '@tanstack/react-query';
import api from 'helpers/api';
import objectifyUrlSearchParams from 'helpers/objectifyUrlSearchParams'; import objectifyUrlSearchParams from 'helpers/objectifyUrlSearchParams';
export default function useFlowFilters() { export default function useFlowFilters() {
@@ -14,7 +12,8 @@ export default function useFlowFilters() {
searchParamsObject.onlyOwnedFlows === 'true' || undefined; searchParamsObject.onlyOwnedFlows === 'true' || undefined;
const filterByStatus = (status) => { const filterByStatus = (status) => {
setSearchParams((current) => { setSearchParams(() => {
// eslint-disable-next-line no-unused-vars
const { status: currentStatus, ...rest } = searchParamsObject; const { status: currentStatus, ...rest } = searchParamsObject;
if (status) { if (status) {
@@ -26,7 +25,8 @@ export default function useFlowFilters() {
}; };
const filterByOwnership = (onlyOwnedFlows) => { const filterByOwnership = (onlyOwnedFlows) => {
setSearchParams((current) => { setSearchParams(() => {
// eslint-disable-next-line no-unused-vars
const { onlyOwnedFlows: currentOnlyOwnedFlows, ...rest } = const { onlyOwnedFlows: currentOnlyOwnedFlows, ...rest } =
searchParamsObject; searchParamsObject;
@@ -42,13 +42,14 @@ export default function useFlowFilters() {
const searchParamsObject = objectifyUrlSearchParams(searchParams); const searchParamsObject = objectifyUrlSearchParams(searchParams);
if (value === undefined) { if (value === undefined) {
// eslint-disable-next-line no-unused-vars
const { [key]: keyToRemove, ...remainingSearchParams } = const { [key]: keyToRemove, ...remainingSearchParams } =
searchParamsObject; searchParamsObject;
return new URLSearchParams(remainingSearchParams).toString(); return new window.URLSearchParams(remainingSearchParams).toString();
} }
return new URLSearchParams({ return new window.URLSearchParams({
...searchParamsObject, ...searchParamsObject,
[key]: value, [key]: value,
}).toString(); }).toString();

View File

@@ -1,4 +1,3 @@
import userAbility from 'helpers/userAbility';
import useCurrentUser from 'hooks/useCurrentUser'; import useCurrentUser from 'hooks/useCurrentUser';
export default function useIsCurrentUserAdmin() { export default function useIsCurrentUserAdmin() {

View File

@@ -4,10 +4,10 @@ import api from 'helpers/api';
import React from 'react'; import React from 'react';
export default function useLazyApps({ appName } = {}, { onSuccess } = {}) { export default function useLazyApps({ appName } = {}, { onSuccess } = {}) {
const abortControllerRef = React.useRef(new AbortController()); const abortControllerRef = React.useRef(new window.AbortController());
React.useEffect(() => { React.useEffect(() => {
abortControllerRef.current = new AbortController(); abortControllerRef.current = new window.AbortController();
return () => { return () => {
abortControllerRef.current?.abort(); abortControllerRef.current?.abort();

View File

@@ -8,8 +8,7 @@ import MetadataProvider from 'components/MetadataProvider';
import { AuthenticationProvider } from 'contexts/Authentication'; import { AuthenticationProvider } from 'contexts/Authentication';
import QueryClientProvider from 'components/QueryClientProvider'; import QueryClientProvider from 'components/QueryClientProvider';
import Router from 'components/Router'; import Router from 'components/Router';
import routes from 'routes'; import routes from './routes';
import reportWebVitals from './reportWebVitals';
// Sets the default locale to English for all luxon DateTime instances created afterwards. // Sets the default locale to English for all luxon DateTime instances created afterwards.
Settings.defaultLocale = 'en'; Settings.defaultLocale = 'en';
@@ -32,8 +31,3 @@ root.render(
</SnackbarProvider> </SnackbarProvider>
</Router>, </Router>,
); );
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

View File

@@ -61,7 +61,7 @@ function AdminTemplates() {
defaultValues={{ enableTemplates: config?.data.enableTemplates }} defaultValues={{ enableTemplates: config?.data.enableTemplates }}
noValidate noValidate
automaticValidation={false} automaticValidation={false}
render={({ formState: { errors, isDirty } }) => ( render={() => (
<Switch <Switch
name="enableTemplates" name="enableTemplates"
disabled={isUpdateConfigPending} disabled={isUpdateConfigPending}

View File

@@ -30,7 +30,9 @@ export default function CreateFlow() {
const flowId = response.data?.id; const flowId = response.data?.id;
navigateToEditor(flowId); navigateToEditor(flowId);
} catch {} } catch (error) {
console.error(error);
}
} }
initiate(); initiate();

View File

@@ -25,9 +25,6 @@ export default function Executions() {
const navigate = useNavigate(); const navigate = useNavigate();
const page = parseInt(searchParams.get('page') || '', 10) || 1; const page = parseInt(searchParams.get('page') || '', 10) || 1;
const name = searchParams.get('name') || ''; const name = searchParams.get('name') || '';
const status = searchParams.get('status');
const startDateTime = searchParams.get('startDateTime');
const endDateTime = searchParams.get('endDateTime');
const [searchValue, setSearchValue] = React.useState(name); const [searchValue, setSearchValue] = React.useState(name);
const { const {
@@ -61,7 +58,7 @@ export default function Executions() {
const getPathWithSearchParams = (page) => { const getPathWithSearchParams = (page) => {
const searchParamsObject = objectifyUrlSearchParams(searchParams); const searchParamsObject = objectifyUrlSearchParams(searchParams);
const newSearchParams = new URLSearchParams({ const newSearchParams = new window.URLSearchParams({
...searchParamsObject, ...searchParamsObject,
page, page,
}); });

View File

@@ -73,7 +73,7 @@ export default function Flows() {
const getPathWithSearchParams = (page) => { const getPathWithSearchParams = (page) => {
const searchParamsObject = objectifyUrlSearchParams(searchParams); const searchParamsObject = objectifyUrlSearchParams(searchParams);
const newSearchParams = new URLSearchParams({ const newSearchParams = new window.URLSearchParams({
...searchParamsObject, ...searchParamsObject,
page, page,
}); });

View File

@@ -87,7 +87,7 @@ export default function UserInterface() {
'data-test': 'snackbar-update-user-interface-success', 'data-test': 'snackbar-update-user-interface-success',
}, },
}); });
} catch (error) { } catch {
throw new Error('Failed while updating!'); throw new Error('Failed while updating!');
} }
}; };

View File

@@ -1,12 +0,0 @@
const reportWebVitals = (onPerfEntry) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

View File

@@ -15,7 +15,6 @@ import Application from 'pages/Application';
import Executions from 'pages/Executions'; import Executions from 'pages/Executions';
import Execution from 'pages/Execution'; import Execution from 'pages/Execution';
import Flows from 'pages/Flows'; import Flows from 'pages/Flows';
import Flow from 'pages/Flow';
import Login from 'pages/Login'; import Login from 'pages/Login';
import AcceptInvitation from 'pages/AcceptInvitation'; import AcceptInvitation from 'pages/AcceptInvitation';
import LoginCallback from 'pages/LoginCallback'; import LoginCallback from 'pages/LoginCallback';

View File

@@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

View File

@@ -0,0 +1,47 @@
import react from '@vitejs/plugin-react';
import path from 'node:path';
import { defineConfig } from 'vite';
import eslint from 'vite-plugin-eslint';
export default defineConfig(() => {
return {
// https://github.com/vitejs/vite/issues/1973#issuecomment-787571499
define: {
'process.env': {},
},
build: {
outDir: 'build',
},
plugins: [
react({
jsxImportSource: '@emotion/react',
babel: {
plugins: ['@emotion/babel-plugin'],
},
}),
eslint({
eslintPath: require.resolve('eslint'),
cache: false,
include: ['src/**/*.js', 'src/**/*.jsx'],
exclude: ['node_modules'],
}),
],
resolve: {
alias: {
components: path.resolve(__dirname, './src/components'),
config: path.resolve(__dirname, './src/config'),
contexts: path.resolve(__dirname, './src/contexts'),
helpers: path.resolve(__dirname, './src/helpers'),
hooks: path.resolve(__dirname, './src/hooks'),
locales: path.resolve(__dirname, './src/locales'),
pages: path.resolve(__dirname, './src/pages'),
propTypes: path.resolve(__dirname, './src/propTypes'),
styles: path.resolve(__dirname, './src/styles'),
},
},
server: {
open: true,
port: process.env.PORT || 3001,
},
};
});

File diff suppressed because it is too large Load Diff