mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
committed by
GitHub
parent
2c5eceb0c1
commit
d7c9c4bf76
@@ -203,10 +203,6 @@ module.exports = {
|
||||
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
|
||||
'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
|
||||
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md
|
||||
'react/sort-comp': 'off',
|
||||
@@ -237,7 +233,7 @@ module.exports = {
|
||||
|
||||
// only .jsx files may have JSX
|
||||
// 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
|
||||
// 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
|
||||
'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',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
|
||||
<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%">
|
||||
|
||||
<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%">
|
||||
|
||||
<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 align="center">
|
||||
|
||||
|
||||
BIN
doc/screenshot1.png
Normal file
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
BIN
doc/screenshot_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 323 KiB |
BIN
doc/screenshot_3.png
Normal file
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 |
@@ -4,12 +4,11 @@
|
||||
<meta charset="UTF-8"
|
||||
name="viewport"
|
||||
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">
|
||||
|
||||
<title>Fredy</title>
|
||||
</head>
|
||||
<body>
|
||||
<body theme-mode="dark">
|
||||
|
||||
<div id="fredy" style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;"></div>
|
||||
</body>
|
||||
|
||||
19
package.json
19
package.json
@@ -7,9 +7,9 @@
|
||||
"dev": "yarn && rm -rf ./ui/public/* && vite",
|
||||
"ui": "rm -rf ./ui/public/* && vite",
|
||||
"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",
|
||||
"lint": "eslint ./index.js ./lib/**/*.js ./test/**/*.js"
|
||||
"lint": "eslint ./index.js ./lib/**/*.js ./test/**/*.js ./ui/src/**/*.jsx"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
@@ -55,6 +55,7 @@
|
||||
"Firefox ESR"
|
||||
],
|
||||
"dependencies": {
|
||||
"@douyinfe/semi-ui": "2.31.0",
|
||||
"@rematch/core": "2.2.0",
|
||||
"@rematch/loading": "2.1.2",
|
||||
"@sendgrid/mail": "7.7.0",
|
||||
@@ -65,7 +66,7 @@
|
||||
"handlebars": "4.7.7",
|
||||
"highcharts": "10.3.3",
|
||||
"highcharts-react-official": "3.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash": "4.17.21",
|
||||
"lowdb": "5.1.0",
|
||||
"markdown": "^0.5.0",
|
||||
"nanoid": "4.0.1",
|
||||
@@ -77,33 +78,31 @@
|
||||
"react-redux": "8.0.5",
|
||||
"react-router": "5.2.1",
|
||||
"react-router-dom": "5.3.0",
|
||||
"react-switch": "7.0.0",
|
||||
"redux": "4.2.1",
|
||||
"redux-thunk": "2.4.2",
|
||||
"restana": "4.9.7",
|
||||
"semantic-ui-react": "2.1.4",
|
||||
"serve-static": "1.15.0",
|
||||
"slack": "11.0.2",
|
||||
"string-similarity": "^4.0.4",
|
||||
"vite": "4.1.4",
|
||||
"vite": "4.2.0",
|
||||
"x-ray": "2.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esmock": "2.1.0",
|
||||
"@babel/core": "7.21.0",
|
||||
"@babel/eslint-parser": "7.19.1",
|
||||
"@babel/core": "7.21.3",
|
||||
"@babel/eslint-parser": "7.21.3",
|
||||
"@babel/preset-env": "7.20.2",
|
||||
"@babel/preset-react": "7.18.6",
|
||||
"chai": "4.3.7",
|
||||
"eslint": "8.36.0",
|
||||
"eslint-config-prettier": "8.7.0",
|
||||
"eslint-plugin-react": "7.32.2",
|
||||
"esmock": "2.1.0",
|
||||
"history": "5.3.0",
|
||||
"husky": "4.3.8",
|
||||
"less": "4.1.3",
|
||||
"lint-staged": "13.2.0",
|
||||
"mocha": "10.2.0",
|
||||
"prettier": "2.8.4",
|
||||
"prettier": "2.8.5",
|
||||
"redux-logger": "3.0.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,10 @@ import React, { useEffect } from 'react';
|
||||
import InsufficientPermission from './components/permission/InsufficientPermission';
|
||||
import PermissionAwareRoute from './components/permission/PermissionAwareRoute';
|
||||
import GeneralSettings from './views/generalSettings/GeneralSettings';
|
||||
import ToastsContainer from './components/toasts/ToastContainer';
|
||||
import JobMutation from './views/jobs/mutation/JobMutation';
|
||||
import UserMutator from './views/user/mutation/UserMutator';
|
||||
import ToastContext from './components/toasts/ToastContext';
|
||||
import JobInsight from './views/jobs/insights/JobInsight.jsx';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import useToast from './components/toasts/useToast';
|
||||
import { Switch, Redirect } from 'react-router-dom';
|
||||
import Logout from './components/logout/Logout';
|
||||
import Logo from './components/logo/Logo';
|
||||
@@ -23,20 +20,21 @@ import './App.less';
|
||||
|
||||
export default function FredyApp() {
|
||||
const dispatch = useDispatch();
|
||||
const [showToast, onToastFinished, toasts] = useToast();
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const currentUser = useSelector((state) => state.user.currentUser);
|
||||
|
||||
useEffect(() => {
|
||||
async function init() {
|
||||
await dispatch.provider.getProvider();
|
||||
await dispatch.jobs.getJobs();
|
||||
await dispatch.jobs.getProcessingTimes();
|
||||
await dispatch.notificationAdapter.getAdapter();
|
||||
await dispatch.user.getCurrentUser();
|
||||
|
||||
if (!needsLogin()) {
|
||||
await dispatch.provider.getProvider();
|
||||
await dispatch.jobs.getJobs();
|
||||
await dispatch.jobs.getProcessingTimes();
|
||||
await dispatch.notificationAdapter.getAdapter();
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
init();
|
||||
}, [currentUser?.userId]);
|
||||
|
||||
@@ -56,44 +54,41 @@ export default function FredyApp() {
|
||||
return loading ? null : needsLogin() ? (
|
||||
login()
|
||||
) : (
|
||||
<ToastContext.Provider value={{ showToast }}>
|
||||
<div className="app">
|
||||
<div className="app__container">
|
||||
<Logout />
|
||||
<Logo width={190} white />
|
||||
<Menu isAdmin={isAdmin()} />
|
||||
<ToastsContainer toasts={toasts} onToastFinished={onToastFinished} />
|
||||
<Switch>
|
||||
<Route name="Insufficient Permission" path={'/403'} component={InsufficientPermission} />
|
||||
<Route name="Create new Job" path={'/jobs/new'} component={JobMutation} />
|
||||
<Route name="Edit a Job" path={'/jobs/edit/:jobId'} component={JobMutation} />
|
||||
<Route name="Insights into a Job" path={'/jobs/insights/:jobId'} component={JobInsight} />
|
||||
<Route name="Job overview" path={'/jobs'} component={Jobs} />
|
||||
<PermissionAwareRoute
|
||||
name="Create new User"
|
||||
path="/users/new"
|
||||
component={<UserMutator />}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
<PermissionAwareRoute
|
||||
name="Edit a user"
|
||||
path="/users/edit/:userId"
|
||||
component={<UserMutator />}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
<PermissionAwareRoute name="Users" path="/users" component={<Users />} currentUser={currentUser} />
|
||||
<PermissionAwareRoute
|
||||
name="General Settings"
|
||||
path="/generalSettings"
|
||||
component={<GeneralSettings />}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
<div className="app">
|
||||
<div className="app__container">
|
||||
<Logout />
|
||||
<Logo width={190} white />
|
||||
<Menu isAdmin={isAdmin()} />
|
||||
<Switch>
|
||||
<Route name="Insufficient Permission" path={'/403'} component={InsufficientPermission} />
|
||||
<Route name="Create new Job" path={'/jobs/new'} component={JobMutation} />
|
||||
<Route name="Edit a Job" path={'/jobs/edit/:jobId'} component={JobMutation} />
|
||||
<Route name="Insights into a Job" path={'/jobs/insights/:jobId'} component={JobInsight} />
|
||||
<Route name="Job overview" path={'/jobs'} component={Jobs} />
|
||||
<PermissionAwareRoute
|
||||
name="Create new User"
|
||||
path="/users/new"
|
||||
component={<UserMutator />}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
<PermissionAwareRoute
|
||||
name="Edit a user"
|
||||
path="/users/edit/:userId"
|
||||
component={<UserMutator />}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
<PermissionAwareRoute name="Users" path="/users" component={<Users />} currentUser={currentUser} />
|
||||
<PermissionAwareRoute
|
||||
name="General Settings"
|
||||
path="/generalSettings"
|
||||
component={<GeneralSettings />}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
|
||||
<Redirect from="/" to={'/jobs'} />
|
||||
</Switch>
|
||||
</div>
|
||||
<Redirect from="/" to={'/jobs'} />
|
||||
</Switch>
|
||||
</div>
|
||||
</ToastContext.Provider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
width:100%;
|
||||
|
||||
&__container {
|
||||
width: 100%;
|
||||
|
||||
padding: 1rem 1rem;
|
||||
background-color: #595959f5;
|
||||
color: #f1f1f1;
|
||||
color: var(--semi-color-text-0);
|
||||
background-color: #232429;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +16,28 @@
|
||||
|
||||
.ui.black.label, .ui.black.labels .label {
|
||||
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;
|
||||
}
|
||||
@@ -5,9 +5,11 @@ import { HashRouter } from 'react-router-dom';
|
||||
import { createHashHistory } from 'history';
|
||||
import { Provider } from 'react-redux';
|
||||
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 root = createRoot(container);
|
||||
|
||||
const history = createHashHistory();
|
||||
|
||||
import App from './App';
|
||||
@@ -17,7 +19,9 @@ import './Index.less';
|
||||
root.render(
|
||||
<Provider store={reduxStore}>
|
||||
<HashRouter history={history}>
|
||||
<App />
|
||||
<LocaleProvider locale={en_US}>
|
||||
<App />
|
||||
</LocaleProvider>
|
||||
</HashRouter>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
@@ -2,5 +2,14 @@ body, html {
|
||||
margin: 0;
|
||||
height: 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;
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
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 = 'medium', className = '' } = {}) {
|
||||
export default function Headline({ text, size = 3 } = {}) {
|
||||
const { Title } = Typography;
|
||||
return (
|
||||
<Header className={`headline ${className}`} size={size}>
|
||||
<Title heading={size} style={{ marginBottom: '1rem' }}>
|
||||
{text}
|
||||
</Header>
|
||||
</Title>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.headline{
|
||||
color: #f1f1f1 !important;
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import React from 'react';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { Button } from '@douyinfe/semi-ui';
|
||||
import { xhrPost } from '../../services/xhr';
|
||||
|
||||
import { IconUser } from '@douyinfe/semi-icons';
|
||||
const Logout = function Logout() {
|
||||
return (
|
||||
<Button
|
||||
content="Logout"
|
||||
labelPosition="left"
|
||||
icon="user"
|
||||
size="mini"
|
||||
icon={<IconUser />}
|
||||
type="danger"
|
||||
theme="solid"
|
||||
onClick={async () => {
|
||||
await xhrPost('/api/login/logout');
|
||||
location.reload();
|
||||
}}
|
||||
negative
|
||||
/>
|
||||
>
|
||||
Logout
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,49 +1,54 @@
|
||||
import React from 'react';
|
||||
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 { 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 history = useHistory();
|
||||
const location = useLocation();
|
||||
|
||||
const isActiveRoute = (name) => location.pathname.indexOf(name) !== -1;
|
||||
|
||||
return (
|
||||
<Menu pointing secondary className="topMenu">
|
||||
<Menu.Item
|
||||
name="jobs"
|
||||
active={isActiveRoute('jobs')}
|
||||
className={isActiveRoute('jobs') ? 'topMenu__active' : 'topMenu__item'}
|
||||
onClick={() => history.push('/jobs')}
|
||||
>
|
||||
<Icon name="search" /> Job Configuration
|
||||
</Menu.Item>
|
||||
<Tabs type="line" activeKey={parsePathName(location.pathname)} onTabClick={(key) => history.push(key)}>
|
||||
<TabPane
|
||||
itemKey="/jobs"
|
||||
tab={
|
||||
<span>
|
||||
<IconTerminal />
|
||||
Jobs
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
|
||||
{isAdmin && (
|
||||
<Menu.Item
|
||||
name="user"
|
||||
active={isActiveRoute('users')}
|
||||
className={isActiveRoute('users') ? 'topMenu__active' : 'topMenu__item'}
|
||||
onClick={() => history.push('/users')}
|
||||
>
|
||||
<Icon name="user" /> User configuration
|
||||
</Menu.Item>
|
||||
<TabPane
|
||||
itemKey="/users"
|
||||
tab={
|
||||
<span>
|
||||
<IconUser />
|
||||
User
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isAdmin && (
|
||||
<Menu.Item
|
||||
name="general"
|
||||
active={isActiveRoute('general')}
|
||||
className={isActiveRoute('general') ? 'topMenu__active' : 'topMenu__item'}
|
||||
onClick={() => history.push('/generalSettings')}
|
||||
>
|
||||
<Icon name="cog" /> General Settings
|
||||
</Menu.Item>
|
||||
<TabPane
|
||||
itemKey="/generalSettings"
|
||||
tab={
|
||||
<span>
|
||||
<IconSetting />
|
||||
General
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Menu>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { Header } from 'semantic-ui-react';
|
||||
import insufficientPermission from '../../assets/insufficient_permission.png';
|
||||
|
||||
export default function InsufficientPermission() {
|
||||
@@ -7,9 +6,7 @@ export default function InsufficientPermission() {
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', flexDirection: 'column' }}>
|
||||
<img src={insufficientPermission} height={250} />
|
||||
<br />
|
||||
<Header as="h4" inverted>
|
||||
Insufficient permission :(
|
||||
</Header>
|
||||
<h4>Insufficient permission :(</h4>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
import React from 'react';
|
||||
import { Header, Icon, Popup, Segment } from 'semantic-ui-react';
|
||||
import { Card } from '@douyinfe/semi-ui';
|
||||
|
||||
import './SegmentParts.less';
|
||||
|
||||
export const SegmentPart = ({ name, icon = null, children, helpText }) => (
|
||||
<Segment inverted>
|
||||
<Header as="h5" inverted sub>
|
||||
{icon && <Icon name={icon} inverted size="mini" />}
|
||||
<Header.Content>{name}</Header.Content>
|
||||
</Header>
|
||||
export const SegmentPart = ({ name, Icon = null, children, helpText }) => {
|
||||
const { Meta } = Card;
|
||||
|
||||
<Popup
|
||||
content={helpText}
|
||||
trigger={
|
||||
<span className="generalSettings__help">
|
||||
{' '}
|
||||
<Icon name="help circle" inverted />
|
||||
What is this?
|
||||
</span>
|
||||
return (
|
||||
<Card
|
||||
title={
|
||||
<Meta title={name} description={helpText} avatar={Icon == null ? null : <Icon size="extra-extra-small" />} />
|
||||
}
|
||||
/>
|
||||
<Segment inverted className="segmentParts">
|
||||
>
|
||||
{children}
|
||||
</Segment>
|
||||
</Segment>
|
||||
);
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,66 +1,79 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { Table, Button } from 'semantic-ui-react';
|
||||
import Switch from 'react-switch';
|
||||
|
||||
const emptyTable = () => {
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell collapsing colSpan={6} style={{ textAlign: 'center' }}>
|
||||
No Data
|
||||
</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>
|
||||
);
|
||||
};
|
||||
import { Button, Empty, Table, Switch } from '@douyinfe/semi-ui';
|
||||
import { IconDelete, IconEdit, IconHistogram } from '@douyinfe/semi-icons';
|
||||
import { IllustrationNoResult, IllustrationNoResultDark } from '@douyinfe/semi-illustrations';
|
||||
const empty = (
|
||||
<Empty
|
||||
image={<IllustrationNoResult />}
|
||||
darkModeImage={<IllustrationNoResultDark />}
|
||||
description={'No jobs available'}
|
||||
/>
|
||||
);
|
||||
|
||||
export default function JobTable({ jobs = {}, onJobRemoval, onJobStatusChanged, onJobEdit, onJobInsight } = {}) {
|
||||
return (
|
||||
<Table singleLine inverted>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell />
|
||||
<Table.HeaderCell>Job Name</Table.HeaderCell>
|
||||
<Table.HeaderCell>Number of findings</Table.HeaderCell>
|
||||
<Table.HeaderCell>Active provider</Table.HeaderCell>
|
||||
<Table.HeaderCell>Active notification adapter</Table.HeaderCell>
|
||||
<Table.HeaderCell></Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
|
||||
<Table.Body>
|
||||
{Object.keys(jobs).length === 0
|
||||
? emptyTable()
|
||||
: content(jobs, onJobRemoval, onJobStatusChanged, onJobEdit, onJobInsight)}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
<Table
|
||||
pagination={false}
|
||||
empty={empty}
|
||||
columns={[
|
||||
{
|
||||
title: '',
|
||||
dataIndex: '',
|
||||
render: (job) => {
|
||||
return <Switch onChange={(checked) => onJobStatusChanged(job.id, checked)} checked={job.enabled} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Job Name',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: 'Number of findings',
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,50 +1,38 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { Table, Button } from 'semantic-ui-react';
|
||||
|
||||
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>
|
||||
);
|
||||
};
|
||||
import { Empty, Table, Button } from '@douyinfe/semi-ui';
|
||||
import { IconDelete, IconEdit } from '@douyinfe/semi-icons';
|
||||
|
||||
export default function NotificationAdapterTable({ notificationAdapter = [], onRemove, onEdit } = {}) {
|
||||
return (
|
||||
<Table singleLine inverted>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>Notification Adapter Name</Table.HeaderCell>
|
||||
<Table.HeaderCell></Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table
|
||||
pagination={false}
|
||||
empty={<Empty description="No Data" />}
|
||||
columns={[
|
||||
{
|
||||
title: 'Notification Adapter Name',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
|
||||
<Table.Body>
|
||||
{notificationAdapter.length === 0 ? emptyTable() : content(notificationAdapter, onRemove, onEdit)}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'tools',
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,53 +1,42 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { Table, Button } from 'semantic-ui-react';
|
||||
|
||||
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>
|
||||
);
|
||||
};
|
||||
import { Empty, Table, Button } from '@douyinfe/semi-ui';
|
||||
import { IconDelete } from '@douyinfe/semi-icons';
|
||||
|
||||
export default function ProviderTable({ providerData = [], onRemove } = {}) {
|
||||
return (
|
||||
<Table singleLine inverted>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>Provider Name</Table.HeaderCell>
|
||||
<Table.HeaderCell>Url</Table.HeaderCell>
|
||||
<Table.HeaderCell></Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
|
||||
<Table.Body>{providerData.length === 0 ? emptyTable() : content(providerData, onRemove)}</Table.Body>
|
||||
</Table>
|
||||
<Table
|
||||
pagination={false}
|
||||
empty={<Empty description="No Provider available" />}
|
||||
columns={[
|
||||
{
|
||||
title: 'Provider Name',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: 'Provider Url',
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,49 +1,58 @@
|
||||
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 { Table, Button, Empty } from '@douyinfe/semi-ui';
|
||||
import { IconDelete, IconEdit } from '@douyinfe/semi-icons';
|
||||
|
||||
const emptyTable = () => {
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell collapsing colSpan={4} style={{ textAlign: 'center' }}>
|
||||
No Data
|
||||
</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>
|
||||
);
|
||||
});
|
||||
};
|
||||
const empty = (
|
||||
<Empty
|
||||
image={<IllustrationNoResult />}
|
||||
darkModeImage={<IllustrationNoResultDark />}
|
||||
description={'No user available'}
|
||||
/>
|
||||
);
|
||||
|
||||
export default function UserTable({ user = [], onUserRemoval, onUserEdit } = {}) {
|
||||
return (
|
||||
<Table inverted>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>Username</Table.HeaderCell>
|
||||
<Table.HeaderCell>Last login</Table.HeaderCell>
|
||||
<Table.HeaderCell>Number of jobs</Table.HeaderCell>
|
||||
<Table.HeaderCell></Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
|
||||
<Table.Body>{user.length === 0 ? emptyTable() : content(user, onUserRemoval, onUserEdit)}</Table.Body>
|
||||
</Table>
|
||||
<Table
|
||||
pagination={false}
|
||||
empty={empty}
|
||||
columns={[
|
||||
{
|
||||
title: 'Username',
|
||||
dataIndex: 'username',
|
||||
},
|
||||
{
|
||||
title: 'Last login',
|
||||
dataIndex: 'lastLogin',
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
const CheckoutDrawerContext = createContext({
|
||||
showToast: () => {},
|
||||
});
|
||||
|
||||
export default CheckoutDrawerContext;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
@@ -2,14 +2,32 @@ import React from 'react';
|
||||
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { Button, Form, Icon, Message, Segment, Radio } from 'semantic-ui-react';
|
||||
import ToastContext from '../../components/toasts/ToastContext';
|
||||
import { Divider, Input, Radio, TimePicker, Button, RadioGroup } from '@douyinfe/semi-ui';
|
||||
import { InputNumber } from '@douyinfe/semi-ui';
|
||||
import Headline from '../../components/headline/Headline';
|
||||
import { xhrPost } from '../../services/xhr';
|
||||
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';
|
||||
|
||||
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 [loading, setLoading] = React.useState(true);
|
||||
|
||||
@@ -21,13 +39,12 @@ const GeneralSettings = function Users() {
|
||||
const [scrapingAntProxy, setScrapingAntProxy] = React.useState('');
|
||||
const [workingHourFrom, setWorkingHourFrom] = React.useState(null);
|
||||
const [workingHourTo, setWorkingHourTo] = React.useState(null);
|
||||
const ctx = React.useContext(ToastContext);
|
||||
|
||||
React.useEffect(() => {
|
||||
async function init() {
|
||||
await dispatch.generalSettings.getGeneralSettings();
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
init();
|
||||
}, []);
|
||||
|
||||
@@ -40,19 +57,18 @@ const GeneralSettings = function Users() {
|
||||
setWorkingHourTo(settings?.workingHours?.to);
|
||||
setScrapingAntProxy(settings?.scrapingAnt?.proxy || 'datacenter');
|
||||
}
|
||||
|
||||
init();
|
||||
}, [settings]);
|
||||
|
||||
const nullOrEmpty = (val) => val == null || val.length === 0;
|
||||
|
||||
const throwMessage = (message, type) => {
|
||||
ctx.showToast({
|
||||
title: type === 'error' ? 'Error' : 'Success',
|
||||
message: message,
|
||||
delay: 5000,
|
||||
backgroundColor: type === 'error' ? '#db2828' : '#87eb8f',
|
||||
color: type === 'error' ? '#fff' : '#000',
|
||||
});
|
||||
if (type === 'error') {
|
||||
Toast.error(message);
|
||||
} else {
|
||||
Toast.success(message);
|
||||
}
|
||||
};
|
||||
|
||||
const onStore = async () => {
|
||||
@@ -97,139 +113,130 @@ const GeneralSettings = function Users() {
|
||||
{!loading && (
|
||||
<React.Fragment>
|
||||
<Headline text="General Settings" />
|
||||
<Message className="generalSettings__message">
|
||||
<h5>
|
||||
<Icon name="info circle" />
|
||||
Info
|
||||
</h5>
|
||||
<p>If you change any settings, you must restart Fredy afterwards.</p>
|
||||
</Message>
|
||||
<Form>
|
||||
<Banner
|
||||
fullMode={false}
|
||||
type="info"
|
||||
closeIcon={null}
|
||||
title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>Info</div>}
|
||||
style={{ marginBottom: '1rem' }}
|
||||
description="If you change any settings, you must restart Fredy afterwards."
|
||||
/>
|
||||
<div>
|
||||
<SegmentPart
|
||||
name="Interval"
|
||||
helpText="Interval in minutes for running queries against the configured services."
|
||||
icon="refresh"
|
||||
Icon={IconRefresh}
|
||||
>
|
||||
<Form.Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1440"
|
||||
<InputNumber
|
||||
min={0}
|
||||
max={1440}
|
||||
placeholder="Interval in minutes"
|
||||
inverted
|
||||
size="mini"
|
||||
width={6}
|
||||
defaultValue={interval}
|
||||
onChange={(e) => setInterval(e.target.value)}
|
||||
value={interval}
|
||||
formatter={(value) => `${value}`.replace(/\D/g, '')}
|
||||
onChange={(value) => setInterval(value)}
|
||||
suffix={'minutes'}
|
||||
/>
|
||||
</SegmentPart>
|
||||
|
||||
<SegmentPart name="Port" helpText="Port on which Fredy is running." icon="connectdevelop">
|
||||
<Form.Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="99999"
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart name="Port" helpText="Port on which Fredy is running." Icon={IconSignal}>
|
||||
<InputNumber
|
||||
min={0}
|
||||
max={99999}
|
||||
placeholder="Port"
|
||||
inverted
|
||||
size="mini"
|
||||
width={6}
|
||||
defaultValue={port}
|
||||
onChange={(e) => setPort(e.target.value)}
|
||||
value={port}
|
||||
formatter={(value) => `${value}`.replace(/\D/g, '')}
|
||||
onChange={(value) => setPort(value)}
|
||||
/>
|
||||
</SegmentPart>
|
||||
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart
|
||||
name="ScrapingAnt Api Key"
|
||||
helpText="The api key for ScrapingAnt is used to be able to scrape Immoscout."
|
||||
icon="key"
|
||||
Icon={IconKey}
|
||||
>
|
||||
<Form.Input
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="ScrapingAnt Api Key"
|
||||
inverted
|
||||
size="mini"
|
||||
width={6}
|
||||
defaultValue={scrapingAntApiKey}
|
||||
onChange={(e) => setScrapingAntApiKey(e.target.value)}
|
||||
value={scrapingAntApiKey}
|
||||
onChange={(val) => setScrapingAntApiKey(val)}
|
||||
/>
|
||||
</SegmentPart>
|
||||
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart
|
||||
name="ScrapingAnt proxy settings"
|
||||
helpText="Scraping ant provides different proxies."
|
||||
icon="key"
|
||||
Icon={IconKey}
|
||||
>
|
||||
<Message info>
|
||||
ScrapingAnt is needed to scrape Immoscout. ScrapingAnt itself is using 2 different types of proxies.{' '}
|
||||
<br />
|
||||
<h4>Datacenter-Proxy</h4>
|
||||
Proxy server located in one of the datacenters across the world. Datacenter proxies are slower and more
|
||||
likely to fail, but they are cheaper. A call with a datacenter proxy cost 10 credits.
|
||||
<h4>Residential-Proxy</h4>
|
||||
High-quality proxy server located in one of the real people houses across the world. Datacenter proxies
|
||||
are faster and more likely to success, but they are more expensive. A call with a datacenter proxy cost
|
||||
250 credits.
|
||||
<br />
|
||||
<br />
|
||||
<b>
|
||||
On the free tier, you have 10.000 credits, so chose your option wisely. Keep in mind, only successful
|
||||
calls will be charged.
|
||||
</b>
|
||||
</Message>
|
||||
<Form.Field>
|
||||
<Radio
|
||||
label="Datacenter proxy"
|
||||
name="scrapingAntProxy"
|
||||
value="datacenter"
|
||||
checked={scrapingAntProxy === 'datacenter'}
|
||||
onChange={(e, { value }) => setScrapingAntProxy(value)}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Radio
|
||||
label="Residential proxy"
|
||||
name="scrapingAntProxy"
|
||||
value="residential"
|
||||
checked={scrapingAntProxy === 'residential'}
|
||||
onChange={(e, { value }) => setScrapingAntProxy(value)}
|
||||
/>
|
||||
</Form.Field>
|
||||
</SegmentPart>
|
||||
<Banner
|
||||
fullMode={false}
|
||||
type="info"
|
||||
closeIcon={null}
|
||||
title={
|
||||
<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>
|
||||
ScrapingAnt is needed to scrape Immoscout. ScrapingAnt itself is using 2 different types of proxies
|
||||
</div>
|
||||
}
|
||||
style={{ marginBottom: '1rem' }}
|
||||
description={
|
||||
<div>
|
||||
<h4>Datacenter-Proxy</h4>
|
||||
Proxy server located in one of the datacenters across the world. Datacenter proxies are slower and
|
||||
more likely to fail, but they are cheaper. A call with a datacenter proxy cost 10 credits.
|
||||
<h4>Residential-Proxy</h4>
|
||||
High-quality proxy server located in one of the real people houses across the world. Datacenter
|
||||
proxies are faster and more likely to success, but they are more expensive. A call with a datacenter
|
||||
proxy cost 250 credits.
|
||||
<br />
|
||||
<br />
|
||||
<b>
|
||||
On the free tier, you have 10.000 credits, so chose your option wisely. Keep in mind, only
|
||||
successful calls will be charged.
|
||||
</b>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<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
|
||||
name="Working hours"
|
||||
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">
|
||||
<Form.Input
|
||||
className="generalSettings__time"
|
||||
type="time"
|
||||
placeholder="Working hours from"
|
||||
inverted
|
||||
size="mini"
|
||||
width={2}
|
||||
defaultValue={workingHourFrom}
|
||||
onChange={(e) => setWorkingHourFrom(e.target.value)}
|
||||
<TimePicker
|
||||
format={'HH:mm'}
|
||||
insetLabel="From"
|
||||
value={formatFromTBackend(workingHourFrom)}
|
||||
placeholder=""
|
||||
onChange={(val) => {
|
||||
setWorkingHourFrom(val == null ? null : formatFromTimestamp(val));
|
||||
}}
|
||||
/>
|
||||
<div className="generalSettings__until">until</div>
|
||||
<Form.Input
|
||||
type="time"
|
||||
placeholder="Working hours to"
|
||||
inverted
|
||||
size="mini"
|
||||
width={2}
|
||||
defaultValue={workingHourTo}
|
||||
onChange={(e) => setWorkingHourTo(e.target.value)}
|
||||
<TimePicker
|
||||
format={'HH:mm'}
|
||||
insetLabel="Until"
|
||||
value={formatFromTBackend(workingHourTo)}
|
||||
placeholder=""
|
||||
onChange={(val) => {
|
||||
setWorkingHourTo(val == null ? null : formatFromTimestamp(val));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</SegmentPart>
|
||||
|
||||
<Segment inverted floated="right">
|
||||
<Button color="teal" onClick={onStore}>
|
||||
Save
|
||||
</Button>
|
||||
</Segment>
|
||||
</Form>
|
||||
<Divider margin="1rem" />
|
||||
<Button type="primary" theme="solid" onClick={onStore} icon={<IconSave />}>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
&__timePickerContainer {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
&__until {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
&__help{
|
||||
@@ -14,8 +10,4 @@
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
&__message{
|
||||
background: #8fe8ff!important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import ToastContext from '../../components/toasts/ToastContext';
|
||||
import JobTable from '../../components/table/JobTable';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { xhrDelete, xhrPut } from '../../services/xhr';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import ProcessingTimes from './ProcessingTimes';
|
||||
|
||||
import { Button, Toast } from '@douyinfe/semi-ui';
|
||||
import { IconPlusCircle } from '@douyinfe/semi-icons';
|
||||
import './Jobs.less';
|
||||
|
||||
export default function Jobs() {
|
||||
@@ -15,49 +14,24 @@ export default function Jobs() {
|
||||
const processingTimes = useSelector((state) => state.jobs.processingTimes);
|
||||
const history = useHistory();
|
||||
const dispatch = useDispatch();
|
||||
const ctx = React.useContext(ToastContext);
|
||||
|
||||
const onJobRemoval = async (jobId) => {
|
||||
try {
|
||||
await xhrDelete('/api/jobs', { jobId });
|
||||
ctx.showToast({
|
||||
title: 'Success',
|
||||
message: 'Job successfully remove',
|
||||
delay: 5000,
|
||||
backgroundColor: '#87eb8f',
|
||||
color: '#000',
|
||||
});
|
||||
Toast.success('Job successfully remove');
|
||||
await dispatch.jobs.getJobs();
|
||||
} catch (error) {
|
||||
ctx.showToast({
|
||||
title: 'Error',
|
||||
message: error,
|
||||
delay: 35000,
|
||||
backgroundColor: '#db2828',
|
||||
color: '#fff',
|
||||
});
|
||||
Toast.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const onJobStatusChanged = async (jobId, status) => {
|
||||
try {
|
||||
await xhrPut(`/api/jobs/${jobId}/status`, { status });
|
||||
ctx.showToast({
|
||||
title: 'Success',
|
||||
message: 'Job status successfully changed',
|
||||
delay: 5000,
|
||||
backgroundColor: '#87eb8f',
|
||||
color: '#000',
|
||||
});
|
||||
Toast.success('Job status successfully changed');
|
||||
await dispatch.jobs.getJobs();
|
||||
} catch (error) {
|
||||
ctx.showToast({
|
||||
title: 'Error',
|
||||
message: error,
|
||||
delay: 35000,
|
||||
backgroundColor: '#db2828',
|
||||
color: '#fff',
|
||||
});
|
||||
Toast.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -65,8 +39,12 @@ export default function Jobs() {
|
||||
<div>
|
||||
<div>
|
||||
{processingTimes != null && <ProcessingTimes processingTimes={processingTimes} />}
|
||||
<Button primary className="jobs__newButton" onClick={() => history.push('/jobs/new')}>
|
||||
<Icon name="plus" />
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<IconPlusCircle />}
|
||||
className="jobs__newButton"
|
||||
onClick={() => history.push('/jobs/new')}
|
||||
>
|
||||
New Job
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,51 +1,67 @@
|
||||
import React from 'react';
|
||||
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 }) {
|
||||
const { Meta } = Card;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div>
|
||||
<Label as="span" color="black">
|
||||
Processing Interval:
|
||||
<Label.Detail>{processingTimes.interval} min</Label.Detail>
|
||||
</Label>
|
||||
<>
|
||||
<Descriptions
|
||||
row
|
||||
size="small"
|
||||
style={{
|
||||
backgroundColor: '#35363c',
|
||||
borderRadius: '4px',
|
||||
padding: '10px',
|
||||
}}
|
||||
>
|
||||
<Descriptions.Item itemKey="Processing Interval">{processingTimes.interval} min</Descriptions.Item>
|
||||
{processingTimes.lastRun && (
|
||||
<React.Fragment>
|
||||
<Label as="span" color="black">
|
||||
Last run:
|
||||
<Label.Detail>{format(processingTimes.lastRun)}</Label.Detail>
|
||||
</Label>
|
||||
<Label as="span" color="black">
|
||||
Next run:
|
||||
<Label.Detail>{format(processingTimes.lastRun + processingTimes.interval * 60000)}</Label.Detail>
|
||||
</Label>
|
||||
</React.Fragment>
|
||||
<>
|
||||
<Descriptions.Item itemKey="Last run">{format(processingTimes.lastRun)}</Descriptions.Item>
|
||||
<Descriptions.Item itemKey="Next run">
|
||||
{format(processingTimes.lastRun + processingTimes.interval * 60000)}
|
||||
</Descriptions.Item>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Descriptions>
|
||||
|
||||
{processingTimes.scrapingAntData != null && (
|
||||
<Segment inverted>
|
||||
<Header as="h5">Remaining ScrapingAnt calls</Header>
|
||||
<Message.List>
|
||||
<Message.Item>Plan: {processingTimes.scrapingAntData.plan_name}</Message.Item>
|
||||
<Message.Item>
|
||||
<>
|
||||
<Divider margin="1rem" />
|
||||
<Card
|
||||
style={{ backgroundColor: '#35363c' }}
|
||||
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))} -{' '}
|
||||
{format(new Date(processingTimes.scrapingAntData.end_date))}
|
||||
</Message.Item>
|
||||
<Message.Item>
|
||||
<br />
|
||||
Credits: {processingTimes.scrapingAntData.remained_credits}/
|
||||
{processingTimes.scrapingAntData.plan_total_credits} (250 credits per call)
|
||||
</Message.Item>
|
||||
</Message.List>
|
||||
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">
|
||||
{' '}
|
||||
ScrapingAnt
|
||||
</a>
|
||||
. You can use the code <b>FREDY10</b> to get 10% off. (No affiliation, we are <b>not</b> getting paid to
|
||||
recommend ScrapingAnt.)
|
||||
</Segment>
|
||||
</p>
|
||||
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">
|
||||
ScrapingAnt
|
||||
</a>
|
||||
. You can use the code <b>FREDY10</b> to get 10% off. (No affiliation, we are <b>not</b> getting paid to
|
||||
recommend ScrapingAnt.)
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
</React.Fragment>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
@@ -2,19 +2,17 @@ import React, { Fragment, useState } from 'react';
|
||||
|
||||
import NotificationAdapterMutator from './components/notificationAdapter/NotificationAdapterMutator';
|
||||
import NotificationAdapterTable from '../../../components/table/NotificationAdapterTable';
|
||||
import { Icon, Form, Button, Label } from 'semantic-ui-react';
|
||||
import ProviderTable from '../../../components/table/ProviderTable';
|
||||
import ProviderMutator from './components/provider/ProviderMutator';
|
||||
import ToastContext from '../../../components/toasts/ToastContext';
|
||||
import Headline from '../../../components/headline/Headline';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { xhrPost } from '../../../services/xhr';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useParams } from 'react-router';
|
||||
|
||||
import { Divider, Input, Switch, Button, TagInput, Toast } from '@douyinfe/semi-ui';
|
||||
import './JobMutation.less';
|
||||
import Switch from 'react-switch';
|
||||
import { SegmentPart } from '../../../components/segment/SegmentPart';
|
||||
import { IconPlusCircle } from '@douyinfe/semi-icons';
|
||||
|
||||
export default function JobMutator() {
|
||||
const jobs = useSelector((state) => state.jobs.jobs);
|
||||
@@ -38,7 +36,6 @@ export default function JobMutator() {
|
||||
const [enabled, setEnabled] = useState(defaultEnabled);
|
||||
const history = useHistory();
|
||||
const dispatch = useDispatch();
|
||||
const ctx = React.useContext(ToastContext);
|
||||
|
||||
const isSavingEnabled = () => {
|
||||
return notificationAdapterData.length > 0 && providerData.length > 0 && name != null && name.length > 0;
|
||||
@@ -55,24 +52,11 @@ export default function JobMutator() {
|
||||
jobId: jobToBeEdit?.id || null,
|
||||
});
|
||||
await dispatch.jobs.getJobs();
|
||||
ctx.showToast({
|
||||
title: 'Success',
|
||||
message: 'Job successfully saved...',
|
||||
delay: 5000,
|
||||
backgroundColor: '#87eb8f',
|
||||
color: '#000',
|
||||
});
|
||||
Toast.success('Job successfully saved...');
|
||||
history.push('/jobs');
|
||||
} catch (Exception) {
|
||||
console.error(Exception.json.message);
|
||||
|
||||
ctx.showToast({
|
||||
title: 'Error',
|
||||
message: Exception.json != null ? Exception.json.message : Exception,
|
||||
delay: 8000,
|
||||
backgroundColor: '#db2828',
|
||||
color: '#fff',
|
||||
});
|
||||
Toast.error(Exception.json != null ? Exception.json.message : Exception);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -107,20 +91,19 @@ export default function JobMutator() {
|
||||
)}
|
||||
|
||||
<Headline text={jobToBeEdit ? 'Edit a Job' : 'Create a new Job'} />
|
||||
<Form>
|
||||
<form>
|
||||
<SegmentPart name="Name">
|
||||
<Form.Input
|
||||
<Input
|
||||
autofocus
|
||||
type="text"
|
||||
maxLength={40}
|
||||
placeholder="Name"
|
||||
autoFocus
|
||||
inverted
|
||||
width={6}
|
||||
defaultValue={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
value={name}
|
||||
onChange={(value) => setName(value)}
|
||||
/>
|
||||
</SegmentPart>
|
||||
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart
|
||||
name="Provider"
|
||||
icon="briefcase"
|
||||
@@ -130,10 +113,14 @@ export default function JobMutator() {
|
||||
'to search for new listings.'
|
||||
}
|
||||
>
|
||||
<Form.Button primary className="jobMutation__newButton" onClick={() => setProviderCreationVisibility(true)}>
|
||||
<Icon name="plus" />
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<IconPlusCircle />}
|
||||
className="jobMutation__newButton"
|
||||
onClick={() => setProviderCreationVisibility(true)}
|
||||
>
|
||||
Add new Provider
|
||||
</Form.Button>
|
||||
</Button>
|
||||
|
||||
<ProviderTable
|
||||
providerData={providerData}
|
||||
@@ -142,20 +129,20 @@ export default function JobMutator() {
|
||||
}}
|
||||
/>
|
||||
</SegmentPart>
|
||||
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart
|
||||
icon="bell"
|
||||
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."
|
||||
>
|
||||
<Form.Button
|
||||
primary
|
||||
<Button
|
||||
type="primary"
|
||||
className="jobMutation__newButton"
|
||||
icon={<IconPlusCircle />}
|
||||
onClick={() => setNotificationCreationVisibility(true)}
|
||||
>
|
||||
<Icon name="plus" />
|
||||
Add new Notification Adapter
|
||||
</Form.Button>
|
||||
</Button>
|
||||
|
||||
<NotificationAdapterTable
|
||||
notificationAdapter={notificationAdapterData}
|
||||
@@ -169,40 +156,19 @@ export default function JobMutator() {
|
||||
}}
|
||||
/>
|
||||
</SegmentPart>
|
||||
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart
|
||||
icon="bell"
|
||||
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
|
||||
type="text"
|
||||
maxLength={40}
|
||||
placeholder="Comma separated list of blacklisted words"
|
||||
autoFocus
|
||||
inverted
|
||||
width={6}
|
||||
onChange={(e) => {
|
||||
if (e.target.value.indexOf(',') !== -1) {
|
||||
setBlacklist([...blacklist, e.target.value.replace(',', '')]);
|
||||
e.target.value = '';
|
||||
}
|
||||
}}
|
||||
<TagInput
|
||||
value={blacklist || []}
|
||||
placeholder="Add a word for filtering..."
|
||||
onChange={(v) => setBlacklist([...v])}
|
||||
/>
|
||||
{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>
|
||||
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart
|
||||
icon="play circle outline"
|
||||
name="Job activation"
|
||||
@@ -210,14 +176,14 @@ export default function JobMutator() {
|
||||
>
|
||||
<Switch className="jobMutation__spaceTop" onChange={(checked) => setEnabled(checked)} checked={enabled} />
|
||||
</SegmentPart>
|
||||
|
||||
<Button color="red" onClick={() => history.push('/jobs')}>
|
||||
<Divider margin="1rem" />
|
||||
<Button type="danger" style={{ marginRight: '1rem' }} onClick={() => history.push('/jobs')}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button color="green" disabled={!isSavingEnabled()} onClick={mutateJob}>
|
||||
<Button type="primary" icon={<IconPlusCircle />} disabled={!isSavingEnabled()} onClick={mutateJob}>
|
||||
Save
|
||||
</Button>
|
||||
</Form>
|
||||
</form>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
.jobMutation {
|
||||
&__newButton{
|
||||
float: right;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-select-option-list-wrapper {
|
||||
width: 25rem;
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { transform } from '../../../../../services/transformer/notificationAdapterTransformer';
|
||||
import { Modal, Form, Button, Dropdown, Input, Message } from 'semantic-ui-react';
|
||||
import { xhrPost } from '../../../../../services/xhr';
|
||||
import Help from './NotificationHelpDisplay';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Switch from 'react-switch';
|
||||
import { Banner, Button, Form, Modal, Select, Switch } from '@douyinfe/semi-ui';
|
||||
|
||||
import './NotificationAdapterMutator.less';
|
||||
|
||||
@@ -138,8 +137,7 @@ export default function NotificationAdapterMutator({
|
||||
const uiElement = selectedAdapter.fields[key];
|
||||
|
||||
return (
|
||||
<Form.Field key={uiElement.description}>
|
||||
<label>{uiElement.label}:</label>
|
||||
<Form key={key}>
|
||||
{uiElement.type === 'boolean' ? (
|
||||
<Switch
|
||||
checked={uiElement.value || false}
|
||||
@@ -148,106 +146,108 @@ export default function NotificationAdapterMutator({
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
<Form.Input
|
||||
style={{ width: '100%' }}
|
||||
field={uiElement.label}
|
||||
type={uiElement.type}
|
||||
value={uiElement.value || ''}
|
||||
placeholder={uiElement.label}
|
||||
onChange={(e) => {
|
||||
setValue(selectedAdapter, uiElement, key, e.target.value);
|
||||
label={uiElement.label}
|
||||
onChange={(value) => {
|
||||
setValue(selectedAdapter, uiElement, key, value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Form.Field>
|
||||
</Form>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
onClose={() => onVisibilityChanged(false)}
|
||||
onOpen={() => onVisibilityChanged(true)}
|
||||
open={visible}
|
||||
title="Adding a new Notification Adapter"
|
||||
visible={visible}
|
||||
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>
|
||||
<Modal.Content image>
|
||||
<Modal.Description>
|
||||
{validationMessage != null && (
|
||||
<Message negative>
|
||||
<Message.Header>Houston we have a problem...</Message.Header>
|
||||
<p dangerouslySetInnerHTML={{ __html: validationMessage }} />
|
||||
</Message>
|
||||
)}
|
||||
{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"
|
||||
{validationMessage != null && (
|
||||
<Banner
|
||||
fullMode={false}
|
||||
type="danger"
|
||||
closeIcon={null}
|
||||
title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>Error</div>}
|
||||
style={{ marginBottom: '1rem' }}
|
||||
description={<p dangerouslySetInnerHTML={{ __html: validationMessage }} />}
|
||||
/>
|
||||
<Button color="black" onClick={() => onSubmit(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button content="Save" labelPosition="right" icon="checkmark" onClick={() => onSubmit(true)} positive />
|
||||
</Modal.Actions>
|
||||
)}
|
||||
{successMessage != null && (
|
||||
<Banner
|
||||
fullMode={false}
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Accordion, Icon } from 'semantic-ui-react';
|
||||
import { Banner } from '@douyinfe/semi-ui';
|
||||
|
||||
export default function Help({ readme }) {
|
||||
const [active, setActive] = React.useState(false);
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion.Title active={active} index={0} onClick={() => setActive(!active)}>
|
||||
<React.Fragment>
|
||||
<Icon name="dropdown" /> <span className="providerMutator__helpLink"> More information</span>
|
||||
</React.Fragment>
|
||||
</Accordion.Title>
|
||||
<Accordion.Content active={active} className="providerMutator__helpBox">
|
||||
<p dangerouslySetInnerHTML={{ __html: readme }} />
|
||||
</Accordion.Content>
|
||||
</Accordion>
|
||||
<Banner
|
||||
fullMode={false}
|
||||
type="info"
|
||||
closeIcon={null}
|
||||
title={<div style={{ fontWeight: 600, fontSize: '14px', lineHeight: '20px' }}>Information</div>}
|
||||
description={<p dangerouslySetInnerHTML={{ __html: readme }} />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Banner, Modal, Select, Input } from '@douyinfe/semi-ui';
|
||||
import { transform } from '../../../../../services/transformer/providerTransformer';
|
||||
import { Modal, Icon, Button, Dropdown, Input, Message } from 'semantic-ui-react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { IconLikeHeart } from '@douyinfe/semi-icons';
|
||||
import './ProviderMutator.less';
|
||||
|
||||
const sortProvider = (a, b) => {
|
||||
@@ -61,79 +61,90 @@ export default function ProviderMutator({ onVisibilityChanged, visible = false,
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal onClose={() => onVisibilityChanged(false)} onOpen={() => onVisibilityChanged(true)} open={visible}>
|
||||
<Modal.Header>Adding a new Provider</Modal.Header>
|
||||
<Modal.Content image>
|
||||
<Modal.Description>
|
||||
{validationMessage != null && (
|
||||
<Message negative>
|
||||
<Message.Header>Houston we have a problem...</Message.Header>
|
||||
<p>{validationMessage}</p>
|
||||
</Message>
|
||||
)}
|
||||
<Modal
|
||||
title="Adding a new Provider"
|
||||
visible={visible}
|
||||
onOk={() => onSubmit(true)}
|
||||
onCancel={() => onSubmit(false)}
|
||||
style={{ width: '50rem' }}
|
||||
okText="Save"
|
||||
>
|
||||
{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>
|
||||
Provider are the <Icon name="heart" color="red" /> of Fredy. We're supporting multiple Provider such as
|
||||
Immowelt, Kalaydo etc. Select a provider from the list below.
|
||||
<br />
|
||||
Fredy will then open the provider's url in a new tab.
|
||||
</p>
|
||||
<p>
|
||||
You will need to configure your search parameter like you would do when you do a regular search on the
|
||||
provider's website.
|
||||
<br />
|
||||
When the search results are shown on the website, copy the url and paste it into the textfield below.
|
||||
<br />
|
||||
<span style={{ color: '#ff0000' }}>
|
||||
<p>
|
||||
Provider are the <IconLikeHeart style={{ color: '#ff0000' }} /> of Fredy. We're supporting multiple Provider
|
||||
such as Immowelt, Kalaydo etc. Select a provider from the list below.
|
||||
<br />
|
||||
Fredy will then open the provider's url in a new tab.
|
||||
</p>
|
||||
<p>
|
||||
You will need to configure your search parameter like you would do when you do a regular search on the
|
||||
provider's website.
|
||||
<br />
|
||||
When the search results are shown on the website, copy the url and paste it into the textfield below.
|
||||
</p>
|
||||
<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.
|
||||
(See readme)
|
||||
</span>
|
||||
<br />
|
||||
<span style={{ color: '#ff0000' }}>
|
||||
</p>
|
||||
<p>
|
||||
Do not forget to sort the results by date before copying the url to Fredy, so that Fredy always captures
|
||||
the latest search results.
|
||||
</span>
|
||||
</p>
|
||||
<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);
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
window.open(selectedProvider.baseUrl);
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Provider Url"
|
||||
width={10}
|
||||
className="providerMutator__fields"
|
||||
onBlur={(e) => {
|
||||
setProviderUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Modal.Description>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button color="black" onClick={() => onSubmit(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button content="Save" labelPosition="right" icon="checkmark" onClick={() => onSubmit(true)} positive />
|
||||
</Modal.Actions>
|
||||
<Select
|
||||
filter
|
||||
placeholder="Select a provider"
|
||||
className="providerMutator__fields"
|
||||
optionList={provider
|
||||
.map((pro) => {
|
||||
return {
|
||||
otherKey: pro.id,
|
||||
value: pro.id,
|
||||
label: pro.name,
|
||||
};
|
||||
})
|
||||
.sort(sortProvider)}
|
||||
style={{ width: 180 }}
|
||||
value={selectedProvider == null ? '' : selectedProvider.id}
|
||||
onChange={(value) => {
|
||||
const selectedProvider = provider.find((pro) => pro.id === value);
|
||||
setSelectedProvider(selectedProvider);
|
||||
|
||||
window.open(selectedProvider.baseUrl);
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Provider Url"
|
||||
width={10}
|
||||
className="providerMutator__fields"
|
||||
onBlur={(e) => {
|
||||
setProviderUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Input } from 'semantic-ui-react';
|
||||
|
||||
import cityBackground from '../../assets/city_background.jpg';
|
||||
import Logo from '../../components/logo/Logo';
|
||||
import { xhrPost } from '../../services/xhr';
|
||||
import { Message } from 'semantic-ui-react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { Input, Button, Banner } from '@douyinfe/semi-ui';
|
||||
|
||||
import './login.less';
|
||||
import { IconUser, IconLock } from '@douyinfe/semi-icons';
|
||||
|
||||
export default function Login() {
|
||||
const dispatch = useDispatch();
|
||||
@@ -44,30 +44,41 @@ export default function Login() {
|
||||
<Logo />
|
||||
<form>
|
||||
<div className="login__loginWrapper">
|
||||
{error && <Message negative icon="error" content={error} />}
|
||||
{error && <Banner type="danger" closeIcon={null} description={error} />}
|
||||
<Input
|
||||
icon="user"
|
||||
iconPosition="left"
|
||||
size="large"
|
||||
prefix={<IconUser />}
|
||||
placeholder="Username"
|
||||
defaultValue={username}
|
||||
value={username}
|
||||
showClear
|
||||
style={{ marginTop: error ? '1rem' : '4rem' }}
|
||||
autoFocus
|
||||
onChange={(e) => setUserName(e.target.value)}
|
||||
autofocus
|
||||
onChange={(value) => setUserName(value)}
|
||||
onKeyPress={async (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
await tryLogin();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="password"
|
||||
icon="lock"
|
||||
iconPosition="left"
|
||||
defaultValue={password}
|
||||
size="large"
|
||||
mode="password"
|
||||
prefix={<IconLock />}
|
||||
value={password}
|
||||
placeholder="Password"
|
||||
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
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
&__loginWrapper {
|
||||
border: 1px solid #555050;
|
||||
border-radius: 30px;
|
||||
height: 25rem;
|
||||
height: 23rem;
|
||||
width: 30rem;
|
||||
z-index: 1;
|
||||
background-color: #151313ab;
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
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 }) {
|
||||
return (
|
||||
<Modal open={true}>
|
||||
<Header icon="warning sign" content="Warning" />
|
||||
<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 title="Removing user" visible={true} closable={false} onOk={onOk} onCancel={onCancel}>
|
||||
<p>Removing this user will also remove all associated jobs.</p>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
|
||||
import ToastContext from '../../components/toasts/ToastContext';
|
||||
import { Toast } from '@douyinfe/semi-ui';
|
||||
import UserTable from '../../components/table/UserTable';
|
||||
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 { xhrDelete } from '../../services/xhr';
|
||||
import { useHistory } from 'react-router';
|
||||
@@ -14,7 +15,6 @@ const Users = function Users() {
|
||||
const dispatch = useDispatch();
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const users = useSelector((state) => state.user.users);
|
||||
const ctx = React.useContext(ToastContext);
|
||||
const [userIdToBeRemoved, setUserIdToBeRemoved] = React.useState(null);
|
||||
const history = useHistory();
|
||||
|
||||
@@ -23,30 +23,19 @@ const Users = function Users() {
|
||||
await dispatch.user.getUsers();
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
init();
|
||||
}, []);
|
||||
|
||||
const onUserRemoval = async () => {
|
||||
try {
|
||||
await xhrDelete('/api/admin/users', { userId: userIdToBeRemoved });
|
||||
ctx.showToast({
|
||||
title: 'Success',
|
||||
message: 'User successfully remove',
|
||||
delay: 4000,
|
||||
backgroundColor: '#87eb8f',
|
||||
color: '#000',
|
||||
});
|
||||
Toast.success('User successfully remove');
|
||||
setUserIdToBeRemoved(null);
|
||||
await dispatch.jobs.getJobs();
|
||||
await dispatch.user.getUsers();
|
||||
} catch (error) {
|
||||
ctx.showToast({
|
||||
title: 'Error',
|
||||
message: error,
|
||||
delay: 8000,
|
||||
backgroundColor: '#db2828',
|
||||
color: '#fff',
|
||||
});
|
||||
Toast.error(error);
|
||||
setUserIdToBeRemoved(null);
|
||||
}
|
||||
};
|
||||
@@ -57,8 +46,12 @@ const Users = function Users() {
|
||||
<React.Fragment>
|
||||
{userIdToBeRemoved && <UserRemovalModal onCancel={() => setUserIdToBeRemoved(null)} onOk={onUserRemoval} />}
|
||||
|
||||
<Button primary className="users__newButton" onClick={() => history.push('/users/new')}>
|
||||
<Icon name="plus" />
|
||||
<Button
|
||||
type="primary"
|
||||
className="users__newButton"
|
||||
icon={<IconPlus />}
|
||||
onClick={() => history.push('/users/new')}
|
||||
>
|
||||
Create new User
|
||||
</Button>
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import ToastContext from '../../../components/toasts/ToastContext';
|
||||
import { xhrGet, xhrPost } from '../../../services/xhr';
|
||||
import { useHistory, useParams } from 'react-router';
|
||||
import { Button, Form } from 'semantic-ui-react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import Switch from 'react-switch';
|
||||
|
||||
import { Divider, Input, Switch, Button, Toast } from '@douyinfe/semi-ui';
|
||||
import './UserMutator.less';
|
||||
import { SegmentPart } from '../../../components/segment/SegmentPart';
|
||||
import { IconPlusCircle } from '@douyinfe/semi-icons';
|
||||
|
||||
const UserMutator = function UserMutator() {
|
||||
const params = useParams();
|
||||
@@ -18,7 +16,6 @@ const UserMutator = function UserMutator() {
|
||||
const [isAdmin, setIsAdmin] = React.useState(false);
|
||||
|
||||
const history = useHistory();
|
||||
const ctx = React.useContext(ToastContext);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -38,6 +35,7 @@ const UserMutator = function UserMutator() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
}, [params.userId]);
|
||||
|
||||
@@ -51,76 +49,62 @@ const UserMutator = function UserMutator() {
|
||||
isAdmin,
|
||||
});
|
||||
await dispatch.user.getUsers();
|
||||
ctx.showToast({
|
||||
title: 'Success',
|
||||
message: 'User successfully saved...',
|
||||
delay: 5000,
|
||||
backgroundColor: '#87eb8f',
|
||||
color: '#000',
|
||||
});
|
||||
Toast.success('User successfully saved...');
|
||||
history.push('/users');
|
||||
} catch (Exception) {
|
||||
console.error(Exception);
|
||||
ctx.showToast({
|
||||
title: 'Error',
|
||||
message: Exception.json.message,
|
||||
delay: 6000,
|
||||
backgroundColor: '#db2828',
|
||||
color: '#fff',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Toast.error(error.json.message);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form inverted className="userMutator">
|
||||
<form className="userMutator">
|
||||
<SegmentPart name="Username" helpText="The username used to login to Fredy">
|
||||
<Form.Input
|
||||
<Input
|
||||
type="text"
|
||||
label="Username"
|
||||
maxLength={30}
|
||||
placeholder="Username"
|
||||
autoFocus
|
||||
inverted
|
||||
width={6}
|
||||
defaultValue={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
value={username}
|
||||
onChange={(val) => setUsername(val)}
|
||||
/>
|
||||
</SegmentPart>
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart name="Password" helpText="The password used to login to Fredy">
|
||||
<Form.Input
|
||||
type="password"
|
||||
<Input
|
||||
mode="password"
|
||||
label="Password"
|
||||
placeholder="Password"
|
||||
inverted
|
||||
width={6}
|
||||
defaultValue={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
value={password}
|
||||
onChange={(val) => setPassword(val)}
|
||||
/>
|
||||
</SegmentPart>
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart name="Retype password" helpText="Retype the password to make sure they match">
|
||||
<Form.Input
|
||||
type="password"
|
||||
<Input
|
||||
mode="password"
|
||||
label="Retype password"
|
||||
placeholder="Retype password"
|
||||
inverted
|
||||
width={6}
|
||||
defaultValue={password2}
|
||||
onChange={(e) => setPassword2(e.target.value)}
|
||||
value={password2}
|
||||
onChange={(val) => setPassword2(val)}
|
||||
/>
|
||||
</SegmentPart>
|
||||
<SegmentPart name="Admin use" helpText="Check this if the user is an administrator">
|
||||
<Form.Field>
|
||||
<label>Is user an admin?</label>
|
||||
<Switch checked={isAdmin} onChange={(checked) => setIsAdmin(checked)} />
|
||||
</Form.Field>
|
||||
<Divider margin="1rem" />
|
||||
<SegmentPart name="Is user an admin?" helpText="Check this if the user is an administrator">
|
||||
<Switch checked={isAdmin} onChange={(checked) => setIsAdmin(checked)} />
|
||||
</SegmentPart>
|
||||
<Button color="red" onClick={() => history.push('/users')}>
|
||||
<Divider margin="1rem" />
|
||||
<Button type="danger" style={{ marginRight: '1rem' }} onClick={() => history.push('/users')}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button color="green" onClick={saveUser}>
|
||||
<Button type="primary" icon={<IconPlusCircle />} onClick={saveUser}>
|
||||
Save
|
||||
</Button>
|
||||
</Form>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
675
yarn.lock
675
yarn.lock
@@ -50,21 +50,21 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.14.tgz#4106fc8b755f3e3ee0a0a7c27dde5de1d2b2baf8"
|
||||
integrity sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==
|
||||
|
||||
"@babel/core@7.21.0":
|
||||
version "7.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13"
|
||||
integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==
|
||||
"@babel/core@7.21.3":
|
||||
version "7.21.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.3.tgz#cf1c877284a469da5d1ce1d1e53665253fae712e"
|
||||
integrity sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.2.0"
|
||||
"@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-module-transforms" "^7.21.0"
|
||||
"@babel/helper-module-transforms" "^7.21.2"
|
||||
"@babel/helpers" "^7.21.0"
|
||||
"@babel/parser" "^7.21.0"
|
||||
"@babel/parser" "^7.21.3"
|
||||
"@babel/template" "^7.20.7"
|
||||
"@babel/traverse" "^7.21.0"
|
||||
"@babel/types" "^7.21.0"
|
||||
"@babel/traverse" "^7.21.3"
|
||||
"@babel/types" "^7.21.3"
|
||||
convert-source-map "^1.7.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
@@ -92,10 +92,10 @@
|
||||
json5 "^2.2.2"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/eslint-parser@7.19.1":
|
||||
version "7.19.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz#4f68f6b0825489e00a24b41b6a1ae35414ecd2f4"
|
||||
integrity sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==
|
||||
"@babel/eslint-parser@7.21.3":
|
||||
version "7.21.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz#d79e822050f2de65d7f368a076846e7184234af7"
|
||||
integrity sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg==
|
||||
dependencies:
|
||||
"@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1"
|
||||
eslint-visitor-keys "^2.1.0"
|
||||
@@ -119,7 +119,7 @@
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/generator@^7.21.0", "@babel/generator@^7.21.1":
|
||||
"@babel/generator@^7.21.1":
|
||||
version "7.21.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd"
|
||||
integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==
|
||||
@@ -129,6 +129,16 @@
|
||||
"@jridgewell/trace-mapping" "^0.3.17"
|
||||
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":
|
||||
version "7.18.6"
|
||||
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/types" "^7.20.7"
|
||||
|
||||
"@babel/helper-module-transforms@^7.21.0":
|
||||
"@babel/helper-module-transforms@^7.21.2":
|
||||
version "7.21.2"
|
||||
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==
|
||||
@@ -414,11 +424,16 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.15.tgz#eec9f36d8eaf0948bb88c87a46784b5ee9fd0c89"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3"
|
||||
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":
|
||||
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"
|
||||
@@ -1077,6 +1092,21 @@
|
||||
"@babel/plugin-transform-react-jsx-development" "^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":
|
||||
version "7.20.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.6.tgz#facf4879bfed9b5326326273a64220f099b0fce3"
|
||||
@@ -1084,13 +1114,6 @@
|
||||
dependencies:
|
||||
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":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
|
||||
@@ -1098,6 +1121,13 @@
|
||||
dependencies:
|
||||
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":
|
||||
version "7.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6"
|
||||
@@ -1171,6 +1201,22 @@
|
||||
debug "^4.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":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
|
||||
@@ -1198,115 +1244,211 @@
|
||||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@esbuild/android-arm64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23"
|
||||
integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==
|
||||
"@babel/types@^7.21.3":
|
||||
version "7.21.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05"
|
||||
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":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2"
|
||||
integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==
|
||||
"@douyinfe/semi-animation-react@2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.31.0.tgz#e7e53219a40fa0f3e192cd6b254e41fdb6f7e079"
|
||||
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":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e"
|
||||
integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==
|
||||
"@douyinfe/semi-animation-styled@2.23.2":
|
||||
version "2.23.2"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.23.2.tgz#f18bc074515441c297cc636ed98521e249d093c9"
|
||||
integrity sha512-cKaA1yGHPF76Rx7EZDZicj+1oX1su2wnqb/UGFOTquAwqWmkTfgQ+EKxCd/N704WH+RtmGf4xbrJKpBvvcEdSQ==
|
||||
|
||||
"@esbuild/darwin-arm64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220"
|
||||
integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==
|
||||
"@douyinfe/semi-animation@2.12.0":
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.12.0.tgz#51fe52d3911c2591a80a6e9fe96e6809c1511f13"
|
||||
integrity sha512-OAfL9Nk38ZPqfdKm9k4cvVXXzm16ALI4LxGNZ0qfe2RCLLnYGB/hNzTctoTDjYD35dFv0yroh3qsXtZuP2xNdg==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.15.4"
|
||||
bezier-easing "^2.1.0"
|
||||
|
||||
"@esbuild/darwin-x64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4"
|
||||
integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==
|
||||
"@douyinfe/semi-animation@2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.31.0.tgz#bcf89009845dbf945b83df2ca4a91d9c6b5631c6"
|
||||
integrity sha512-UxEdBT90A2oAIauTHx2wXTIfOhF6Evlfo7tZ0QaeJtzRlK1km/qfZRRIVYXx1F8CVdgJSAiE2x2p9d78EHrcag==
|
||||
dependencies:
|
||||
bezier-easing "^2.1.0"
|
||||
|
||||
"@esbuild/freebsd-arm64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27"
|
||||
integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==
|
||||
"@douyinfe/semi-foundation@2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-foundation/-/semi-foundation-2.31.0.tgz#cfe41c8bc58b7d9b1c73a9bc5a1bc82a0901991f"
|
||||
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":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72"
|
||||
integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==
|
||||
"@douyinfe/semi-icons@2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-icons/-/semi-icons-2.31.0.tgz#32b5ec27f29cb74f5a2125f058d86c5e2d82cecb"
|
||||
integrity sha512-txON0yQpJAA4I1FILttQ5uFOZfCah1yp4RIE+nlv7f50QKIMptQDcSagwdHQiUvz2zuuBS0WOotN9ZZnDn9DAw==
|
||||
dependencies:
|
||||
classnames "^2.2.6"
|
||||
|
||||
"@esbuild/linux-arm64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca"
|
||||
integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==
|
||||
"@douyinfe/semi-illustrations@2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-illustrations/-/semi-illustrations-2.31.0.tgz#59c952ff84c00da3a277009f3a9d0990b470451b"
|
||||
integrity sha512-Jl7V6Guri9dFTil7lvzBV3w0JEIOqiRPuH4Sb92f8dVMjfGY+/llkKsqsdTv3Jns5nAKos/z8ILkA/5EJX4SIw==
|
||||
|
||||
"@esbuild/linux-arm@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196"
|
||||
integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==
|
||||
"@douyinfe/semi-theme-default@2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-theme-default/-/semi-theme-default-2.31.0.tgz#5644e7dda1001bdfaa5704d5bcef0ff5b4ab0f7b"
|
||||
integrity sha512-zuU/vurGQeNSFIFEG031LlOfJIkdnC+LqO+4j8TrkGWGHk9rQqzkjADzecAp5I51s0c/KxDMie1SPkcMNU2zJA==
|
||||
dependencies:
|
||||
glob "^7.1.6"
|
||||
|
||||
"@esbuild/linux-ia32@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54"
|
||||
integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==
|
||||
"@douyinfe/semi-ui@2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@douyinfe/semi-ui/-/semi-ui-2.31.0.tgz#7731c980ab505eb08b59d38accf1842878e637ef"
|
||||
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":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8"
|
||||
integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==
|
||||
"@esbuild/android-arm64@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz#15a8e2b407d03989b899e325151dc2e96d19c620"
|
||||
integrity sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==
|
||||
|
||||
"@esbuild/linux-mips64el@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726"
|
||||
integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==
|
||||
"@esbuild/android-arm@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.12.tgz#677a09297e1f4f37aba7b4fc4f31088b00484985"
|
||||
integrity sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==
|
||||
|
||||
"@esbuild/linux-ppc64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8"
|
||||
integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==
|
||||
"@esbuild/android-x64@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.12.tgz#b292729eef4e0060ae1941f6a021c4d2542a3521"
|
||||
integrity sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==
|
||||
|
||||
"@esbuild/linux-riscv64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9"
|
||||
integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==
|
||||
"@esbuild/darwin-arm64@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz#efa35318df931da05825894e1787b976d55adbe3"
|
||||
integrity sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==
|
||||
|
||||
"@esbuild/linux-s390x@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87"
|
||||
integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==
|
||||
"@esbuild/darwin-x64@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz#e7b54bb3f6dc81aadfd0485cd1623c648157e64d"
|
||||
integrity sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==
|
||||
|
||||
"@esbuild/linux-x64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f"
|
||||
integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==
|
||||
"@esbuild/freebsd-arm64@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz#99a18a8579d6299c449566fe91d9b6a54cf2a591"
|
||||
integrity sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==
|
||||
|
||||
"@esbuild/netbsd-x64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775"
|
||||
integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==
|
||||
"@esbuild/freebsd-x64@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz#0e090190fede307fb4022f671791a50dd5121abd"
|
||||
integrity sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==
|
||||
|
||||
"@esbuild/openbsd-x64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35"
|
||||
integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==
|
||||
"@esbuild/linux-arm64@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz#7fe2a69f8a1a7153fa2b0f44aabcadb59475c7e0"
|
||||
integrity sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==
|
||||
|
||||
"@esbuild/sunos-x64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c"
|
||||
integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==
|
||||
"@esbuild/linux-arm@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz#b87c76ebf1fe03e01fd6bb5cfc2f3c5becd5ee93"
|
||||
integrity sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==
|
||||
|
||||
"@esbuild/win32-arm64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a"
|
||||
integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==
|
||||
"@esbuild/linux-ia32@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz#9e9357090254524d32e6708883a47328f3037858"
|
||||
integrity sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==
|
||||
|
||||
"@esbuild/win32-ia32@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09"
|
||||
integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==
|
||||
"@esbuild/linux-loong64@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz#9deb605f9e2c82f59412ddfefb4b6b96d54b5b5b"
|
||||
integrity sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==
|
||||
|
||||
"@esbuild/win32-x64@0.16.17":
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091"
|
||||
integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==
|
||||
"@esbuild/linux-mips64el@0.17.12":
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz#6ef170b974ddf5e6acdfa5b05f22b6e9dfd2b003"
|
||||
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":
|
||||
version "4.2.0"
|
||||
@@ -1340,21 +1482,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe"
|
||||
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":
|
||||
version "0.11.8"
|
||||
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"
|
||||
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":
|
||||
version "2.2.0"
|
||||
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"
|
||||
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":
|
||||
version "7.7.0"
|
||||
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"
|
||||
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:
|
||||
version "0.4.0"
|
||||
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"
|
||||
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:
|
||||
version "9.0.1"
|
||||
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"
|
||||
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:
|
||||
version "2.2.0"
|
||||
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"
|
||||
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:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
@@ -2175,6 +2309,11 @@ copy-anything@^2.0.1:
|
||||
dependencies:
|
||||
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:
|
||||
version "3.26.1"
|
||||
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:
|
||||
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:
|
||||
version "1.0.2"
|
||||
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"
|
||||
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:
|
||||
version "2.6.9"
|
||||
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-symbol "^1.0.2"
|
||||
|
||||
esbuild@^0.16.14:
|
||||
version "0.16.17"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259"
|
||||
integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==
|
||||
esbuild@^0.17.5:
|
||||
version "0.17.12"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.12.tgz#2ad7523bf1bc01881e9d904bc04e693bd3bdcf2f"
|
||||
integrity sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==
|
||||
optionalDependencies:
|
||||
"@esbuild/android-arm" "0.16.17"
|
||||
"@esbuild/android-arm64" "0.16.17"
|
||||
"@esbuild/android-x64" "0.16.17"
|
||||
"@esbuild/darwin-arm64" "0.16.17"
|
||||
"@esbuild/darwin-x64" "0.16.17"
|
||||
"@esbuild/freebsd-arm64" "0.16.17"
|
||||
"@esbuild/freebsd-x64" "0.16.17"
|
||||
"@esbuild/linux-arm" "0.16.17"
|
||||
"@esbuild/linux-arm64" "0.16.17"
|
||||
"@esbuild/linux-ia32" "0.16.17"
|
||||
"@esbuild/linux-loong64" "0.16.17"
|
||||
"@esbuild/linux-mips64el" "0.16.17"
|
||||
"@esbuild/linux-ppc64" "0.16.17"
|
||||
"@esbuild/linux-riscv64" "0.16.17"
|
||||
"@esbuild/linux-s390x" "0.16.17"
|
||||
"@esbuild/linux-x64" "0.16.17"
|
||||
"@esbuild/netbsd-x64" "0.16.17"
|
||||
"@esbuild/openbsd-x64" "0.16.17"
|
||||
"@esbuild/sunos-x64" "0.16.17"
|
||||
"@esbuild/win32-arm64" "0.16.17"
|
||||
"@esbuild/win32-ia32" "0.16.17"
|
||||
"@esbuild/win32-x64" "0.16.17"
|
||||
"@esbuild/android-arm" "0.17.12"
|
||||
"@esbuild/android-arm64" "0.17.12"
|
||||
"@esbuild/android-x64" "0.17.12"
|
||||
"@esbuild/darwin-arm64" "0.17.12"
|
||||
"@esbuild/darwin-x64" "0.17.12"
|
||||
"@esbuild/freebsd-arm64" "0.17.12"
|
||||
"@esbuild/freebsd-x64" "0.17.12"
|
||||
"@esbuild/linux-arm" "0.17.12"
|
||||
"@esbuild/linux-arm64" "0.17.12"
|
||||
"@esbuild/linux-ia32" "0.17.12"
|
||||
"@esbuild/linux-loong64" "0.17.12"
|
||||
"@esbuild/linux-mips64el" "0.17.12"
|
||||
"@esbuild/linux-ppc64" "0.17.12"
|
||||
"@esbuild/linux-riscv64" "0.17.12"
|
||||
"@esbuild/linux-s390x" "0.17.12"
|
||||
"@esbuild/linux-x64" "0.17.12"
|
||||
"@esbuild/netbsd-x64" "0.17.12"
|
||||
"@esbuild/openbsd-x64" "0.17.12"
|
||||
"@esbuild/sunos-x64" "0.17.12"
|
||||
"@esbuild/win32-arm64" "0.17.12"
|
||||
"@esbuild/win32-ia32" "0.17.12"
|
||||
"@esbuild/win32-x64" "0.17.12"
|
||||
|
||||
escalade@^3.1.1:
|
||||
version "3.1.1"
|
||||
@@ -2847,11 +3001,6 @@ execa@^7.0.0:
|
||||
signal-exit "^3.0.7"
|
||||
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:
|
||||
version "2.0.3"
|
||||
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"
|
||||
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:
|
||||
version "11.12.0"
|
||||
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"
|
||||
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:
|
||||
version "0.2.1"
|
||||
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"
|
||||
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:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226"
|
||||
@@ -3814,11 +3977,6 @@ locate-path@^6.0.0:
|
||||
dependencies:
|
||||
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:
|
||||
version "4.2.0"
|
||||
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"
|
||||
integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=
|
||||
|
||||
lodash@^4.17.21:
|
||||
lodash@4.17.21, lodash@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
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"
|
||||
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:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||
@@ -4046,7 +4209,7 @@ minimatch@^3.0.4:
|
||||
dependencies:
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
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"
|
||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||
|
||||
prettier@2.8.4:
|
||||
version "2.8.4"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
|
||||
integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
|
||||
prettier@2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.5.tgz#3dd8ae1ebddc4f6aa419c9b64d8c8319a7e0d982"
|
||||
integrity sha512-3gzuxrHbKUePRBB4ZeU08VNkUcqEHaUaouNt0m7LGP4Hti/NuB07C7PPTM/LkWqXoJYJn2McEo5+kxPNrtQkLQ==
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
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"
|
||||
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:
|
||||
version "15.7.2"
|
||||
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"
|
||||
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:
|
||||
version "1.0.1"
|
||||
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"
|
||||
scheduler "^0.23.0"
|
||||
|
||||
react-fast-compare@^3.0.1:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
|
||||
react-draggable@^4.0.3:
|
||||
version "4.4.5"
|
||||
resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.5.tgz#9e37fe7ce1a4cf843030f521a0a4cc41886d7e7c"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
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:
|
||||
version "18.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67"
|
||||
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:
|
||||
version "8.0.5"
|
||||
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"
|
||||
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:
|
||||
version "5.3.0"
|
||||
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-warning "^1.0.0"
|
||||
|
||||
react-switch@7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-switch/-/react-switch-7.0.0.tgz#400990bb9822864938e343ed24f13276a617bdc0"
|
||||
integrity sha512-KkDeW+cozZXI6knDPyUt3KBN1rmhoVYgAdCJqAh7st7tk8YE6N0iR89zjCWO8T8dUTeJGTR0KU+5CHCRMRffiA==
|
||||
react-sortable-hoc@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-2.0.0.tgz#f6780d8aa4b922a21f3e754af542f032677078b7"
|
||||
integrity sha512-JZUw7hBsAHXK7PTyErJyI7SopSBFRcFHDjWW5SWjcugY0i6iH7f+eJkY8cJmGMlZ1C9xz1J3Vjz0plFpavVeRg==
|
||||
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:
|
||||
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"
|
||||
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:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||
@@ -4948,10 +5124,10 @@ rimraf@^3.0.2:
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rollup@^3.10.0:
|
||||
version "3.15.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.15.0.tgz#6f4105e8c4b8145229657b74ad660b02fbfacc05"
|
||||
integrity sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg==
|
||||
rollup@^3.18.0:
|
||||
version "3.19.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.19.1.tgz#2b3a31ac1ff9f3afab2e523fa687fef5b0ee20fc"
|
||||
integrity sha512-lAbrdN7neYCg/8WaoWn/ckzCtz+jr70GFfYdlf50OF7387HTg+wiuiqJRFYawwSPpqfqDNYqK7smY/ks2iAudg==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
@@ -5008,30 +5184,18 @@ scheduler@^0.23.0:
|
||||
dependencies:
|
||||
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:
|
||||
version "0.9.6"
|
||||
resolved "https://registry.yarnpkg.com/selectn/-/selectn-0.9.6.tgz#bd873a556d18f96d8515fc91503ec6ff398ff9a2"
|
||||
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:
|
||||
version "1.0.0"
|
||||
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"
|
||||
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:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||
@@ -5626,6 +5785,11 @@ util@0.10.3:
|
||||
dependencies:
|
||||
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:
|
||||
version "1.0.1"
|
||||
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"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||
|
||||
vite@4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-4.1.4.tgz#170d93bcff97e0ebc09764c053eebe130bfe6ca0"
|
||||
integrity sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==
|
||||
vite@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-4.2.0.tgz#d4e6eafbc034f3faf0ab376bd5b76ac15775eb99"
|
||||
integrity sha512-AbDTyzzwuKoRtMIRLGNxhLRuv1FpRgdIw+1y6AQG73Q5+vtecmvzKo/yk8X/vrHDpETRTx01ABijqUHIzBXi0g==
|
||||
dependencies:
|
||||
esbuild "^0.16.14"
|
||||
esbuild "^0.17.5"
|
||||
postcss "^8.4.21"
|
||||
resolve "^1.22.1"
|
||||
rollup "^3.10.0"
|
||||
rollup "^3.18.0"
|
||||
optionalDependencies:
|
||||
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:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
|
||||
|
||||
Reference in New Issue
Block a user