Compare commits

...

2 Commits
7.0.0 ... 7.1.0

Author SHA1 Message Date
Christian Kellner
f3cded7e5d fixing npe 2023-03-20 10:56:33 +01:00
Christian Kellner
d7c9c4bf76 Modernizing ui (#73)
Modernizing ui
2023-03-20 08:52:13 +01:00
45 changed files with 1234 additions and 1276 deletions

View File

@@ -203,10 +203,6 @@ module.exports = {
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
'react/self-closing-comp': 'warn', 'react/self-closing-comp': 'warn',
// Enforce spaces before the closing bracket of self-closing JSX elements
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md
'react/jsx-space-before-closing': ['warn', 'always'],
// Enforce component methods order // Enforce component methods order
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md
'react/sort-comp': 'off', 'react/sort-comp': 'off',
@@ -237,7 +233,7 @@ module.exports = {
// only .jsx files may have JSX // only .jsx files may have JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md
'react/jsx-filename-extension': ['error', { extensions: ['.js'] }], 'react/jsx-filename-extension': ['error', { extensions: ['.jsx'] }],
// prevent accidental JS comments from being injected into JSX as text // prevent accidental JS comments from being injected into JSX as text
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md
@@ -282,15 +278,5 @@ module.exports = {
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md
'react/no-children-prop': 'warn', 'react/no-children-prop': 'warn',
// Validate whitespace in and around the JSX opening and closing brackets
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md
'react/jsx-tag-spacing': [
'warn',
{
closingSlash: 'never',
beforeSelfClosing: 'always',
afterOpening: 'never',
},
],
}, },
}; };

View File

@@ -27,11 +27,11 @@ yarn run start
_Fredy_ will start with the default port, set to `9998`. You can access _Fredy_ by opening your browser at `http://localhost:9998`. The default login is `admin`, both for username and password. You should change the password as soon as possible when you plan to run Fredy on a server. _Fredy_ will start with the default port, set to `9998`. You can access _Fredy_ by opening your browser at `http://localhost:9998`. The default login is `admin`, both for username and password. You should change the password as soon as possible when you plan to run Fredy on a server.
<p align="center"> <p align="center">
<img alt="Job Configuration" src="https://github.com/orangecoding/fredy/blob/master/doc/screenshot__1.png" width="30%"> <img alt="Job Configuration" src="https://github.com/orangecoding/fredy/blob/master/doc/screenshot1.png" width="30%">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
<img alt="Job Analytics" src="https://github.com/orangecoding/fredy/blob/master/doc/screenshot2.png" width="30%"> <img alt="Job Analytics" src="https://github.com/orangecoding/fredy/blob/master/doc/screenshot_2.png" width="30%">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
<img alt="Job Overview" width="30%" src="https://github.com/orangecoding/fredy/blob/master/doc/screenshot3.png"> <img alt="Job Overview" width="30%" src="https://github.com/orangecoding/fredy/blob/master/doc/screenshot_3.png">
</p> </p>
<p align="center"> <p align="center">

BIN
doc/screenshot1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 KiB

BIN
doc/screenshot_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

BIN
doc/screenshot_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

View File

@@ -4,12 +4,11 @@
<meta charset="UTF-8" <meta charset="UTF-8"
name="viewport" name="viewport"
content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"> content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2/dist/semantic.min.css">
<meta name="google" content="notranslate"> <meta name="google" content="notranslate">
<title>Fredy</title> <title>Fredy</title>
</head> </head>
<body> <body theme-mode="dark">
<div id="fredy" style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;"></div> <div id="fredy" style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;"></div>
</body> </body>

View File

@@ -1,15 +1,15 @@
{ {
"name": "fredy", "name": "fredy",
"version": "7.0.0", "version": "7.1.0",
"description": "[F]ind [R]eal [E]states [d]amn eas[y].", "description": "[F]ind [R]eal [E]states [d]amn eas[y].",
"scripts": { "scripts": {
"start": "node index.js", "start": "node index.js",
"dev": "yarn && rm -rf ./ui/public/* && vite", "dev": "yarn && rm -rf ./ui/public/* && vite",
"ui": "rm -rf ./ui/public/* && vite", "ui": "rm -rf ./ui/public/* && vite",
"prod": "yarn && vite build --emptyOutDir", "prod": "yarn && vite build --emptyOutDir",
"format": "prettier --write lib/**/*.js ui/src/**/*.js test/**/*.js *.js --single-quote --print-width 120", "format": "prettier --write lib/**/*.js ui/src/**/*.jsx test/**/*.js *.js --single-quote --print-width 120",
"test": "mocha --loader=esmock --timeout 3000000 test/**/*.test.js", "test": "mocha --loader=esmock --timeout 3000000 test/**/*.test.js",
"lint": "eslint ./index.js ./lib/**/*.js ./test/**/*.js" "lint": "eslint ./index.js ./lib/**/*.js ./test/**/*.js ./ui/src/**/*.jsx"
}, },
"husky": { "husky": {
"hooks": { "hooks": {
@@ -55,6 +55,7 @@
"Firefox ESR" "Firefox ESR"
], ],
"dependencies": { "dependencies": {
"@douyinfe/semi-ui": "2.31.0",
"@rematch/core": "2.2.0", "@rematch/core": "2.2.0",
"@rematch/loading": "2.1.2", "@rematch/loading": "2.1.2",
"@sendgrid/mail": "7.7.0", "@sendgrid/mail": "7.7.0",
@@ -65,7 +66,7 @@
"handlebars": "4.7.7", "handlebars": "4.7.7",
"highcharts": "10.3.3", "highcharts": "10.3.3",
"highcharts-react-official": "3.2.0", "highcharts-react-official": "3.2.0",
"lodash": "^4.17.21", "lodash": "4.17.21",
"lowdb": "5.1.0", "lowdb": "5.1.0",
"markdown": "^0.5.0", "markdown": "^0.5.0",
"nanoid": "4.0.1", "nanoid": "4.0.1",
@@ -77,33 +78,31 @@
"react-redux": "8.0.5", "react-redux": "8.0.5",
"react-router": "5.2.1", "react-router": "5.2.1",
"react-router-dom": "5.3.0", "react-router-dom": "5.3.0",
"react-switch": "7.0.0",
"redux": "4.2.1", "redux": "4.2.1",
"redux-thunk": "2.4.2", "redux-thunk": "2.4.2",
"restana": "4.9.7", "restana": "4.9.7",
"semantic-ui-react": "2.1.4",
"serve-static": "1.15.0", "serve-static": "1.15.0",
"slack": "11.0.2", "slack": "11.0.2",
"string-similarity": "^4.0.4", "string-similarity": "^4.0.4",
"vite": "4.1.4", "vite": "4.2.0",
"x-ray": "2.3.4" "x-ray": "2.3.4"
}, },
"devDependencies": { "devDependencies": {
"esmock": "2.1.0", "@babel/core": "7.21.3",
"@babel/core": "7.21.0", "@babel/eslint-parser": "7.21.3",
"@babel/eslint-parser": "7.19.1",
"@babel/preset-env": "7.20.2", "@babel/preset-env": "7.20.2",
"@babel/preset-react": "7.18.6", "@babel/preset-react": "7.18.6",
"chai": "4.3.7", "chai": "4.3.7",
"eslint": "8.36.0", "eslint": "8.36.0",
"eslint-config-prettier": "8.7.0", "eslint-config-prettier": "8.7.0",
"eslint-plugin-react": "7.32.2", "eslint-plugin-react": "7.32.2",
"esmock": "2.1.0",
"history": "5.3.0", "history": "5.3.0",
"husky": "4.3.8", "husky": "4.3.8",
"less": "4.1.3", "less": "4.1.3",
"lint-staged": "13.2.0", "lint-staged": "13.2.0",
"mocha": "10.2.0", "mocha": "10.2.0",
"prettier": "2.8.4", "prettier": "2.8.5",
"redux-logger": "3.0.6" "redux-logger": "3.0.6"
} }
} }

View File

@@ -3,13 +3,10 @@ import React, { useEffect } from 'react';
import InsufficientPermission from './components/permission/InsufficientPermission'; import InsufficientPermission from './components/permission/InsufficientPermission';
import PermissionAwareRoute from './components/permission/PermissionAwareRoute'; import PermissionAwareRoute from './components/permission/PermissionAwareRoute';
import GeneralSettings from './views/generalSettings/GeneralSettings'; import GeneralSettings from './views/generalSettings/GeneralSettings';
import ToastsContainer from './components/toasts/ToastContainer';
import JobMutation from './views/jobs/mutation/JobMutation'; import JobMutation from './views/jobs/mutation/JobMutation';
import UserMutator from './views/user/mutation/UserMutator'; import UserMutator from './views/user/mutation/UserMutator';
import ToastContext from './components/toasts/ToastContext';
import JobInsight from './views/jobs/insights/JobInsight.jsx'; import JobInsight from './views/jobs/insights/JobInsight.jsx';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import useToast from './components/toasts/useToast';
import { Switch, Redirect } from 'react-router-dom'; import { Switch, Redirect } from 'react-router-dom';
import Logout from './components/logout/Logout'; import Logout from './components/logout/Logout';
import Logo from './components/logo/Logo'; import Logo from './components/logo/Logo';
@@ -23,20 +20,21 @@ import './App.less';
export default function FredyApp() { export default function FredyApp() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [showToast, onToastFinished, toasts] = useToast();
const [loading, setLoading] = React.useState(true); const [loading, setLoading] = React.useState(true);
const currentUser = useSelector((state) => state.user.currentUser); const currentUser = useSelector((state) => state.user.currentUser);
useEffect(() => { useEffect(() => {
async function init() { async function init() {
await dispatch.provider.getProvider();
await dispatch.jobs.getJobs();
await dispatch.jobs.getProcessingTimes();
await dispatch.notificationAdapter.getAdapter();
await dispatch.user.getCurrentUser(); await dispatch.user.getCurrentUser();
if (!needsLogin()) {
await dispatch.provider.getProvider();
await dispatch.jobs.getJobs();
await dispatch.jobs.getProcessingTimes();
await dispatch.notificationAdapter.getAdapter();
}
setLoading(false); setLoading(false);
} }
init(); init();
}, [currentUser?.userId]); }, [currentUser?.userId]);
@@ -56,44 +54,41 @@ export default function FredyApp() {
return loading ? null : needsLogin() ? ( return loading ? null : needsLogin() ? (
login() login()
) : ( ) : (
<ToastContext.Provider value={{ showToast }}> <div className="app">
<div className="app"> <div className="app__container">
<div className="app__container"> <Logout />
<Logout /> <Logo width={190} white />
<Logo width={190} white /> <Menu isAdmin={isAdmin()} />
<Menu isAdmin={isAdmin()} /> <Switch>
<ToastsContainer toasts={toasts} onToastFinished={onToastFinished} /> <Route name="Insufficient Permission" path={'/403'} component={InsufficientPermission} />
<Switch> <Route name="Create new Job" path={'/jobs/new'} component={JobMutation} />
<Route name="Insufficient Permission" path={'/403'} component={InsufficientPermission} /> <Route name="Edit a Job" path={'/jobs/edit/:jobId'} component={JobMutation} />
<Route name="Create new Job" path={'/jobs/new'} component={JobMutation} /> <Route name="Insights into a Job" path={'/jobs/insights/:jobId'} component={JobInsight} />
<Route name="Edit a Job" path={'/jobs/edit/:jobId'} component={JobMutation} /> <Route name="Job overview" path={'/jobs'} component={Jobs} />
<Route name="Insights into a Job" path={'/jobs/insights/:jobId'} component={JobInsight} /> <PermissionAwareRoute
<Route name="Job overview" path={'/jobs'} component={Jobs} /> name="Create new User"
<PermissionAwareRoute path="/users/new"
name="Create new User" component={<UserMutator />}
path="/users/new" currentUser={currentUser}
component={<UserMutator />} />
currentUser={currentUser} <PermissionAwareRoute
/> name="Edit a user"
<PermissionAwareRoute path="/users/edit/:userId"
name="Edit a user" component={<UserMutator />}
path="/users/edit/:userId" currentUser={currentUser}
component={<UserMutator />} />
currentUser={currentUser} <PermissionAwareRoute name="Users" path="/users" component={<Users />} currentUser={currentUser} />
/> <PermissionAwareRoute
<PermissionAwareRoute name="Users" path="/users" component={<Users />} currentUser={currentUser} /> name="General Settings"
<PermissionAwareRoute path="/generalSettings"
name="General Settings" component={<GeneralSettings />}
path="/generalSettings" currentUser={currentUser}
component={<GeneralSettings />} />
currentUser={currentUser}
/>
<Redirect from="/" to={'/jobs'} /> <Redirect from="/" to={'/jobs'} />
</Switch> </Switch>
</div>
</div> </div>
</ToastContext.Provider> </div>
); );
} }

View File

@@ -4,11 +4,9 @@
width:100%; width:100%;
&__container { &__container {
width: 100%;
padding: 1rem 1rem; padding: 1rem 1rem;
background-color: #595959f5; color: var(--semi-color-text-0);
color: #f1f1f1; background-color: #232429;
} }
} }
@@ -19,3 +17,27 @@
.ui.black.label, .ui.black.labels .label { .ui.black.label, .ui.black.labels .label {
background-color: #31303078!important; background-color: #31303078!important;
} }
a:link {
color: #54a9ff;
background-color: transparent;
text-decoration: none;
}
a:visited {
color: #54a9ff;
background-color: transparent;
text-decoration: none;
}
a:hover {
color: #54a9ff;
background-color: transparent;
text-decoration: underline;
}
a:active {
color: #54a9ff;
background-color: transparent;
text-decoration: underline;
}

View File

@@ -5,9 +5,11 @@ import { HashRouter } from 'react-router-dom';
import { createHashHistory } from 'history'; import { createHashHistory } from 'history';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import en_US from '@douyinfe/semi-ui/lib/es/locale/source/en_US';
import { LocaleProvider } from '@douyinfe/semi-ui';
const container = document.getElementById('fredy'); const container = document.getElementById('fredy');
const root = createRoot(container); const root = createRoot(container);
const history = createHashHistory(); const history = createHashHistory();
import App from './App'; import App from './App';
@@ -17,7 +19,9 @@ import './Index.less';
root.render( root.render(
<Provider store={reduxStore}> <Provider store={reduxStore}>
<HashRouter history={history}> <HashRouter history={history}>
<App /> <LocaleProvider locale={en_US}>
<App />
</LocaleProvider>
</HashRouter> </HashRouter>
</Provider> </Provider>
); );

View File

@@ -2,5 +2,14 @@ body, html {
margin: 0; margin: 0;
height: 100%; height: 100%;
width: 100%; width: 100%;
background-color: #595959f5; background-color: #232429;
}
.semi-table-row-head{
background-color: #2b2b2b !important;
color: #fff !important;
}
.semi-table-row-cell {
background-color: #333333 !important;
} }

View File

@@ -1,12 +1,11 @@
import React from 'react'; import React from 'react';
import { Header } from 'semantic-ui-react'; import { Typography } from '@douyinfe/semi-ui';
import './Headline.less'; export default function Headline({ text, size = 3 } = {}) {
const { Title } = Typography;
export default function Headline({ text, size = 'medium', className = '' } = {}) {
return ( return (
<Header className={`headline ${className}`} size={size}> <Title heading={size} style={{ marginBottom: '1rem' }}>
{text} {text}
</Header> </Title>
); );
} }

View File

@@ -1,3 +0,0 @@
.headline{
color: #f1f1f1 !important;
}

View File

@@ -1,20 +1,20 @@
import React from 'react'; import React from 'react';
import { Button } from 'semantic-ui-react'; import { Button } from '@douyinfe/semi-ui';
import { xhrPost } from '../../services/xhr'; import { xhrPost } from '../../services/xhr';
import { IconUser } from '@douyinfe/semi-icons';
const Logout = function Logout() { const Logout = function Logout() {
return ( return (
<Button <Button
content="Logout" icon={<IconUser />}
labelPosition="left" type="danger"
icon="user" theme="solid"
size="mini"
onClick={async () => { onClick={async () => {
await xhrPost('/api/login/logout'); await xhrPost('/api/login/logout');
location.reload(); location.reload();
}} }}
negative >
/> Logout
</Button>
); );
}; };

View File

@@ -1,49 +1,54 @@
import React from 'react'; import React from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { Icon, Menu } from 'semantic-ui-react'; import { Tabs, TabPane } from '@douyinfe/semi-ui';
import './Menu.less';
import { useLocation } from 'react-router'; import { useLocation } from 'react-router';
import { IconUser, IconTerminal, IconSetting } from '@douyinfe/semi-icons';
function parsePathName(name) {
const split = name.split('/').filter((s) => s.length !== 0);
return '/' + split[0];
}
const TopMenu = function TopMenu({ isAdmin }) { const TopMenu = function TopMenu({ isAdmin }) {
const history = useHistory(); const history = useHistory();
const location = useLocation(); const location = useLocation();
const isActiveRoute = (name) => location.pathname.indexOf(name) !== -1;
return ( return (
<Menu pointing secondary className="topMenu"> <Tabs type="line" activeKey={parsePathName(location.pathname)} onTabClick={(key) => history.push(key)}>
<Menu.Item <TabPane
name="jobs" itemKey="/jobs"
active={isActiveRoute('jobs')} tab={
className={isActiveRoute('jobs') ? 'topMenu__active' : 'topMenu__item'} <span>
onClick={() => history.push('/jobs')} <IconTerminal />
> Jobs
<Icon name="search" /> Job Configuration </span>
</Menu.Item> }
/>
{isAdmin && ( {isAdmin && (
<Menu.Item <TabPane
name="user" itemKey="/users"
active={isActiveRoute('users')} tab={
className={isActiveRoute('users') ? 'topMenu__active' : 'topMenu__item'} <span>
onClick={() => history.push('/users')} <IconUser />
> User
<Icon name="user" /> User configuration </span>
</Menu.Item> }
/>
)} )}
{isAdmin && ( {isAdmin && (
<Menu.Item <TabPane
name="general" itemKey="/generalSettings"
active={isActiveRoute('general')} tab={
className={isActiveRoute('general') ? 'topMenu__active' : 'topMenu__item'} <span>
onClick={() => history.push('/generalSettings')} <IconSetting />
> General
<Icon name="cog" /> General Settings </span>
</Menu.Item> }
/>
)} )}
</Menu> </Tabs>
); );
}; };

View File

@@ -1,15 +0,0 @@
.topMenu {
border-bottom: 1px solid #b7b7b7f2 !important;
&__active {
border-bottom: 1px solid #06dcfff2 !important;
font-weight: 550 !important;
color: #3ed7ff !important;
margin: 0 0 -1px !important;
}
&__item {
color: #fffffff2 !important;
border-color: transparent !important;
}
}

View File

@@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import { Header } from 'semantic-ui-react';
import insufficientPermission from '../../assets/insufficient_permission.png'; import insufficientPermission from '../../assets/insufficient_permission.png';
export default function InsufficientPermission() { export default function InsufficientPermission() {
@@ -7,9 +6,7 @@ export default function InsufficientPermission() {
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', flexDirection: 'column' }}> <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', flexDirection: 'column' }}>
<img src={insufficientPermission} height={250} /> <img src={insufficientPermission} height={250} />
<br /> <br />
<Header as="h4" inverted> <h4>Insufficient permission :(</h4>
Insufficient permission :(
</Header>
</div> </div>
); );
} }

View File

@@ -1,27 +1,18 @@
import React from 'react'; import React from 'react';
import { Header, Icon, Popup, Segment } from 'semantic-ui-react'; import { Card } from '@douyinfe/semi-ui';
import './SegmentParts.less'; import './SegmentParts.less';
export const SegmentPart = ({ name, icon = null, children, helpText }) => ( export const SegmentPart = ({ name, Icon = null, children, helpText }) => {
<Segment inverted> const { Meta } = Card;
<Header as="h5" inverted sub>
{icon && <Icon name={icon} inverted size="mini" />}
<Header.Content>{name}</Header.Content>
</Header>
<Popup return (
content={helpText} <Card
trigger={ title={
<span className="generalSettings__help"> <Meta title={name} description={helpText} avatar={Icon == null ? null : <Icon size="extra-extra-small" />} />
{' '}
<Icon name="help circle" inverted />
What is this?
</span>
} }
/> >
<Segment inverted className="segmentParts">
{children} {children}
</Segment> </Card>
</Segment> );
); };

View File

@@ -1,66 +1,79 @@
import React, { Fragment } from 'react'; import React from 'react';
import { Table, Button } from 'semantic-ui-react'; import { Button, Empty, Table, Switch } from '@douyinfe/semi-ui';
import Switch from 'react-switch'; import { IconDelete, IconEdit, IconHistogram } from '@douyinfe/semi-icons';
import { IllustrationNoResult, IllustrationNoResultDark } from '@douyinfe/semi-illustrations';
const emptyTable = () => { const empty = (
return ( <Empty
<Table.Row> image={<IllustrationNoResult />}
<Table.Cell collapsing colSpan={6} style={{ textAlign: 'center' }}> darkModeImage={<IllustrationNoResultDark />}
No Data description={'No jobs available'}
</Table.Cell> />
</Table.Row> );
);
};
const content = (jobs, onJobRemoval, onJobStatusChanged, onJobEdit, onJobInsight) => {
return (
<Fragment>
{Object.keys(jobs).map((jobKey) => {
const job = jobs[jobKey];
return (
<Table.Row key={jobKey}>
<Table.Cell collapsing>
<Switch onChange={(checked) => onJobStatusChanged(job.id, checked)} checked={job.enabled} />
</Table.Cell>
<Table.Cell>{job.name}</Table.Cell>
<Table.Cell>{job.numberOfFoundListings || 0}</Table.Cell>
<Table.Cell>{job.provider.length || 0}</Table.Cell>
<Table.Cell>{job.notificationAdapter.length || 0}</Table.Cell>
<Table.Cell>
<div style={{ float: 'right' }}>
<Button circular color="teal" icon="chart line" onClick={() => onJobInsight(job.id)} />
<Button circular color="blue" icon="edit" onClick={() => onJobEdit(job.id)} />
<Button circular color="red" icon="trash" onClick={() => onJobRemoval(job.id)} />
</div>
</Table.Cell>
</Table.Row>
);
})}
</Fragment>
);
};
export default function JobTable({ jobs = {}, onJobRemoval, onJobStatusChanged, onJobEdit, onJobInsight } = {}) { export default function JobTable({ jobs = {}, onJobRemoval, onJobStatusChanged, onJobEdit, onJobInsight } = {}) {
return ( return (
<Table singleLine inverted> <Table
<Table.Header> pagination={false}
<Table.Row> empty={empty}
<Table.HeaderCell /> columns={[
<Table.HeaderCell>Job Name</Table.HeaderCell> {
<Table.HeaderCell>Number of findings</Table.HeaderCell> title: '',
<Table.HeaderCell>Active provider</Table.HeaderCell> dataIndex: '',
<Table.HeaderCell>Active notification adapter</Table.HeaderCell> render: (job) => {
<Table.HeaderCell></Table.HeaderCell> return <Switch onChange={(checked) => onJobStatusChanged(job.id, checked)} checked={job.enabled} />;
</Table.Row> },
</Table.Header> },
{
<Table.Body> title: 'Job Name',
{Object.keys(jobs).length === 0 dataIndex: 'name',
? emptyTable() },
: content(jobs, onJobRemoval, onJobStatusChanged, onJobEdit, onJobInsight)} {
</Table.Body> title: 'Number of findings',
</Table> dataIndex: 'numberOfFoundListings',
render: (value) => {
return value || 0;
},
},
{
title: 'Active provider',
dataIndex: 'provider',
render: (value) => {
return value.length || 0;
},
},
{
title: 'Active notification adapter',
dataIndex: 'notificationAdapter',
render: (value) => {
return value.length || 0;
},
},
{
title: '',
dataIndex: 'tools',
render: (_, job) => {
return (
<div style={{ float: 'right' }}>
<Button
type="primary"
icon={<IconHistogram />}
onClick={() => onJobInsight(job.id)}
style={{ marginRight: '1rem' }}
/>
<Button
type="secondary"
icon={<IconEdit />}
onClick={() => onJobEdit(job.id)}
style={{ marginRight: '1rem' }}
/>
<Button type="danger" icon={<IconDelete />} onClick={() => onJobRemoval(job.id)} />
</div>
);
},
},
]}
dataSource={jobs}
/>
); );
} }

View File

@@ -1,50 +1,38 @@
import React, { Fragment } from 'react'; import React from 'react';
import { Table, Button } from 'semantic-ui-react'; import { Empty, Table, Button } from '@douyinfe/semi-ui';
import { IconDelete, IconEdit } from '@douyinfe/semi-icons';
const emptyTable = () => {
return (
<Table.Row>
<Table.Cell collapsing colSpan="3" style={{ textAlign: 'center' }}>
No Data
</Table.Cell>
</Table.Row>
);
};
const content = (adapterData, onRemove, onEdit) => {
return (
<Fragment>
{adapterData.map((data) => {
return (
<Table.Row key={data.id}>
<Table.Cell>{data.name}</Table.Cell>
<Table.Cell>
<div style={{ float: 'right' }}>
<Button circular color="blue" icon="edit" onClick={() => onEdit(data.id)} />
<Button circular color="red" icon="trash" onClick={() => onRemove(data.id)} />
</div>
</Table.Cell>
</Table.Row>
);
})}
</Fragment>
);
};
export default function NotificationAdapterTable({ notificationAdapter = [], onRemove, onEdit } = {}) { export default function NotificationAdapterTable({ notificationAdapter = [], onRemove, onEdit } = {}) {
return ( return (
<Table singleLine inverted> <Table
<Table.Header> pagination={false}
<Table.Row> empty={<Empty description="No Data" />}
<Table.HeaderCell>Notification Adapter Name</Table.HeaderCell> columns={[
<Table.HeaderCell></Table.HeaderCell> {
</Table.Row> title: 'Notification Adapter Name',
</Table.Header> dataIndex: 'name',
},
<Table.Body> {
{notificationAdapter.length === 0 ? emptyTable() : content(notificationAdapter, onRemove, onEdit)} title: '',
</Table.Body> dataIndex: 'tools',
</Table> render: (_, record) => {
return (
<div style={{ float: 'right' }}>
<Button
type="secondary"
icon={<IconEdit />}
onClick={() => onEdit(record.id)}
style={{ marginRight: '1rem' }}
/>
<Button type="danger" icon={<IconDelete />} onClick={() => onRemove(record.id)} />
</div>
);
},
},
]}
dataSource={notificationAdapter}
/>
); );
} }

View File

@@ -1,53 +1,42 @@
import React, { Fragment } from 'react'; import React from 'react';
import { Table, Button } from 'semantic-ui-react'; import { Empty, Table, Button } from '@douyinfe/semi-ui';
import { IconDelete } from '@douyinfe/semi-icons';
const emptyTable = () => {
return (
<Table.Row>
<Table.Cell collapsing colSpan="3" style={{ textAlign: 'center' }}>
No Data
</Table.Cell>
</Table.Row>
);
};
const content = (providerData, onRemove) => {
return (
<Fragment>
{providerData.map((data) => {
return (
<Table.Row key={data.id}>
<Table.Cell>{data.name}</Table.Cell>
<Table.Cell>
<a href={data.url} target="_blank" rel="noopener noreferrer">
Visit site
</a>
</Table.Cell>
<Table.Cell>
<div style={{ float: 'right' }}>
<Button circular color="red" icon="trash" onClick={() => onRemove(data.id)} />
</div>
</Table.Cell>
</Table.Row>
);
})}
</Fragment>
);
};
export default function ProviderTable({ providerData = [], onRemove } = {}) { export default function ProviderTable({ providerData = [], onRemove } = {}) {
return ( return (
<Table singleLine inverted> <Table
<Table.Header> pagination={false}
<Table.Row> empty={<Empty description="No Provider available" />}
<Table.HeaderCell>Provider Name</Table.HeaderCell> columns={[
<Table.HeaderCell>Url</Table.HeaderCell> {
<Table.HeaderCell></Table.HeaderCell> title: 'Provider Name',
</Table.Row> dataIndex: 'name',
</Table.Header> },
{
<Table.Body>{providerData.length === 0 ? emptyTable() : content(providerData, onRemove)}</Table.Body> title: 'Provider Url',
</Table> dataIndex: 'url',
render: (_, data) => {
return (
<a href={data.url} target="_blank" rel="noopener noreferrer">
Visit site
</a>
);
},
},
{
title: '',
dataIndex: 'tools',
render: (_, record) => {
return (
<div style={{ float: 'right' }}>
<Button type="danger" icon={<IconDelete />} onClick={() => onRemove(record.id)} />
</div>
);
},
},
]}
dataSource={providerData}
/>
); );
} }

View File

@@ -1,49 +1,58 @@
import React from 'react'; import React from 'react';
import { Table, Button } from 'semantic-ui-react'; import { IllustrationNoResult, IllustrationNoResultDark } from '@douyinfe/semi-illustrations';
import { format } from '../../services/time/timeService'; import { format } from '../../services/time/timeService';
import { Table, Button, Empty } from '@douyinfe/semi-ui';
import { IconDelete, IconEdit } from '@douyinfe/semi-icons';
const emptyTable = () => { const empty = (
return ( <Empty
<Table.Row> image={<IllustrationNoResult />}
<Table.Cell collapsing colSpan={4} style={{ textAlign: 'center' }}> darkModeImage={<IllustrationNoResultDark />}
No Data description={'No user available'}
</Table.Cell> />
</Table.Row> );
);
};
const content = (user, onUserRemoval, onUserEdit) => {
return user.map((user) => {
return (
<Table.Row key={user.id}>
<Table.Cell>{user.username}</Table.Cell>
<Table.Cell>{user.lastLogin == null ? '---' : format(user.lastLogin)}</Table.Cell>
<Table.Cell>{user.numberOfJobs}</Table.Cell>
<Table.Cell>
<div style={{ float: 'right' }}>
<Button circular color="red" icon="trash" onClick={() => onUserRemoval(user.id)} />
<Button circular color="blue" icon="edit" onClick={() => onUserEdit(user.id)} />
</div>
</Table.Cell>
</Table.Row>
);
});
};
export default function UserTable({ user = [], onUserRemoval, onUserEdit } = {}) { export default function UserTable({ user = [], onUserRemoval, onUserEdit } = {}) {
return ( return (
<Table inverted> <Table
<Table.Header> pagination={false}
<Table.Row> empty={empty}
<Table.HeaderCell>Username</Table.HeaderCell> columns={[
<Table.HeaderCell>Last login</Table.HeaderCell> {
<Table.HeaderCell>Number of jobs</Table.HeaderCell> title: 'Username',
<Table.HeaderCell></Table.HeaderCell> dataIndex: 'username',
</Table.Row> },
</Table.Header> {
title: 'Last login',
<Table.Body>{user.length === 0 ? emptyTable() : content(user, onUserRemoval, onUserEdit)}</Table.Body> dataIndex: 'lastLogin',
</Table> render: (value) => {
return format(value);
},
},
{
title: 'Number of jobs',
dataIndex: 'numberOfJobs',
},
{
title: '',
dataIndex: 'tools',
render: (value, user) => {
return (
<div style={{ float: 'right' }}>
<Button
type="danger"
icon={<IconDelete />}
onClick={() => onUserRemoval(user.id)}
style={{ marginRight: '1rem' }}
/>
<Button type="primary" icon={<IconEdit />} onClick={() => onUserEdit(user.id)} />
</div>
);
},
},
]}
dataSource={user}
/>
); );
} }

View File

@@ -1,27 +0,0 @@
import React from 'react';
import './Toasts.css';
export default function Toast({ id, delay = 5500, message, onHide, backgroundColor, color, title }) {
const [className, setClassname] = React.useState('toast-container show-toast');
React.useEffect(() => {
let hideTimeout = null;
const timeout = setTimeout(() => {
setClassname('toast-container hide-toast');
hideTimeout = setTimeout(() => {
onHide && onHide(id);
}, 500);
}, delay);
return () => {
clearTimeout(timeout);
clearTimeout(hideTimeout);
};
}, [id, delay, onHide]);
return (
<div className={className} style={{ backgroundColor, color }}>
<h5>{title}</h5>
{message}
</div>
);
}

View File

@@ -1,12 +0,0 @@
import Toast from './Toast';
import React from 'react';
export default function ToastsContainer({ toasts, onToastFinished }) {
return (
<div className="toasts-container">
{toasts.map((toast, index) => (
<Toast key={index} {...toast} onHide={onToastFinished} />
))}
</div>
);
}

View File

@@ -1,7 +0,0 @@
import { createContext } from 'react';
const CheckoutDrawerContext = createContext({
showToast: () => {},
});
export default CheckoutDrawerContext;

View File

@@ -1,63 +0,0 @@
.toasts-container {
position: fixed;
z-index: 65535;
right: 0;
max-width: 250px;
display: flex;
flex-direction: column-reverse;
}
.toasts-container > .toast-container {
margin-bottom: 10px;
}
.toasts-container:last-child {
margin-bottom: 0;
}
.toast-container {
visibility: hidden;
position: relative;
z-index: 65535;
right: -1000px;
background-color: skyblue;
border-radius: 10px;
padding: 10px;
min-width: 10rem;
min-height: 3rem;
}
.toast-container.show-toast {
visibility: visible;
right: 24px;
animation: slidein 0.5s;
}
.toast-container.hide-toast {
visibility: visible;
animation: slideout 0.5s;
}
@keyframes slidein {
from {
right: -1000px;
opacity: 0;
}
to {
right: 24px;
opacity: 1;
}
}
@keyframes slideout {
from {
right: 24px;
opacity: 1;
}
to {
right: -1000px;
opacity: 0;
}
}

View File

@@ -1,23 +0,0 @@
import React from 'react';
export default function useToast() {
const [toasts, setToasts] = React.useState([]);
const showToast = ({ message, delay, color, backgroundColor, title }) => {
const toast = {
id: toasts.length,
message,
delay,
backgroundColor,
color,
title,
};
setToasts([...toasts, toast].reverse());
};
const onToastFinished = (id) => {
setToasts(toasts.filter((toast) => toast.id !== id));
};
return [showToast, onToastFinished, toasts];
}

View File

@@ -2,14 +2,32 @@ import React from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Button, Form, Icon, Message, Segment, Radio } from 'semantic-ui-react'; import { Divider, Input, Radio, TimePicker, Button, RadioGroup } from '@douyinfe/semi-ui';
import ToastContext from '../../components/toasts/ToastContext'; import { InputNumber } from '@douyinfe/semi-ui';
import Headline from '../../components/headline/Headline'; import Headline from '../../components/headline/Headline';
import { xhrPost } from '../../services/xhr'; import { xhrPost } from '../../services/xhr';
import { SegmentPart } from '../../components/segment/SegmentPart'; import { SegmentPart } from '../../components/segment/SegmentPart';
import { Banner, Toast } from '@douyinfe/semi-ui';
import { IconSave, IconCalendar, IconKey, IconRefresh, IconSignal } from '@douyinfe/semi-icons';
import './GeneralSettings.less'; import './GeneralSettings.less';
const GeneralSettings = function Users() { function formatFromTimestamp(ts) {
const date = new Date(ts);
return `${date.getHours()}:${date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()}`;
}
function formatFromTBackend(time) {
if (time == null || time.length === 0) {
return null;
}
const date = new Date();
const split = time.split(':');
date.setHours(split[0]);
date.setMinutes(split[1]);
return date.getTime();
}
const GeneralSettings = function GeneralSettings() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [loading, setLoading] = React.useState(true); const [loading, setLoading] = React.useState(true);
@@ -21,13 +39,12 @@ const GeneralSettings = function Users() {
const [scrapingAntProxy, setScrapingAntProxy] = React.useState(''); const [scrapingAntProxy, setScrapingAntProxy] = React.useState('');
const [workingHourFrom, setWorkingHourFrom] = React.useState(null); const [workingHourFrom, setWorkingHourFrom] = React.useState(null);
const [workingHourTo, setWorkingHourTo] = React.useState(null); const [workingHourTo, setWorkingHourTo] = React.useState(null);
const ctx = React.useContext(ToastContext);
React.useEffect(() => { React.useEffect(() => {
async function init() { async function init() {
await dispatch.generalSettings.getGeneralSettings(); await dispatch.generalSettings.getGeneralSettings();
setLoading(false); setLoading(false);
} }
init(); init();
}, []); }, []);
@@ -40,19 +57,18 @@ const GeneralSettings = function Users() {
setWorkingHourTo(settings?.workingHours?.to); setWorkingHourTo(settings?.workingHours?.to);
setScrapingAntProxy(settings?.scrapingAnt?.proxy || 'datacenter'); setScrapingAntProxy(settings?.scrapingAnt?.proxy || 'datacenter');
} }
init(); init();
}, [settings]); }, [settings]);
const nullOrEmpty = (val) => val == null || val.length === 0; const nullOrEmpty = (val) => val == null || val.length === 0;
const throwMessage = (message, type) => { const throwMessage = (message, type) => {
ctx.showToast({ if (type === 'error') {
title: type === 'error' ? 'Error' : 'Success', Toast.error(message);
message: message, } else {
delay: 5000, Toast.success(message);
backgroundColor: type === 'error' ? '#db2828' : '#87eb8f', }
color: type === 'error' ? '#fff' : '#000',
});
}; };
const onStore = async () => { const onStore = async () => {
@@ -97,139 +113,130 @@ const GeneralSettings = function Users() {
{!loading && ( {!loading && (
<React.Fragment> <React.Fragment>
<Headline text="General Settings" /> <Headline text="General Settings" />
<Message className="generalSettings__message"> <Banner
<h5> fullMode={false}
<Icon name="info circle" /> type="info"
Info closeIcon={null}
</h5> title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>Info</div>}
<p>If you change any settings, you must restart Fredy afterwards.</p> style={{ marginBottom: '1rem' }}
</Message> description="If you change any settings, you must restart Fredy afterwards."
<Form> />
<div>
<SegmentPart <SegmentPart
name="Interval" name="Interval"
helpText="Interval in minutes for running queries against the configured services." helpText="Interval in minutes for running queries against the configured services."
icon="refresh" Icon={IconRefresh}
> >
<Form.Input <InputNumber
type="number" min={0}
min="0" max={1440}
max="1440"
placeholder="Interval in minutes" placeholder="Interval in minutes"
inverted value={interval}
size="mini" formatter={(value) => `${value}`.replace(/\D/g, '')}
width={6} onChange={(value) => setInterval(value)}
defaultValue={interval} suffix={'minutes'}
onChange={(e) => setInterval(e.target.value)}
/> />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart name="Port" helpText="Port on which Fredy is running." icon="connectdevelop"> <SegmentPart name="Port" helpText="Port on which Fredy is running." Icon={IconSignal}>
<Form.Input <InputNumber
type="number" min={0}
min="0" max={99999}
max="99999"
placeholder="Port" placeholder="Port"
inverted value={port}
size="mini" formatter={(value) => `${value}`.replace(/\D/g, '')}
width={6} onChange={(value) => setPort(value)}
defaultValue={port}
onChange={(e) => setPort(e.target.value)}
/> />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart <SegmentPart
name="ScrapingAnt Api Key" name="ScrapingAnt Api Key"
helpText="The api key for ScrapingAnt is used to be able to scrape Immoscout." helpText="The api key for ScrapingAnt is used to be able to scrape Immoscout."
icon="key" Icon={IconKey}
> >
<Form.Input <Input
type="text" type="text"
placeholder="ScrapingAnt Api Key" placeholder="ScrapingAnt Api Key"
inverted value={scrapingAntApiKey}
size="mini" onChange={(val) => setScrapingAntApiKey(val)}
width={6}
defaultValue={scrapingAntApiKey}
onChange={(e) => setScrapingAntApiKey(e.target.value)}
/> />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart <SegmentPart
name="ScrapingAnt proxy settings" name="ScrapingAnt proxy settings"
helpText="Scraping ant provides different proxies." helpText="Scraping ant provides different proxies."
icon="key" Icon={IconKey}
> >
<Message info> <Banner
ScrapingAnt is needed to scrape Immoscout. ScrapingAnt itself is using 2 different types of proxies.{' '} fullMode={false}
<br /> type="info"
<h4>Datacenter-Proxy</h4> closeIcon={null}
Proxy server located in one of the datacenters across the world. Datacenter proxies are slower and more title={
likely to fail, but they are cheaper. A call with a datacenter proxy cost 10 credits. <div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>
<h4>Residential-Proxy</h4> ScrapingAnt is needed to scrape Immoscout. ScrapingAnt itself is using 2 different types of proxies
High-quality proxy server located in one of the real people houses across the world. Datacenter proxies </div>
are faster and more likely to success, but they are more expensive. A call with a datacenter proxy cost }
250 credits. style={{ marginBottom: '1rem' }}
<br /> description={
<br /> <div>
<b> <h4>Datacenter-Proxy</h4>
On the free tier, you have 10.000 credits, so chose your option wisely. Keep in mind, only successful Proxy server located in one of the datacenters across the world. Datacenter proxies are slower and
calls will be charged. more likely to fail, but they are cheaper. A call with a datacenter proxy cost 10 credits.
</b> <h4>Residential-Proxy</h4>
</Message> High-quality proxy server located in one of the real people houses across the world. Datacenter
<Form.Field> proxies are faster and more likely to success, but they are more expensive. A call with a datacenter
<Radio proxy cost 250 credits.
label="Datacenter proxy" <br />
name="scrapingAntProxy" <br />
value="datacenter" <b>
checked={scrapingAntProxy === 'datacenter'} On the free tier, you have 10.000 credits, so chose your option wisely. Keep in mind, only
onChange={(e, { value }) => setScrapingAntProxy(value)} successful calls will be charged.
/> </b>
</Form.Field> </div>
<Form.Field> }
<Radio />
label="Residential proxy"
name="scrapingAntProxy"
value="residential"
checked={scrapingAntProxy === 'residential'}
onChange={(e, { value }) => setScrapingAntProxy(value)}
/>
</Form.Field>
</SegmentPart>
<RadioGroup value={scrapingAntProxy} onChange={(e) => setScrapingAntProxy(e.target.value)}>
<Radio name="datacenter" value="datacenter" checked={scrapingAntProxy === 'datacenter'}>
Datacenter proxy
</Radio>
<Radio name="residential" value="residential" checked={scrapingAntProxy === 'residential'}>
Residential proxy
</Radio>
</RadioGroup>
</SegmentPart>
<Divider margin="1rem" />
<SegmentPart <SegmentPart
name="Working hours" name="Working hours"
helpText="During this hours, Fredy will search for new apartments. If nothing is configured, Fredy will search around the clock." helpText="During this hours, Fredy will search for new apartments. If nothing is configured, Fredy will search around the clock."
icon="calendar outline" Icon={IconCalendar}
> >
<div className="generalSettings__timePickerContainer"> <div className="generalSettings__timePickerContainer">
<Form.Input <TimePicker
className="generalSettings__time" format={'HH:mm'}
type="time" insetLabel="From"
placeholder="Working hours from" value={formatFromTBackend(workingHourFrom)}
inverted placeholder=""
size="mini" onChange={(val) => {
width={2} setWorkingHourFrom(val == null ? null : formatFromTimestamp(val));
defaultValue={workingHourFrom} }}
onChange={(e) => setWorkingHourFrom(e.target.value)}
/> />
<div className="generalSettings__until">until</div> <TimePicker
<Form.Input format={'HH:mm'}
type="time" insetLabel="Until"
placeholder="Working hours to" value={formatFromTBackend(workingHourTo)}
inverted placeholder=""
size="mini" onChange={(val) => {
width={2} setWorkingHourTo(val == null ? null : formatFromTimestamp(val));
defaultValue={workingHourTo} }}
onChange={(e) => setWorkingHourTo(e.target.value)}
/> />
</div> </div>
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<Segment inverted floated="right"> <Button type="primary" theme="solid" onClick={onStore} icon={<IconSave />}>
<Button color="teal" onClick={onStore}> Save
Save </Button>
</Button> </div>
</Segment>
</Form>
</React.Fragment> </React.Fragment>
)} )}
</div> </div>

View File

@@ -2,11 +2,7 @@
&__timePickerContainer { &__timePickerContainer {
display: flex; display: flex;
align-items: baseline; align-items: baseline;
} gap: 1rem;
&__until {
margin-left: 1rem;
margin-right: 1rem;
} }
&__help{ &__help{
@@ -14,8 +10,4 @@
margin-left: 1rem; margin-left: 1rem;
} }
&__message{
background: #8fe8ff!important;
}
} }

View File

@@ -1,13 +1,12 @@
import React from 'react'; import React from 'react';
import ToastContext from '../../components/toasts/ToastContext';
import JobTable from '../../components/table/JobTable'; import JobTable from '../../components/table/JobTable';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { xhrDelete, xhrPut } from '../../services/xhr'; import { xhrDelete, xhrPut } from '../../services/xhr';
import { Button, Icon } from 'semantic-ui-react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import ProcessingTimes from './ProcessingTimes'; import ProcessingTimes from './ProcessingTimes';
import { Button, Toast } from '@douyinfe/semi-ui';
import { IconPlusCircle } from '@douyinfe/semi-icons';
import './Jobs.less'; import './Jobs.less';
export default function Jobs() { export default function Jobs() {
@@ -15,49 +14,24 @@ export default function Jobs() {
const processingTimes = useSelector((state) => state.jobs.processingTimes); const processingTimes = useSelector((state) => state.jobs.processingTimes);
const history = useHistory(); const history = useHistory();
const dispatch = useDispatch(); const dispatch = useDispatch();
const ctx = React.useContext(ToastContext);
const onJobRemoval = async (jobId) => { const onJobRemoval = async (jobId) => {
try { try {
await xhrDelete('/api/jobs', { jobId }); await xhrDelete('/api/jobs', { jobId });
ctx.showToast({ Toast.success('Job successfully remove');
title: 'Success',
message: 'Job successfully remove',
delay: 5000,
backgroundColor: '#87eb8f',
color: '#000',
});
await dispatch.jobs.getJobs(); await dispatch.jobs.getJobs();
} catch (error) { } catch (error) {
ctx.showToast({ Toast.error(error);
title: 'Error',
message: error,
delay: 35000,
backgroundColor: '#db2828',
color: '#fff',
});
} }
}; };
const onJobStatusChanged = async (jobId, status) => { const onJobStatusChanged = async (jobId, status) => {
try { try {
await xhrPut(`/api/jobs/${jobId}/status`, { status }); await xhrPut(`/api/jobs/${jobId}/status`, { status });
ctx.showToast({ Toast.success('Job status successfully changed');
title: 'Success',
message: 'Job status successfully changed',
delay: 5000,
backgroundColor: '#87eb8f',
color: '#000',
});
await dispatch.jobs.getJobs(); await dispatch.jobs.getJobs();
} catch (error) { } catch (error) {
ctx.showToast({ Toast.error(error);
title: 'Error',
message: error,
delay: 35000,
backgroundColor: '#db2828',
color: '#fff',
});
} }
}; };
@@ -65,8 +39,12 @@ export default function Jobs() {
<div> <div>
<div> <div>
{processingTimes != null && <ProcessingTimes processingTimes={processingTimes} />} {processingTimes != null && <ProcessingTimes processingTimes={processingTimes} />}
<Button primary className="jobs__newButton" onClick={() => history.push('/jobs/new')}> <Button
<Icon name="plus" /> type="primary"
icon={<IconPlusCircle />}
className="jobs__newButton"
onClick={() => history.push('/jobs/new')}
>
New Job New Job
</Button> </Button>
</div> </div>

View File

@@ -1,51 +1,67 @@
import React from 'react'; import React from 'react';
import { format } from '../../services/time/timeService'; import { format } from '../../services/time/timeService';
import { Header, Label, Message, Segment } from 'semantic-ui-react'; import { Card, Descriptions, Divider } from '@douyinfe/semi-ui';
import { IconBolt } from '@douyinfe/semi-icons';
export default function ProcessingTimes({ processingTimes }) { export default function ProcessingTimes({ processingTimes }) {
const { Meta } = Card;
return ( return (
<React.Fragment> <>
<div> <Descriptions
<Label as="span" color="black"> row
Processing Interval: size="small"
<Label.Detail>{processingTimes.interval} min</Label.Detail> style={{
</Label> backgroundColor: '#35363c',
borderRadius: '4px',
padding: '10px',
}}
>
<Descriptions.Item itemKey="Processing Interval">{processingTimes.interval} min</Descriptions.Item>
{processingTimes.lastRun && ( {processingTimes.lastRun && (
<React.Fragment> <>
<Label as="span" color="black"> <Descriptions.Item itemKey="Last run">{format(processingTimes.lastRun)}</Descriptions.Item>
Last run: <Descriptions.Item itemKey="Next run">
<Label.Detail>{format(processingTimes.lastRun)}</Label.Detail> {format(processingTimes.lastRun + processingTimes.interval * 60000)}
</Label> </Descriptions.Item>
<Label as="span" color="black"> </>
Next run:
<Label.Detail>{format(processingTimes.lastRun + processingTimes.interval * 60000)}</Label.Detail>
</Label>
</React.Fragment>
)} )}
</div> </Descriptions>
{processingTimes.scrapingAntData != null && ( {processingTimes.scrapingAntData != null && (
<Segment inverted> <>
<Header as="h5">Remaining ScrapingAnt calls</Header> <Divider margin="1rem" />
<Message.List> <Card
<Message.Item>Plan: {processingTimes.scrapingAntData.plan_name}</Message.Item> style={{ backgroundColor: '#35363c' }}
<Message.Item> title={
<Meta
title="Remaining ScrapingAnt calls"
description="Information about your Scraping Ant Plan"
avatar={<IconBolt />}
/>
}
>
<p>Plan: {processingTimes.scrapingAntData.plan_name}</p>
<p>
Duration: {format(new Date(processingTimes.scrapingAntData.start_date))} -{' '} Duration: {format(new Date(processingTimes.scrapingAntData.start_date))} -{' '}
{format(new Date(processingTimes.scrapingAntData.end_date))} {format(new Date(processingTimes.scrapingAntData.end_date))}
</Message.Item> <br />
<Message.Item>
Credits: {processingTimes.scrapingAntData.remained_credits}/ Credits: {processingTimes.scrapingAntData.remained_credits}/
{processingTimes.scrapingAntData.plan_total_credits} (250 credits per call) {processingTimes.scrapingAntData.plan_total_credits} (250 credits per call)
</Message.Item> </p>
</Message.List> If you want to scrape Immoscout more often, you have to purchase a premium account of{' '}
If you want to scrape Immoscout more often, you have to purchase a premium account of{' '} <a href="https://scrapingant.com/" target="_blank" rel="noreferrer">
<a href="https://scrapingant.com/" target="_blank" rel="noreferrer"> ScrapingAnt
{' '} </a>
ScrapingAnt . You can use the code <b>FREDY10</b> to get 10% off. (No affiliation, we are <b>not</b> getting paid to
</a> recommend ScrapingAnt.)
. You can use the code <b>FREDY10</b> to get 10% off. (No affiliation, we are <b>not</b> getting paid to </Card>
recommend ScrapingAnt.) </>
</Segment>
)} )}
</React.Fragment> </>
); );
} }
/*
*/

View File

@@ -2,19 +2,17 @@ import React, { Fragment, useState } from 'react';
import NotificationAdapterMutator from './components/notificationAdapter/NotificationAdapterMutator'; import NotificationAdapterMutator from './components/notificationAdapter/NotificationAdapterMutator';
import NotificationAdapterTable from '../../../components/table/NotificationAdapterTable'; import NotificationAdapterTable from '../../../components/table/NotificationAdapterTable';
import { Icon, Form, Button, Label } from 'semantic-ui-react';
import ProviderTable from '../../../components/table/ProviderTable'; import ProviderTable from '../../../components/table/ProviderTable';
import ProviderMutator from './components/provider/ProviderMutator'; import ProviderMutator from './components/provider/ProviderMutator';
import ToastContext from '../../../components/toasts/ToastContext';
import Headline from '../../../components/headline/Headline'; import Headline from '../../../components/headline/Headline';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { xhrPost } from '../../../services/xhr'; import { xhrPost } from '../../../services/xhr';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { useParams } from 'react-router'; import { useParams } from 'react-router';
import { Divider, Input, Switch, Button, TagInput, Toast } from '@douyinfe/semi-ui';
import './JobMutation.less'; import './JobMutation.less';
import Switch from 'react-switch';
import { SegmentPart } from '../../../components/segment/SegmentPart'; import { SegmentPart } from '../../../components/segment/SegmentPart';
import { IconPlusCircle } from '@douyinfe/semi-icons';
export default function JobMutator() { export default function JobMutator() {
const jobs = useSelector((state) => state.jobs.jobs); const jobs = useSelector((state) => state.jobs.jobs);
@@ -38,7 +36,6 @@ export default function JobMutator() {
const [enabled, setEnabled] = useState(defaultEnabled); const [enabled, setEnabled] = useState(defaultEnabled);
const history = useHistory(); const history = useHistory();
const dispatch = useDispatch(); const dispatch = useDispatch();
const ctx = React.useContext(ToastContext);
const isSavingEnabled = () => { const isSavingEnabled = () => {
return notificationAdapterData.length > 0 && providerData.length > 0 && name != null && name.length > 0; return notificationAdapterData.length > 0 && providerData.length > 0 && name != null && name.length > 0;
@@ -55,24 +52,11 @@ export default function JobMutator() {
jobId: jobToBeEdit?.id || null, jobId: jobToBeEdit?.id || null,
}); });
await dispatch.jobs.getJobs(); await dispatch.jobs.getJobs();
ctx.showToast({ Toast.success('Job successfully saved...');
title: 'Success',
message: 'Job successfully saved...',
delay: 5000,
backgroundColor: '#87eb8f',
color: '#000',
});
history.push('/jobs'); history.push('/jobs');
} catch (Exception) { } catch (Exception) {
console.error(Exception.json.message); console.error(Exception.json.message);
Toast.error(Exception.json != null ? Exception.json.message : Exception);
ctx.showToast({
title: 'Error',
message: Exception.json != null ? Exception.json.message : Exception,
delay: 8000,
backgroundColor: '#db2828',
color: '#fff',
});
} }
}; };
@@ -107,20 +91,19 @@ export default function JobMutator() {
)} )}
<Headline text={jobToBeEdit ? 'Edit a Job' : 'Create a new Job'} /> <Headline text={jobToBeEdit ? 'Edit a Job' : 'Create a new Job'} />
<Form> <form>
<SegmentPart name="Name"> <SegmentPart name="Name">
<Form.Input <Input
autofocus
type="text" type="text"
maxLength={40} maxLength={40}
placeholder="Name" placeholder="Name"
autoFocus
inverted
width={6} width={6}
defaultValue={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(value) => setName(value)}
/> />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart <SegmentPart
name="Provider" name="Provider"
icon="briefcase" icon="briefcase"
@@ -130,10 +113,14 @@ export default function JobMutator() {
'to search for new listings.' 'to search for new listings.'
} }
> >
<Form.Button primary className="jobMutation__newButton" onClick={() => setProviderCreationVisibility(true)}> <Button
<Icon name="plus" /> type="primary"
icon={<IconPlusCircle />}
className="jobMutation__newButton"
onClick={() => setProviderCreationVisibility(true)}
>
Add new Provider Add new Provider
</Form.Button> </Button>
<ProviderTable <ProviderTable
providerData={providerData} providerData={providerData}
@@ -142,20 +129,20 @@ export default function JobMutator() {
}} }}
/> />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart <SegmentPart
icon="bell" icon="bell"
name="Notification Adapter" name="Notification Adapter"
helpText="Fredy supports multiple ways to notify you about new findings. These are called notification adapter. You can chose between email, Telegram etc." helpText="Fredy supports multiple ways to notify you about new findings. These are called notification adapter. You can chose between email, Telegram etc."
> >
<Form.Button <Button
primary type="primary"
className="jobMutation__newButton" className="jobMutation__newButton"
icon={<IconPlusCircle />}
onClick={() => setNotificationCreationVisibility(true)} onClick={() => setNotificationCreationVisibility(true)}
> >
<Icon name="plus" />
Add new Notification Adapter Add new Notification Adapter
</Form.Button> </Button>
<NotificationAdapterTable <NotificationAdapterTable
notificationAdapter={notificationAdapterData} notificationAdapter={notificationAdapterData}
@@ -169,40 +156,19 @@ export default function JobMutator() {
}} }}
/> />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart <SegmentPart
icon="bell" icon="bell"
name="Blacklist" name="Blacklist"
helpText="If a listing contains one of these words, it will be filtered out. Words must be comma separated. To remove a word from the black list, just click the red label(s)." helpText="If a listing contains one of these words, it will be filtered out. Type in a word, then hit enter."
> >
<Form.Input <TagInput
type="text" value={blacklist || []}
maxLength={40} placeholder="Add a word for filtering..."
placeholder="Comma separated list of blacklisted words" onChange={(v) => setBlacklist([...v])}
autoFocus
inverted
width={6}
onChange={(e) => {
if (e.target.value.indexOf(',') !== -1) {
setBlacklist([...blacklist, e.target.value.replace(',', '')]);
e.target.value = '';
}
}}
/> />
{blacklist.map((blacklistWord) => (
<Label
as="a"
key={`blacklist_${blacklistWord}`}
onClick={(e, obj) => {
setBlacklist(blacklist.filter((word) => word !== obj.content));
}}
content={blacklistWord}
icon="thumbs down"
color="red"
/>
))}
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart <SegmentPart
icon="play circle outline" icon="play circle outline"
name="Job activation" name="Job activation"
@@ -210,14 +176,14 @@ export default function JobMutator() {
> >
<Switch className="jobMutation__spaceTop" onChange={(checked) => setEnabled(checked)} checked={enabled} /> <Switch className="jobMutation__spaceTop" onChange={(checked) => setEnabled(checked)} checked={enabled} />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<Button color="red" onClick={() => history.push('/jobs')}> <Button type="danger" style={{ marginRight: '1rem' }} onClick={() => history.push('/jobs')}>
Cancel Cancel
</Button> </Button>
<Button color="green" disabled={!isSavingEnabled()} onClick={mutateJob}> <Button type="primary" icon={<IconPlusCircle />} disabled={!isSavingEnabled()} onClick={mutateJob}>
Save Save
</Button> </Button>
</Form> </form>
</Fragment> </Fragment>
); );
} }

View File

@@ -1,5 +1,10 @@
.jobMutation { .jobMutation {
&__newButton{ &__newButton{
float: right; float: right;
margin-bottom: 1rem;
} }
} }
.semi-select-option-list-wrapper {
width: 25rem;
}

View File

@@ -1,11 +1,10 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { transform } from '../../../../../services/transformer/notificationAdapterTransformer'; import { transform } from '../../../../../services/transformer/notificationAdapterTransformer';
import { Modal, Form, Button, Dropdown, Input, Message } from 'semantic-ui-react';
import { xhrPost } from '../../../../../services/xhr'; import { xhrPost } from '../../../../../services/xhr';
import Help from './NotificationHelpDisplay'; import Help from './NotificationHelpDisplay';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import Switch from 'react-switch'; import { Banner, Button, Form, Modal, Select, Switch } from '@douyinfe/semi-ui';
import './NotificationAdapterMutator.less'; import './NotificationAdapterMutator.less';
@@ -138,8 +137,7 @@ export default function NotificationAdapterMutator({
const uiElement = selectedAdapter.fields[key]; const uiElement = selectedAdapter.fields[key];
return ( return (
<Form.Field key={uiElement.description}> <Form key={key}>
<label>{uiElement.label}:</label>
{uiElement.type === 'boolean' ? ( {uiElement.type === 'boolean' ? (
<Switch <Switch
checked={uiElement.value || false} checked={uiElement.value || false}
@@ -148,106 +146,108 @@ export default function NotificationAdapterMutator({
}} }}
/> />
) : ( ) : (
<Input <Form.Input
style={{ width: '100%' }}
field={uiElement.label}
type={uiElement.type} type={uiElement.type}
value={uiElement.value || ''} value={uiElement.value || ''}
placeholder={uiElement.label} placeholder={uiElement.label}
onChange={(e) => { label={uiElement.label}
setValue(selectedAdapter, uiElement, key, e.target.value); onChange={(value) => {
setValue(selectedAdapter, uiElement, key, value);
}} }}
/> />
)} )}
</Form.Field> </Form>
); );
}); });
}; };
return ( return (
<Modal <Modal
onClose={() => onVisibilityChanged(false)} title="Adding a new Notification Adapter"
onOpen={() => onVisibilityChanged(true)} visible={visible}
open={visible}
style={{ width: '95%' }} style={{ width: '95%' }}
footer={
<div>
<Button type="secondary" disabled={selectedAdapter == null} style={{ float: 'left' }} onClick={() => onTry()}>
Try
</Button>
<Button type="danger" onClick={() => onSubmit(true)}>
Save
</Button>
<Button type="primary" onClick={() => onSubmit(false)}>
Cancel
</Button>
</div>
}
> >
<Modal.Header>Adding a new Notification Adapter</Modal.Header> {validationMessage != null && (
<Modal.Content image> <Banner
<Modal.Description> fullMode={false}
{validationMessage != null && ( type="danger"
<Message negative> closeIcon={null}
<Message.Header>Houston we have a problem...</Message.Header> title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>Error</div>}
<p dangerouslySetInnerHTML={{ __html: validationMessage }} /> style={{ marginBottom: '1rem' }}
</Message> description={<p dangerouslySetInnerHTML={{ __html: validationMessage }} />}
)}
{successMessage != null && (
<Message positive>
<Message.Header>Yay!</Message.Header>
<p dangerouslySetInnerHTML={{ __html: successMessage }} />
</Message>
)}
<p>
When Fredy found new listings, we like to report them to you. To do so, notification adapter can be
configured. <br />
There are multiple ways how Fredy can send new listings to you. Chose your weapon...
</p>
<Dropdown
placeholder="Select a notification adapter"
className="providerMutator__fields"
selection
value={selectedAdapter == null ? '' : selectedAdapter.id}
options={adapter
.map((a) => {
return {
key: a.id,
value: a.id,
text: a.name,
};
})
//filter out those, that have already been selected
.filter((option) =>
editNotificationAdapter != null
? true
: selected.find((selectedOption) => selectedOption.id === option.key) == null
)
.sort(sortAdapter)}
onChange={(e, { value }) => {
setSuccessMessage(null);
setValidationMessage(null);
const selectedAdapter = adapter.find((a) => a.id === value);
setSelectedAdapter(Object.assign({}, selectedAdapter));
}}
/>
<br />
<br />
{selectedAdapter != null && (
<Form>
<i>{selectedAdapter.description}</i>
<br />
{selectedAdapter.readme != null && (
<React.Fragment>
<Help readme={selectedAdapter.readme} />
</React.Fragment>
)}
<br />
{getFieldsFor(selectedAdapter)}
</Form>
)}
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button
content="Try Notification Adapter"
labelPosition="left"
floated="left"
icon="hand spock"
onClick={() => onTry()}
color="teal"
/> />
<Button color="black" onClick={() => onSubmit(false)}> )}
Cancel {successMessage != null && (
</Button> <Banner
<Button content="Save" labelPosition="right" icon="checkmark" onClick={() => onSubmit(true)} positive /> fullMode={false}
</Modal.Actions> type="success"
closeIcon={null}
title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>Yay!</div>}
style={{ marginBottom: '1rem' }}
description={<p dangerouslySetInnerHTML={{ __html: successMessage }} />}
/>
)}
<p>
When Fredy found new listings, we like to report them to you. To do so, notification adapter can be configured.{' '}
<br />
There are multiple ways how Fredy can send new listings to you. Chose your weapon...
</p>
<Select
filter
placeholder="Select a notification adapter"
className="providerMutator__fields"
value={selectedAdapter == null ? '' : selectedAdapter.id}
optionList={adapter
.map((a) => {
return {
otherKey: a.id,
value: a.id,
label: a.name,
};
})
//filter out those, that have already been selected
.filter((option) =>
editNotificationAdapter != null
? true
: selected.find((selectedOption) => selectedOption.id === option.key) == null
)
.sort(sortAdapter)}
onChange={(value) => {
setSuccessMessage(null);
setValidationMessage(null);
const selectedAdapter = adapter.find((a) => a.id === value);
setSelectedAdapter(Object.assign({}, selectedAdapter));
}}
/>
<br />
<br />
{selectedAdapter != null && (
<>
<i>{selectedAdapter.description}</i>
<br />
<br />
{selectedAdapter.readme != null && <Help readme={selectedAdapter.readme} />}
<br />
{getFieldsFor(selectedAdapter)}
</>
)}
</Modal> </Modal>
); );
} }

View File

@@ -1,19 +1,14 @@
import React from 'react'; import React from 'react';
import { Accordion, Icon } from 'semantic-ui-react'; import { Banner } from '@douyinfe/semi-ui';
export default function Help({ readme }) { export default function Help({ readme }) {
const [active, setActive] = React.useState(false);
return ( return (
<Accordion> <Banner
<Accordion.Title active={active} index={0} onClick={() => setActive(!active)}> fullMode={false}
<React.Fragment> type="info"
<Icon name="dropdown" /> <span className="providerMutator__helpLink"> More information</span> closeIcon={null}
</React.Fragment> title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>Information</div>}
</Accordion.Title> description={<p dangerouslySetInnerHTML={{ __html: readme }} />}
<Accordion.Content active={active} className="providerMutator__helpBox"> />
<p dangerouslySetInnerHTML={{ __html: readme }} />
</Accordion.Content>
</Accordion>
); );
} }

View File

@@ -1,9 +1,9 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Banner, Modal, Select, Input } from '@douyinfe/semi-ui';
import { transform } from '../../../../../services/transformer/providerTransformer'; import { transform } from '../../../../../services/transformer/providerTransformer';
import { Modal, Icon, Button, Dropdown, Input, Message } from 'semantic-ui-react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { IconLikeHeart } from '@douyinfe/semi-icons';
import './ProviderMutator.less'; import './ProviderMutator.less';
const sortProvider = (a, b) => { const sortProvider = (a, b) => {
@@ -61,79 +61,90 @@ export default function ProviderMutator({ onVisibilityChanged, visible = false,
}; };
return ( return (
<Modal onClose={() => onVisibilityChanged(false)} onOpen={() => onVisibilityChanged(true)} open={visible}> <Modal
<Modal.Header>Adding a new Provider</Modal.Header> title="Adding a new Provider"
<Modal.Content image> visible={visible}
<Modal.Description> onOk={() => onSubmit(true)}
{validationMessage != null && ( onCancel={() => onSubmit(false)}
<Message negative> style={{ width: '50rem' }}
<Message.Header>Houston we have a problem...</Message.Header> okText="Save"
<p>{validationMessage}</p> >
</Message> {validationMessage != null && (
)} <Banner
fullMode={false}
type="danger"
closeIcon={null}
title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>Error</div>}
style={{ marginBottom: '1rem' }}
description={validationMessage}
/>
)}
<p> <p>
Provider are the <Icon name="heart" color="red" /> of Fredy. We're supporting multiple Provider such as Provider are the <IconLikeHeart style={{ color: '#ff0000' }} /> of Fredy. We're supporting multiple Provider
Immowelt, Kalaydo etc. Select a provider from the list below. such as Immowelt, Kalaydo etc. Select a provider from the list below.
<br /> <br />
Fredy will then open the provider's url in a new tab. Fredy will then open the provider's url in a new tab.
</p> </p>
<p> <p>
You will need to configure your search parameter like you would do when you do a regular search on the You will need to configure your search parameter like you would do when you do a regular search on the
provider's website. provider's website.
<br /> <br />
When the search results are shown on the website, copy the url and paste it into the textfield below. When the search results are shown on the website, copy the url and paste it into the textfield below.
<br /> </p>
<span style={{ color: '#ff0000' }}> <Banner
fullMode={false}
type="warning"
closeIcon={null}
title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>ScrapingAnt</div>}
style={{ marginBottom: '1rem' }}
description={
<div>
<p>
If you chose Immoscout as a provider, make sure to also add the scrapingAnt apiKey to the config.json. If you chose Immoscout as a provider, make sure to also add the scrapingAnt apiKey to the config.json.
(See readme) (See readme)
</span> </p>
<br /> <p>
<span style={{ color: '#ff0000' }}>
Do not forget to sort the results by date before copying the url to Fredy, so that Fredy always captures Do not forget to sort the results by date before copying the url to Fredy, so that Fredy always captures
the latest search results. the latest search results.
</span> </p>
</p> </div>
<Dropdown }
placeholder="Select a provider" />
className="providerMutator__fields"
selection
value={selectedProvider == null ? '' : selectedProvider.id}
options={provider
.map((pro) => {
return {
key: pro.id,
value: pro.id,
text: pro.name,
};
})
.sort(sortProvider)}
onChange={(e, { value }) => {
const selectedProvider = provider.find((pro) => pro.id === value);
setSelectedProvider(selectedProvider);
window.open(selectedProvider.baseUrl); <Select
}} filter
/> placeholder="Select a provider"
<br /> className="providerMutator__fields"
<br /> optionList={provider
<Input .map((pro) => {
type="text" return {
placeholder="Provider Url" otherKey: pro.id,
width={10} value: pro.id,
className="providerMutator__fields" label: pro.name,
onBlur={(e) => { };
setProviderUrl(e.target.value); })
}} .sort(sortProvider)}
/> style={{ width: 180 }}
</Modal.Description> value={selectedProvider == null ? '' : selectedProvider.id}
</Modal.Content> onChange={(value) => {
<Modal.Actions> const selectedProvider = provider.find((pro) => pro.id === value);
<Button color="black" onClick={() => onSubmit(false)}> setSelectedProvider(selectedProvider);
Cancel
</Button> window.open(selectedProvider.baseUrl);
<Button content="Save" labelPosition="right" icon="checkmark" onClick={() => onSubmit(true)} positive /> }}
</Modal.Actions> />
<br />
<br />
<Input
type="text"
placeholder="Provider Url"
width={10}
className="providerMutator__fields"
onBlur={(e) => {
setProviderUrl(e.target.value);
}}
/>
</Modal> </Modal>
); );
} }

View File

@@ -1,14 +1,14 @@
import React from 'react'; import React from 'react';
import { Input } from 'semantic-ui-react';
import cityBackground from '../../assets/city_background.jpg'; import cityBackground from '../../assets/city_background.jpg';
import Logo from '../../components/logo/Logo'; import Logo from '../../components/logo/Logo';
import { xhrPost } from '../../services/xhr'; import { xhrPost } from '../../services/xhr';
import { Message } from 'semantic-ui-react';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { Input, Button, Banner } from '@douyinfe/semi-ui';
import './login.less'; import './login.less';
import { IconUser, IconLock } from '@douyinfe/semi-icons';
export default function Login() { export default function Login() {
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -44,30 +44,41 @@ export default function Login() {
<Logo /> <Logo />
<form> <form>
<div className="login__loginWrapper"> <div className="login__loginWrapper">
{error && <Message negative icon="error" content={error} />} {error && <Banner type="danger" closeIcon={null} description={error} />}
<Input <Input
icon="user" size="large"
iconPosition="left" prefix={<IconUser />}
placeholder="Username" placeholder="Username"
defaultValue={username} value={username}
showClear
style={{ marginTop: error ? '1rem' : '4rem' }} style={{ marginTop: error ? '1rem' : '4rem' }}
autoFocus autofocus
onChange={(e) => setUserName(e.target.value)} onChange={(value) => setUserName(value)}
onKeyPress={async (e) => {
if (e.key === 'Enter') {
await tryLogin();
}
}}
/> />
<Input <Input
type="password" size="large"
icon="lock" mode="password"
iconPosition="left" prefix={<IconLock />}
defaultValue={password} value={password}
placeholder="Password" placeholder="Password"
style={{ marginTop: '2rem' }} style={{ marginTop: '2rem' }}
onChange={(e) => setPassword(e.target.value)} onChange={(value) => setPassword(value)}
onKeyPress={async (e) => {
if (e.key === 'Enter') {
await tryLogin();
}
}}
/> />
<button className="ui primary button" style={{ marginTop: '3rem' }} onClick={tryLogin}> <Button type="primary" onClick={tryLogin} theme="solid" style={{ marginTop: '3rem' }}>
Login Login
</button> </Button>
</div> </div>
</form> </form>
</div> </div>

View File

@@ -20,7 +20,7 @@
&__loginWrapper { &__loginWrapper {
border: 1px solid #555050; border: 1px solid #555050;
border-radius: 30px; border-radius: 30px;
height: 25rem; height: 23rem;
width: 30rem; width: 30rem;
z-index: 1; z-index: 1;
background-color: #151313ab; background-color: #151313ab;

View File

@@ -1,21 +1,9 @@
import React from 'react'; import React from 'react';
import { Modal, Header, Icon, Button } from 'semantic-ui-react'; import { Modal } from '@douyinfe/semi-ui';
const UserRemovalModal = function UserRemovalModal({ onOk, onCancel }) { const UserRemovalModal = function UserRemovalModal({ onOk, onCancel }) {
return ( return (
<Modal open={true}> <Modal title="Removing user" visible={true} closable={false} onOk={onOk} onCancel={onCancel}>
<Header icon="warning sign" content="Warning" /> <p>Removing this user will also remove all associated jobs.</p>
<Modal.Content>
<p>Removing this user will also remove all associated jobs.</p>
</Modal.Content>
<Modal.Actions>
<Button color="red" onClick={() => onCancel()}>
<Icon name="remove" /> Cancel
</Button>
<Button color="green" onClick={() => onOk()}>
<Icon name="checkmark" /> Remove
</Button>
</Modal.Actions>
</Modal> </Modal>
); );
}; };

View File

@@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import ToastContext from '../../components/toasts/ToastContext'; import { Toast } from '@douyinfe/semi-ui';
import UserTable from '../../components/table/UserTable'; import UserTable from '../../components/table/UserTable';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Button, Icon } from 'semantic-ui-react'; import { IconPlus } from '@douyinfe/semi-icons';
import { Button } from '@douyinfe/semi-ui';
import UserRemovalModal from './UserRemovalModal'; import UserRemovalModal from './UserRemovalModal';
import { xhrDelete } from '../../services/xhr'; import { xhrDelete } from '../../services/xhr';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
@@ -14,7 +15,6 @@ const Users = function Users() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [loading, setLoading] = React.useState(true); const [loading, setLoading] = React.useState(true);
const users = useSelector((state) => state.user.users); const users = useSelector((state) => state.user.users);
const ctx = React.useContext(ToastContext);
const [userIdToBeRemoved, setUserIdToBeRemoved] = React.useState(null); const [userIdToBeRemoved, setUserIdToBeRemoved] = React.useState(null);
const history = useHistory(); const history = useHistory();
@@ -23,30 +23,19 @@ const Users = function Users() {
await dispatch.user.getUsers(); await dispatch.user.getUsers();
setLoading(false); setLoading(false);
} }
init(); init();
}, []); }, []);
const onUserRemoval = async () => { const onUserRemoval = async () => {
try { try {
await xhrDelete('/api/admin/users', { userId: userIdToBeRemoved }); await xhrDelete('/api/admin/users', { userId: userIdToBeRemoved });
ctx.showToast({ Toast.success('User successfully remove');
title: 'Success',
message: 'User successfully remove',
delay: 4000,
backgroundColor: '#87eb8f',
color: '#000',
});
setUserIdToBeRemoved(null); setUserIdToBeRemoved(null);
await dispatch.jobs.getJobs(); await dispatch.jobs.getJobs();
await dispatch.user.getUsers(); await dispatch.user.getUsers();
} catch (error) { } catch (error) {
ctx.showToast({ Toast.error(error);
title: 'Error',
message: error,
delay: 8000,
backgroundColor: '#db2828',
color: '#fff',
});
setUserIdToBeRemoved(null); setUserIdToBeRemoved(null);
} }
}; };
@@ -57,8 +46,12 @@ const Users = function Users() {
<React.Fragment> <React.Fragment>
{userIdToBeRemoved && <UserRemovalModal onCancel={() => setUserIdToBeRemoved(null)} onOk={onUserRemoval} />} {userIdToBeRemoved && <UserRemovalModal onCancel={() => setUserIdToBeRemoved(null)} onOk={onUserRemoval} />}
<Button primary className="users__newButton" onClick={() => history.push('/users/new')}> <Button
<Icon name="plus" /> type="primary"
className="users__newButton"
icon={<IconPlus />}
onClick={() => history.push('/users/new')}
>
Create new User Create new User
</Button> </Button>

View File

@@ -1,14 +1,12 @@
import React from 'react'; import React from 'react';
import ToastContext from '../../../components/toasts/ToastContext';
import { xhrGet, xhrPost } from '../../../services/xhr'; import { xhrGet, xhrPost } from '../../../services/xhr';
import { useHistory, useParams } from 'react-router'; import { useHistory, useParams } from 'react-router';
import { Button, Form } from 'semantic-ui-react';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import Switch from 'react-switch'; import { Divider, Input, Switch, Button, Toast } from '@douyinfe/semi-ui';
import './UserMutator.less'; import './UserMutator.less';
import { SegmentPart } from '../../../components/segment/SegmentPart'; import { SegmentPart } from '../../../components/segment/SegmentPart';
import { IconPlusCircle } from '@douyinfe/semi-icons';
const UserMutator = function UserMutator() { const UserMutator = function UserMutator() {
const params = useParams(); const params = useParams();
@@ -18,7 +16,6 @@ const UserMutator = function UserMutator() {
const [isAdmin, setIsAdmin] = React.useState(false); const [isAdmin, setIsAdmin] = React.useState(false);
const history = useHistory(); const history = useHistory();
const ctx = React.useContext(ToastContext);
const dispatch = useDispatch(); const dispatch = useDispatch();
React.useEffect(() => { React.useEffect(() => {
@@ -38,6 +35,7 @@ const UserMutator = function UserMutator() {
} }
} }
} }
init(); init();
}, [params.userId]); }, [params.userId]);
@@ -51,76 +49,62 @@ const UserMutator = function UserMutator() {
isAdmin, isAdmin,
}); });
await dispatch.user.getUsers(); await dispatch.user.getUsers();
ctx.showToast({ Toast.success('User successfully saved...');
title: 'Success',
message: 'User successfully saved...',
delay: 5000,
backgroundColor: '#87eb8f',
color: '#000',
});
history.push('/users'); history.push('/users');
} catch (Exception) { } catch (error) {
console.error(Exception); console.error(error);
ctx.showToast({ Toast.error(error.json.message);
title: 'Error',
message: Exception.json.message,
delay: 6000,
backgroundColor: '#db2828',
color: '#fff',
});
} }
}; };
return ( return (
<Form inverted className="userMutator"> <form className="userMutator">
<SegmentPart name="Username" helpText="The username used to login to Fredy"> <SegmentPart name="Username" helpText="The username used to login to Fredy">
<Form.Input <Input
type="text" type="text"
label="Username" label="Username"
maxLength={30} maxLength={30}
placeholder="Username" placeholder="Username"
autoFocus autoFocus
inverted
width={6} width={6}
defaultValue={username} value={username}
onChange={(e) => setUsername(e.target.value)} onChange={(val) => setUsername(val)}
/> />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart name="Password" helpText="The password used to login to Fredy"> <SegmentPart name="Password" helpText="The password used to login to Fredy">
<Form.Input <Input
type="password" mode="password"
label="Password" label="Password"
placeholder="Password" placeholder="Password"
inverted
width={6} width={6}
defaultValue={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(val) => setPassword(val)}
/> />
</SegmentPart> </SegmentPart>
<Divider margin="1rem" />
<SegmentPart name="Retype password" helpText="Retype the password to make sure they match"> <SegmentPart name="Retype password" helpText="Retype the password to make sure they match">
<Form.Input <Input
type="password" mode="password"
label="Retype password" label="Retype password"
placeholder="Retype password" placeholder="Retype password"
inverted
width={6} width={6}
defaultValue={password2} value={password2}
onChange={(e) => setPassword2(e.target.value)} onChange={(val) => setPassword2(val)}
/> />
</SegmentPart> </SegmentPart>
<SegmentPart name="Admin use" helpText="Check this if the user is an administrator"> <Divider margin="1rem" />
<Form.Field> <SegmentPart name="Is user an admin?" helpText="Check this if the user is an administrator">
<label>Is user an admin?</label> <Switch checked={isAdmin} onChange={(checked) => setIsAdmin(checked)} />
<Switch checked={isAdmin} onChange={(checked) => setIsAdmin(checked)} />
</Form.Field>
</SegmentPart> </SegmentPart>
<Button color="red" onClick={() => history.push('/users')}> <Divider margin="1rem" />
<Button type="danger" style={{ marginRight: '1rem' }} onClick={() => history.push('/users')}>
Cancel Cancel
</Button> </Button>
<Button color="green" onClick={saveUser}> <Button type="primary" icon={<IconPlusCircle />} onClick={saveUser}>
Save Save
</Button> </Button>
</Form> </form>
); );
}; };

675
yarn.lock
View File

@@ -50,21 +50,21 @@
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.14.tgz#4106fc8b755f3e3ee0a0a7c27dde5de1d2b2baf8" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.14.tgz#4106fc8b755f3e3ee0a0a7c27dde5de1d2b2baf8"
integrity sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw== integrity sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==
"@babel/core@7.21.0": "@babel/core@7.21.3":
version "7.21.0" version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.3.tgz#cf1c877284a469da5d1ce1d1e53665253fae712e"
integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA== integrity sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==
dependencies: dependencies:
"@ampproject/remapping" "^2.2.0" "@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.18.6" "@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.21.0" "@babel/generator" "^7.21.3"
"@babel/helper-compilation-targets" "^7.20.7" "@babel/helper-compilation-targets" "^7.20.7"
"@babel/helper-module-transforms" "^7.21.0" "@babel/helper-module-transforms" "^7.21.2"
"@babel/helpers" "^7.21.0" "@babel/helpers" "^7.21.0"
"@babel/parser" "^7.21.0" "@babel/parser" "^7.21.3"
"@babel/template" "^7.20.7" "@babel/template" "^7.20.7"
"@babel/traverse" "^7.21.0" "@babel/traverse" "^7.21.3"
"@babel/types" "^7.21.0" "@babel/types" "^7.21.3"
convert-source-map "^1.7.0" convert-source-map "^1.7.0"
debug "^4.1.0" debug "^4.1.0"
gensync "^1.0.0-beta.2" gensync "^1.0.0-beta.2"
@@ -92,10 +92,10 @@
json5 "^2.2.2" json5 "^2.2.2"
semver "^6.3.0" semver "^6.3.0"
"@babel/eslint-parser@7.19.1": "@babel/eslint-parser@7.21.3":
version "7.19.1" version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz#4f68f6b0825489e00a24b41b6a1ae35414ecd2f4" resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz#d79e822050f2de65d7f368a076846e7184234af7"
integrity sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ== integrity sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg==
dependencies: dependencies:
"@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1"
eslint-visitor-keys "^2.1.0" eslint-visitor-keys "^2.1.0"
@@ -119,7 +119,7 @@
"@jridgewell/gen-mapping" "^0.3.2" "@jridgewell/gen-mapping" "^0.3.2"
jsesc "^2.5.1" jsesc "^2.5.1"
"@babel/generator@^7.21.0", "@babel/generator@^7.21.1": "@babel/generator@^7.21.1":
version "7.21.1" version "7.21.1"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd"
integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==
@@ -129,6 +129,16 @@
"@jridgewell/trace-mapping" "^0.3.17" "@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1" jsesc "^2.5.1"
"@babel/generator@^7.21.3":
version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.3.tgz#232359d0874b392df04045d72ce2fd9bb5045fce"
integrity sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==
dependencies:
"@babel/types" "^7.21.3"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.18.6": "@babel/helper-annotate-as-pure@^7.18.6":
version "7.18.6" version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
@@ -275,7 +285,7 @@
"@babel/traverse" "^7.20.10" "@babel/traverse" "^7.20.10"
"@babel/types" "^7.20.7" "@babel/types" "^7.20.7"
"@babel/helper-module-transforms@^7.21.0": "@babel/helper-module-transforms@^7.21.2":
version "7.21.2" version "7.21.2"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2"
integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==
@@ -414,11 +424,16 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.15.tgz#eec9f36d8eaf0948bb88c87a46784b5ee9fd0c89" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.15.tgz#eec9f36d8eaf0948bb88c87a46784b5ee9fd0c89"
integrity sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg== integrity sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==
"@babel/parser@^7.21.0", "@babel/parser@^7.21.2": "@babel/parser@^7.21.2":
version "7.21.2" version "7.21.2"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3"
integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==
"@babel/parser@^7.21.3":
version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3"
integrity sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
version "7.18.6" version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
@@ -1077,6 +1092,21 @@
"@babel/plugin-transform-react-jsx-development" "^7.18.6" "@babel/plugin-transform-react-jsx-development" "^7.18.6"
"@babel/plugin-transform-react-pure-annotations" "^7.18.6" "@babel/plugin-transform-react-pure-annotations" "^7.18.6"
"@babel/runtime-corejs3@^7.15.4":
version "7.21.0"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz#6e4939d9d9789ff63e2dc58e88f13a3913a24eba"
integrity sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==
dependencies:
core-js-pure "^3.25.1"
regenerator-runtime "^0.13.11"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.2.0":
version "7.21.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
dependencies:
regenerator-runtime "^0.13.11"
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.8.4": "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.8.4":
version "7.20.6" version "7.20.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.6.tgz#facf4879bfed9b5326326273a64220f099b0fce3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.6.tgz#facf4879bfed9b5326326273a64220f099b0fce3"
@@ -1084,13 +1114,6 @@
dependencies: dependencies:
regenerator-runtime "^0.13.11" regenerator-runtime "^0.13.11"
"@babel/runtime@^7.10.4", "@babel/runtime@^7.10.5", "@babel/runtime@^7.7.6":
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.12.1": "@babel/runtime@^7.12.1":
version "7.17.9" version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
@@ -1098,6 +1121,13 @@
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@^7.7.6":
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.9.2": "@babel/runtime@^7.9.2":
version "7.14.0" version "7.14.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6"
@@ -1171,6 +1201,22 @@
debug "^4.1.0" debug "^4.1.0"
globals "^11.1.0" globals "^11.1.0"
"@babel/traverse@^7.21.3":
version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.3.tgz#4747c5e7903d224be71f90788b06798331896f67"
integrity sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.21.3"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.21.0"
"@babel/helper-hoist-variables" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/parser" "^7.21.3"
"@babel/types" "^7.21.3"
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.4.4": "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.4.4":
version "7.20.5" version "7.20.5"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
@@ -1198,115 +1244,211 @@
"@babel/helper-validator-identifier" "^7.19.1" "@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@esbuild/android-arm64@0.16.17": "@babel/types@^7.21.3":
version "0.16.17" version "7.21.3"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05"
integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg== integrity sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==
dependencies:
"@babel/helper-string-parser" "^7.19.4"
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
"@esbuild/android-arm@0.16.17": "@douyinfe/semi-animation-react@2.31.0":
version "0.16.17" version "2.31.0"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2" resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.31.0.tgz#e7e53219a40fa0f3e192cd6b254e41fdb6f7e079"
integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw== integrity sha512-jSEg6LJH6/Lo++la98s3xtY5/pow44Tn7q9UbkqREBE8y2GtzoRpKCxmoYRATGo96q/3WmeDcd+fDWnvY9LAKg==
dependencies:
"@douyinfe/semi-animation" "2.12.0"
"@douyinfe/semi-animation-styled" "2.23.2"
classnames "^2.2.6"
"@esbuild/android-x64@0.16.17": "@douyinfe/semi-animation-styled@2.23.2":
version "0.16.17" version "2.23.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e" resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.23.2.tgz#f18bc074515441c297cc636ed98521e249d093c9"
integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ== integrity sha512-cKaA1yGHPF76Rx7EZDZicj+1oX1su2wnqb/UGFOTquAwqWmkTfgQ+EKxCd/N704WH+RtmGf4xbrJKpBvvcEdSQ==
"@esbuild/darwin-arm64@0.16.17": "@douyinfe/semi-animation@2.12.0":
version "0.16.17" version "2.12.0"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220" resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.12.0.tgz#51fe52d3911c2591a80a6e9fe96e6809c1511f13"
integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w== integrity sha512-OAfL9Nk38ZPqfdKm9k4cvVXXzm16ALI4LxGNZ0qfe2RCLLnYGB/hNzTctoTDjYD35dFv0yroh3qsXtZuP2xNdg==
dependencies:
"@babel/runtime-corejs3" "^7.15.4"
bezier-easing "^2.1.0"
"@esbuild/darwin-x64@0.16.17": "@douyinfe/semi-animation@2.31.0":
version "0.16.17" version "2.31.0"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4" resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.31.0.tgz#bcf89009845dbf945b83df2ca4a91d9c6b5631c6"
integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg== integrity sha512-UxEdBT90A2oAIauTHx2wXTIfOhF6Evlfo7tZ0QaeJtzRlK1km/qfZRRIVYXx1F8CVdgJSAiE2x2p9d78EHrcag==
dependencies:
bezier-easing "^2.1.0"
"@esbuild/freebsd-arm64@0.16.17": "@douyinfe/semi-foundation@2.31.0":
version "0.16.17" version "2.31.0"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27" resolved "https://registry.yarnpkg.com/@douyinfe/semi-foundation/-/semi-foundation-2.31.0.tgz#cfe41c8bc58b7d9b1c73a9bc5a1bc82a0901991f"
integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw== integrity sha512-Bw/I4uZF/wv6fVUKsPdB+E5fIeojK3C9sjfOrIMfwKcimWxtOSY/Kyzb+vM9xrCf5spssizOOQp1Ge4IG0niLA==
dependencies:
"@douyinfe/semi-animation" "2.12.0"
async-validator "^3.5.0"
classnames "^2.2.6"
date-fns "^2.9.0"
date-fns-tz "^1.0.10"
lodash "^4.17.21"
memoize-one "^5.2.1"
scroll-into-view-if-needed "^2.2.24"
"@esbuild/freebsd-x64@0.16.17": "@douyinfe/semi-icons@2.31.0":
version "0.16.17" version "2.31.0"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72" resolved "https://registry.yarnpkg.com/@douyinfe/semi-icons/-/semi-icons-2.31.0.tgz#32b5ec27f29cb74f5a2125f058d86c5e2d82cecb"
integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug== integrity sha512-txON0yQpJAA4I1FILttQ5uFOZfCah1yp4RIE+nlv7f50QKIMptQDcSagwdHQiUvz2zuuBS0WOotN9ZZnDn9DAw==
dependencies:
classnames "^2.2.6"
"@esbuild/linux-arm64@0.16.17": "@douyinfe/semi-illustrations@2.31.0":
version "0.16.17" version "2.31.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca" resolved "https://registry.yarnpkg.com/@douyinfe/semi-illustrations/-/semi-illustrations-2.31.0.tgz#59c952ff84c00da3a277009f3a9d0990b470451b"
integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g== integrity sha512-Jl7V6Guri9dFTil7lvzBV3w0JEIOqiRPuH4Sb92f8dVMjfGY+/llkKsqsdTv3Jns5nAKos/z8ILkA/5EJX4SIw==
"@esbuild/linux-arm@0.16.17": "@douyinfe/semi-theme-default@2.31.0":
version "0.16.17" version "2.31.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196" resolved "https://registry.yarnpkg.com/@douyinfe/semi-theme-default/-/semi-theme-default-2.31.0.tgz#5644e7dda1001bdfaa5704d5bcef0ff5b4ab0f7b"
integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ== integrity sha512-zuU/vurGQeNSFIFEG031LlOfJIkdnC+LqO+4j8TrkGWGHk9rQqzkjADzecAp5I51s0c/KxDMie1SPkcMNU2zJA==
dependencies:
glob "^7.1.6"
"@esbuild/linux-ia32@0.16.17": "@douyinfe/semi-ui@2.31.0":
version "0.16.17" version "2.31.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54" resolved "https://registry.yarnpkg.com/@douyinfe/semi-ui/-/semi-ui-2.31.0.tgz#7731c980ab505eb08b59d38accf1842878e637ef"
integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg== integrity sha512-nqdEh0Jl6v3dkLSHwcCQ70Qd4weIXcSM2RP34BAbpJdrZniArJYua47XVC97gl8D7UF/iwevU8WkK+zoQtvEow==
dependencies:
"@douyinfe/semi-animation" "2.31.0"
"@douyinfe/semi-animation-react" "2.31.0"
"@douyinfe/semi-foundation" "2.31.0"
"@douyinfe/semi-icons" "2.31.0"
"@douyinfe/semi-illustrations" "2.31.0"
"@douyinfe/semi-theme-default" "2.31.0"
async-validator "^3.5.0"
classnames "^2.2.6"
copy-text-to-clipboard "^2.1.1"
date-fns "^2.9.0"
date-fns-tz "^1.0.10"
lodash "^4.17.21"
prop-types "^15.7.2"
react-resizable "^1.8.0"
react-sortable-hoc "^2.0.0"
react-window "^1.8.2"
resize-observer-polyfill "^1.5.1"
scroll-into-view-if-needed "^2.2.24"
utility-types "^3.10.0"
"@esbuild/linux-loong64@0.16.17": "@esbuild/android-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz#15a8e2b407d03989b899e325151dc2e96d19c620"
integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ== integrity sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==
"@esbuild/linux-mips64el@0.16.17": "@esbuild/android-arm@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.12.tgz#677a09297e1f4f37aba7b4fc4f31088b00484985"
integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw== integrity sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==
"@esbuild/linux-ppc64@0.16.17": "@esbuild/android-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.12.tgz#b292729eef4e0060ae1941f6a021c4d2542a3521"
integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g== integrity sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==
"@esbuild/linux-riscv64@0.16.17": "@esbuild/darwin-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz#efa35318df931da05825894e1787b976d55adbe3"
integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw== integrity sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==
"@esbuild/linux-s390x@0.16.17": "@esbuild/darwin-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz#e7b54bb3f6dc81aadfd0485cd1623c648157e64d"
integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w== integrity sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==
"@esbuild/linux-x64@0.16.17": "@esbuild/freebsd-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz#99a18a8579d6299c449566fe91d9b6a54cf2a591"
integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw== integrity sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==
"@esbuild/netbsd-x64@0.16.17": "@esbuild/freebsd-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz#0e090190fede307fb4022f671791a50dd5121abd"
integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA== integrity sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==
"@esbuild/openbsd-x64@0.16.17": "@esbuild/linux-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz#7fe2a69f8a1a7153fa2b0f44aabcadb59475c7e0"
integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg== integrity sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==
"@esbuild/sunos-x64@0.16.17": "@esbuild/linux-arm@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz#b87c76ebf1fe03e01fd6bb5cfc2f3c5becd5ee93"
integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw== integrity sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==
"@esbuild/win32-arm64@0.16.17": "@esbuild/linux-ia32@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz#9e9357090254524d32e6708883a47328f3037858"
integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw== integrity sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==
"@esbuild/win32-ia32@0.16.17": "@esbuild/linux-loong64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz#9deb605f9e2c82f59412ddfefb4b6b96d54b5b5b"
integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig== integrity sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==
"@esbuild/win32-x64@0.16.17": "@esbuild/linux-mips64el@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz#6ef170b974ddf5e6acdfa5b05f22b6e9dfd2b003"
integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q== integrity sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==
"@esbuild/linux-ppc64@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz#1638d3d4acf1d34aaf37cf8908c2e1cefed16204"
integrity sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==
"@esbuild/linux-riscv64@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz#135b6e9270a8e2de2b9094bb21a287517df520ef"
integrity sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==
"@esbuild/linux-s390x@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz#21e40830770c5d08368e300842bde382ce97d615"
integrity sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==
"@esbuild/linux-x64@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz#76c1c199871d48e1aaa47a762fb9e0dca52e1f7a"
integrity sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==
"@esbuild/netbsd-x64@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz#c7c3b3017a4b938c76c35f66af529baf62eac527"
integrity sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==
"@esbuild/openbsd-x64@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz#05d04217d980e049001afdbeacbb58d31bb5cefb"
integrity sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==
"@esbuild/sunos-x64@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz#cf3862521600e4eb6c440ec3bad31ed40fb87ef3"
integrity sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==
"@esbuild/win32-arm64@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz#43dd7fb5be77bf12a1550355ab2b123efd60868e"
integrity sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==
"@esbuild/win32-ia32@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz#9940963d0bff4ea3035a84e2b4c6e41c5e6296eb"
integrity sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==
"@esbuild/win32-x64@0.17.12":
version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz#3a11d13e9a5b0c05db88991b234d8baba1f96487"
integrity sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==
"@eslint-community/eslint-utils@^4.2.0": "@eslint-community/eslint-utils@^4.2.0":
version "4.2.0" version "4.2.0"
@@ -1340,21 +1482,6 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe"
integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==
"@fluentui/react-component-event-listener@~0.63.0":
version "0.63.1"
resolved "https://registry.yarnpkg.com/@fluentui/react-component-event-listener/-/react-component-event-listener-0.63.1.tgz#c2af94893671f1d6bfe2a8a07dcfa2cb01b85f52"
integrity sha512-gSMdOh6tI3IJKZFqxfQwbTpskpME0CvxdxGM2tdglmf6ZPVDi0L4+KKIm+2dN8nzb8Ya1A8ZT+Ddq0KmZtwVQg==
dependencies:
"@babel/runtime" "^7.10.4"
"@fluentui/react-component-ref@~0.63.0":
version "0.63.1"
resolved "https://registry.yarnpkg.com/@fluentui/react-component-ref/-/react-component-ref-0.63.1.tgz#a7778e2a5c724d12e828afd994c93fa2da44f64e"
integrity sha512-8MkXX4+R3i80msdbD4rFpEB4WWq2UDvGwG386g3ckIWbekdvN9z2kWAd9OXhRGqB7QeOsoAGWocp6gAMCivRlw==
dependencies:
"@babel/runtime" "^7.10.4"
react-is "^16.6.3"
"@humanwhocodes/config-array@^0.11.8": "@humanwhocodes/config-array@^0.11.8":
version "0.11.8" version "0.11.8"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
@@ -1460,11 +1587,6 @@
"@nodelib/fs.scandir" "2.1.5" "@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0" fastq "^1.6.0"
"@popperjs/core@^2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.6.0.tgz#f022195afdfc942e088ee2101285a1d31c7d727f"
integrity sha512-cPqjjzuFWNK3BSKLm0abspP0sp/IGOli4p5I5fKFAzdS8fvjdOwDCfZqAaIiXd9lPkOWi3SUUfZof3hEb7J/uw==
"@rematch/core@2.2.0": "@rematch/core@2.2.0":
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/@rematch/core/-/core-2.2.0.tgz#c4e6cc9d369d341afe2345842f43c255b7a44e90" resolved "https://registry.yarnpkg.com/@rematch/core/-/core-2.2.0.tgz#c4e6cc9d369d341afe2345842f43c255b7a44e90"
@@ -1475,14 +1597,6 @@
resolved "https://registry.yarnpkg.com/@rematch/loading/-/loading-2.1.2.tgz#1dc680d445cd2d1234489cb69816278d02cf2216" resolved "https://registry.yarnpkg.com/@rematch/loading/-/loading-2.1.2.tgz#1dc680d445cd2d1234489cb69816278d02cf2216"
integrity sha512-3fWUvWkIxP+BEi2LCKYKaUkMFCT0MDcN1xQD19tPNufMry7skqybahqm9/ugs9wIji1n3ObF7yHkrb01E+N3Tw== integrity sha512-3fWUvWkIxP+BEi2LCKYKaUkMFCT0MDcN1xQD19tPNufMry7skqybahqm9/ugs9wIji1n3ObF7yHkrb01E+N3Tw==
"@semantic-ui-react/event-stack@^3.1.3":
version "3.1.3"
resolved "https://registry.yarnpkg.com/@semantic-ui-react/event-stack/-/event-stack-3.1.3.tgz#2862d2631d67dd846c705db2fc1ede1c468be3a1"
integrity sha512-FdTmJyWvJaYinHrKRsMLDrz4tTMGdFfds299Qory53hBugiDvGC0tEJf+cHsi5igDwWb/CLOgOiChInHwq8URQ==
dependencies:
exenv "^1.2.2"
prop-types "^15.6.2"
"@sendgrid/client@^7.7.0": "@sendgrid/client@^7.7.0":
version "7.7.0" version "7.7.0"
resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.7.0.tgz#f8f67abd604205a0d0b1af091b61517ef465fdbf" resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.7.0.tgz#f8f67abd604205a0d0b1af091b61517ef465fdbf"
@@ -1729,6 +1843,11 @@ astral-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
async-validator@^3.5.0:
version "3.5.2"
resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-3.5.2.tgz#68e866a96824e8b2694ff7a831c1a25c44d5e500"
integrity sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ==
asynckit@^0.4.0: asynckit@^0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -1796,6 +1915,11 @@ better-sqlite3@8.2.0:
bindings "^1.5.0" bindings "^1.5.0"
prebuild-install "^7.1.0" prebuild-install "^7.1.0"
bezier-easing@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/bezier-easing/-/bezier-easing-2.1.0.tgz#c04dfe8b926d6ecaca1813d69ff179b7c2025d86"
integrity sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==
bignumber.js@^9.0.0: bignumber.js@^9.0.0:
version "9.0.1" version "9.0.1"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5"
@@ -2018,6 +2142,11 @@ ci-info@^2.0.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
classnames@^2.2.6:
version "2.3.2"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
clean-stack@^2.0.0: clean-stack@^2.0.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
@@ -2116,6 +2245,11 @@ component-emitter@^1.2.0:
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
compute-scroll-into-view@^1.0.20:
version "1.0.20"
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
concat-map@0.0.1: concat-map@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -2175,6 +2309,11 @@ copy-anything@^2.0.1:
dependencies: dependencies:
is-what "^3.7.1" is-what "^3.7.1"
copy-text-to-clipboard@^2.1.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-2.2.0.tgz#329dd6daf8c42034c763ace567418401764579ae"
integrity sha512-WRvoIdnTs1rgPMkgA2pUOa/M4Enh2uzCwdKsOMYNAJiz/4ZvEJgmbF4OmninPmlFdAWisfeh0tH+Cpf7ni3RqQ==
core-js-compat@^3.25.1: core-js-compat@^3.25.1:
version "3.26.1" version "3.26.1"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.26.1.tgz#0e710b09ebf689d719545ac36e49041850f943df" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.26.1.tgz#0e710b09ebf689d719545ac36e49041850f943df"
@@ -2182,6 +2321,11 @@ core-js-compat@^3.25.1:
dependencies: dependencies:
browserslist "^4.21.4" browserslist "^4.21.4"
core-js-pure@^3.25.1:
version "3.29.1"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.29.1.tgz#1be6ca2b8772f6b4df7fc4621743286e676c6162"
integrity sha512-4En6zYVi0i0XlXHVz/bi6l1XDjCqkKRq765NXuX+SnaIatlE96Odt5lMLjdxUiNI1v9OXI5DSLWYPlmTfkTktg==
core-util-is@~1.0.0: core-util-is@~1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -2241,6 +2385,16 @@ data-uri-to-buffer@^4.0.0:
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
date-fns-tz@^1.0.10:
version "1.3.8"
resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.3.8.tgz#083e3a4e1f19b7857fa0c18deea6c2bc46ded7b9"
integrity sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==
date-fns@^2.9.0:
version "2.29.3"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8"
integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==
debug@2.6.9, debug@^2.1.3: debug@2.6.9, debug@^2.1.3:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -2628,33 +2782,33 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1" is-date-object "^1.0.1"
is-symbol "^1.0.2" is-symbol "^1.0.2"
esbuild@^0.16.14: esbuild@^0.17.5:
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.12.tgz#2ad7523bf1bc01881e9d904bc04e693bd3bdcf2f"
integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg== integrity sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==
optionalDependencies: optionalDependencies:
"@esbuild/android-arm" "0.16.17" "@esbuild/android-arm" "0.17.12"
"@esbuild/android-arm64" "0.16.17" "@esbuild/android-arm64" "0.17.12"
"@esbuild/android-x64" "0.16.17" "@esbuild/android-x64" "0.17.12"
"@esbuild/darwin-arm64" "0.16.17" "@esbuild/darwin-arm64" "0.17.12"
"@esbuild/darwin-x64" "0.16.17" "@esbuild/darwin-x64" "0.17.12"
"@esbuild/freebsd-arm64" "0.16.17" "@esbuild/freebsd-arm64" "0.17.12"
"@esbuild/freebsd-x64" "0.16.17" "@esbuild/freebsd-x64" "0.17.12"
"@esbuild/linux-arm" "0.16.17" "@esbuild/linux-arm" "0.17.12"
"@esbuild/linux-arm64" "0.16.17" "@esbuild/linux-arm64" "0.17.12"
"@esbuild/linux-ia32" "0.16.17" "@esbuild/linux-ia32" "0.17.12"
"@esbuild/linux-loong64" "0.16.17" "@esbuild/linux-loong64" "0.17.12"
"@esbuild/linux-mips64el" "0.16.17" "@esbuild/linux-mips64el" "0.17.12"
"@esbuild/linux-ppc64" "0.16.17" "@esbuild/linux-ppc64" "0.17.12"
"@esbuild/linux-riscv64" "0.16.17" "@esbuild/linux-riscv64" "0.17.12"
"@esbuild/linux-s390x" "0.16.17" "@esbuild/linux-s390x" "0.17.12"
"@esbuild/linux-x64" "0.16.17" "@esbuild/linux-x64" "0.17.12"
"@esbuild/netbsd-x64" "0.16.17" "@esbuild/netbsd-x64" "0.17.12"
"@esbuild/openbsd-x64" "0.16.17" "@esbuild/openbsd-x64" "0.17.12"
"@esbuild/sunos-x64" "0.16.17" "@esbuild/sunos-x64" "0.17.12"
"@esbuild/win32-arm64" "0.16.17" "@esbuild/win32-arm64" "0.17.12"
"@esbuild/win32-ia32" "0.16.17" "@esbuild/win32-ia32" "0.17.12"
"@esbuild/win32-x64" "0.16.17" "@esbuild/win32-x64" "0.17.12"
escalade@^3.1.1: escalade@^3.1.1:
version "3.1.1" version "3.1.1"
@@ -2847,11 +3001,6 @@ execa@^7.0.0:
signal-exit "^3.0.7" signal-exit "^3.0.7"
strip-final-newline "^3.0.0" strip-final-newline "^3.0.0"
exenv@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
expand-template@^2.0.3: expand-template@^2.0.3:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
@@ -3128,6 +3277,18 @@ glob@^7.1.3:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
glob@^7.1.6:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.1.1"
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^11.1.0: globals@^11.1.0:
version "11.12.0" version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@@ -3423,6 +3584,13 @@ internal-slot@^1.0.3:
has "^1.0.3" has "^1.0.3"
side-channel "^1.0.4" side-channel "^1.0.4"
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
is-arrayish@^0.2.1: is-arrayish@^0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -3722,11 +3890,6 @@ json5@^2.2.2:
array-includes "^3.1.1" array-includes "^3.1.1"
object.assign "^4.1.1" object.assign "^4.1.1"
keyboard-key@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/keyboard-key/-/keyboard-key-1.1.0.tgz#6f2e8e37fa11475bb1f1d65d5174f1b35653f5b7"
integrity sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==
keygrip@~1.1.0: keygrip@~1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226"
@@ -3814,11 +3977,6 @@ locate-path@^6.0.0:
dependencies: dependencies:
p-locate "^5.0.0" p-locate "^5.0.0"
lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash.assignin@^4.0.9: lodash.assignin@^4.0.9:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
@@ -3884,7 +4042,7 @@ lodash.some@^4.4.0:
resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=
lodash@^4.17.21: lodash@4.17.21, lodash@^4.17.21:
version "4.17.21" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -3974,6 +4132,11 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
"memoize-one@>=3.1.1 <6", memoize-one@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
merge-stream@^2.0.0: merge-stream@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -4046,7 +4209,7 @@ minimatch@^3.0.4:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimatch@^3.0.5, minimatch@^3.1.2: minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
@@ -4558,10 +4721,10 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier@2.8.4: prettier@2.8.5:
version "2.8.4" version "2.8.5"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.5.tgz#3dd8ae1ebddc4f6aa419c9b64d8c8319a7e0d982"
integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== integrity sha512-3gzuxrHbKUePRBB4ZeU08VNkUcqEHaUaouNt0m7LGP4Hti/NuB07C7PPTM/LkWqXoJYJn2McEo5+kxPNrtQkLQ==
process-nextick-args@~2.0.0: process-nextick-args@~2.0.0:
version "2.0.1" version "2.0.1"
@@ -4573,6 +4736,15 @@ promise-polyfill@^1.1.6:
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-1.1.6.tgz#cd04eff46f5c95c3a7d045591d79b5e3e01f12d7" resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-1.1.6.tgz#cd04eff46f5c95c3a7d045591d79b5e3e01f12d7"
integrity sha1-zQTv9G9clcOn0EVZHXm14+AfEtc= integrity sha1-zQTv9G9clcOn0EVZHXm14+AfEtc=
prop-types@15.x, prop-types@^15.5.7, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.13.1"
prop-types@^15.6.2, prop-types@^15.7.2: prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
@@ -4582,15 +4754,6 @@ prop-types@^15.6.2, prop-types@^15.7.2:
object-assign "^4.1.1" object-assign "^4.1.1"
react-is "^16.8.1" react-is "^16.8.1"
prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.13.1"
prr@~1.0.1: prr@~1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@@ -4675,34 +4838,24 @@ react-dom@18.2.0:
loose-envify "^1.1.0" loose-envify "^1.1.0"
scheduler "^0.23.0" scheduler "^0.23.0"
react-fast-compare@^3.0.1: react-draggable@^4.0.3:
version "3.2.0" version "4.4.5"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.5.tgz#9e37fe7ce1a4cf843030f521a0a4cc41886d7e7c"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== integrity sha512-OMHzJdyJbYTZo4uQE393fHcqqPYsEtkjfMgvCHr6rejT+Ezn4OZbNyGH50vv+SunC1RMvwOTSWkEODQLzw1M9g==
dependencies:
clsx "^1.1.1"
prop-types "^15.8.1"
react-is@^16.13.1, react-is@^16.6.0, react-is@^16.6.3, react-is@^16.7.0, react-is@^16.8.1: react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
"react-is@^16.8.6 || ^17.0.0 || ^18.0.0":
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-is@^18.0.0: react-is@^18.0.0:
version "18.1.0" version "18.1.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67"
integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==
react-popper@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba"
integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==
dependencies:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-redux@8.0.5: react-redux@8.0.5:
version "8.0.5" version "8.0.5"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd"
@@ -4720,6 +4873,14 @@ react-refresh@^0.14.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
react-resizable@^1.8.0:
version "1.11.1"
resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-1.11.1.tgz#02ca6850afa7a22c1b3e623e64aef71ee252af69"
integrity sha512-S70gbLaAYqjuAd49utRHibtHLrHXInh7GuOR+6OO6RO6uleQfuBnWmZjRABfqNEx3C3Z6VPLg0/0uOYFrkfu9Q==
dependencies:
prop-types "15.x"
react-draggable "^4.0.3"
react-router-dom@5.3.0: react-router-dom@5.3.0:
version "5.3.0" version "5.3.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363"
@@ -4749,12 +4910,22 @@ react-router@5.2.1:
tiny-invariant "^1.0.2" tiny-invariant "^1.0.2"
tiny-warning "^1.0.0" tiny-warning "^1.0.0"
react-switch@7.0.0: react-sortable-hoc@^2.0.0:
version "7.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/react-switch/-/react-switch-7.0.0.tgz#400990bb9822864938e343ed24f13276a617bdc0" resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-2.0.0.tgz#f6780d8aa4b922a21f3e754af542f032677078b7"
integrity sha512-KkDeW+cozZXI6knDPyUt3KBN1rmhoVYgAdCJqAh7st7tk8YE6N0iR89zjCWO8T8dUTeJGTR0KU+5CHCRMRffiA== integrity sha512-JZUw7hBsAHXK7PTyErJyI7SopSBFRcFHDjWW5SWjcugY0i6iH7f+eJkY8cJmGMlZ1C9xz1J3Vjz0plFpavVeRg==
dependencies: dependencies:
prop-types "^15.7.2" "@babel/runtime" "^7.2.0"
invariant "^2.2.4"
prop-types "^15.5.7"
react-window@^1.8.2:
version "1.8.8"
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.8.tgz#1b52919f009ddf91970cbdb2050a6c7be44df243"
integrity sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==
dependencies:
"@babel/runtime" "^7.0.0"
memoize-one ">=3.1.1 <6"
react@18.2.0: react@18.2.0:
version "18.2.0" version "18.2.0"
@@ -4888,6 +5059,11 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
resolve-from@^4.0.0: resolve-from@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
@@ -4948,10 +5124,10 @@ rimraf@^3.0.2:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
rollup@^3.10.0: rollup@^3.18.0:
version "3.15.0" version "3.19.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.15.0.tgz#6f4105e8c4b8145229657b74ad660b02fbfacc05" resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.19.1.tgz#2b3a31ac1ff9f3afab2e523fa687fef5b0ee20fc"
integrity sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg== integrity sha512-lAbrdN7neYCg/8WaoWn/ckzCtz+jr70GFfYdlf50OF7387HTg+wiuiqJRFYawwSPpqfqDNYqK7smY/ks2iAudg==
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
@@ -5008,30 +5184,18 @@ scheduler@^0.23.0:
dependencies: dependencies:
loose-envify "^1.1.0" loose-envify "^1.1.0"
scroll-into-view-if-needed@^2.2.24:
version "2.2.31"
resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587"
integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
dependencies:
compute-scroll-into-view "^1.0.20"
selectn@^0.9.6: selectn@^0.9.6:
version "0.9.6" version "0.9.6"
resolved "https://registry.yarnpkg.com/selectn/-/selectn-0.9.6.tgz#bd873a556d18f96d8515fc91503ec6ff398ff9a2" resolved "https://registry.yarnpkg.com/selectn/-/selectn-0.9.6.tgz#bd873a556d18f96d8515fc91503ec6ff398ff9a2"
integrity sha1-vYc6VW0Y+W2FFfyRUD7G/zmP+aI= integrity sha1-vYc6VW0Y+W2FFfyRUD7G/zmP+aI=
semantic-ui-react@2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/semantic-ui-react/-/semantic-ui-react-2.1.4.tgz#8a877b169125bb7dd9321c53c425d6d46ac53862"
integrity sha512-7CxjBoFUfH7fUvtn+SPkkIocthUD9kV3niF1mUMa9TbeyPAf2brtRCZBlT2OpHaXmkscFzGjEfhbJo9gKfotzQ==
dependencies:
"@babel/runtime" "^7.10.5"
"@fluentui/react-component-event-listener" "~0.63.0"
"@fluentui/react-component-ref" "~0.63.0"
"@popperjs/core" "^2.6.0"
"@semantic-ui-react/event-stack" "^3.1.3"
clsx "^1.1.1"
keyboard-key "^1.1.0"
lodash "^4.17.21"
lodash-es "^4.17.21"
prop-types "^15.7.2"
react-is "^16.8.6 || ^17.0.0 || ^18.0.0"
react-popper "^2.3.0"
shallowequal "^1.1.0"
semver-compare@^1.0.0: semver-compare@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
@@ -5100,11 +5264,6 @@ setprototypeof@1.2.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
shebang-command@^2.0.0: shebang-command@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -5626,6 +5785,11 @@ util@0.10.3:
dependencies: dependencies:
inherits "2.0.1" inherits "2.0.1"
utility-types@^3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
value-equal@^1.0.1: value-equal@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
@@ -5636,25 +5800,18 @@ vary@^1.0.0:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
vite@4.1.4: vite@4.2.0:
version "4.1.4" version "4.2.0"
resolved "https://registry.yarnpkg.com/vite/-/vite-4.1.4.tgz#170d93bcff97e0ebc09764c053eebe130bfe6ca0" resolved "https://registry.yarnpkg.com/vite/-/vite-4.2.0.tgz#d4e6eafbc034f3faf0ab376bd5b76ac15775eb99"
integrity sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg== integrity sha512-AbDTyzzwuKoRtMIRLGNxhLRuv1FpRgdIw+1y6AQG73Q5+vtecmvzKo/yk8X/vrHDpETRTx01ABijqUHIzBXi0g==
dependencies: dependencies:
esbuild "^0.16.14" esbuild "^0.17.5"
postcss "^8.4.21" postcss "^8.4.21"
resolve "^1.22.1" resolve "^1.22.1"
rollup "^3.10.0" rollup "^3.18.0"
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
warning@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"
web-streams-polyfill@^3.0.3: web-streams-polyfill@^3.0.3:
version "3.2.1" version "3.2.1"
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"