Initial Skynet premium portal suppport
This commit is contained in:
232
src/containers/AddEditHost/AddEditHost.js
Normal file
232
src/containers/AddEditHost/AddEditHost.js
Normal file
@@ -0,0 +1,232 @@
|
||||
import React from 'react';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
import DropDown from '../../components/UI/DropDown/DropDown';
|
||||
import PropTypes from 'prop-types';
|
||||
import Text from '../../components/UI/Text/Text';
|
||||
import { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createDismissDisplay } from '../../utils.jsx';
|
||||
import {
|
||||
addEditHost,
|
||||
completeAddEditHost,
|
||||
} from '../../redux/actions/host_actions';
|
||||
|
||||
class AddEditHost extends Component {
|
||||
state = {
|
||||
AgentString: '',
|
||||
ApiPassword: '',
|
||||
ApiPort: 443,
|
||||
AuthPassword: '',
|
||||
AuthURL: '',
|
||||
AuthUser: '',
|
||||
HostNameOrIp: '',
|
||||
Path: '',
|
||||
Protocol: 'https',
|
||||
TimeoutMs: 60000,
|
||||
};
|
||||
|
||||
originalState = {};
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.HostData) {
|
||||
const state = { ...this.state, ...this.props.HostData };
|
||||
this.originalState = { ...state };
|
||||
this.setState(state);
|
||||
}
|
||||
}
|
||||
|
||||
handleSave = () => {
|
||||
this.props.completeAddEditHost(this.state);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Box dxStyle={{ width: '430px', height: 'auto', padding: '5px' }}>
|
||||
{createDismissDisplay(this.props.Close)}
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
paddingBottom: '5px',
|
||||
boxSizing: 'border-box',
|
||||
}}>
|
||||
<h1
|
||||
style={{
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
color: 'var(--text_color_error)',
|
||||
}}>
|
||||
Portal Settings
|
||||
</h1>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Text text={'Host / IP'} textAlign={'left'} type={'Heading2'} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<input
|
||||
onChange={(e) =>
|
||||
this.setState({ HostNameOrIp: e.target.value.trim() })
|
||||
}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ width: '100%' }}
|
||||
type={'text'}
|
||||
value={this.state.HostNameOrIp}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ height: 'var(--default_spacing)' }} />
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Text text={'Protocol'} textAlign={'left'} type={'Heading2'} />
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<Text text={'Port'} textAlign={'left'} type={'Heading2'} />
|
||||
<div style={{ paddingLeft: 'var(--default_spacing)' }} />
|
||||
<Text text={'Timeout (ms)'} textAlign={'left'} type={'Heading2'} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<DropDown
|
||||
changed={(e) => this.setState({ Protocol: e.target.value })}
|
||||
items={['https', 'http']}
|
||||
selected={this.state.Protocol}
|
||||
/>
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
<input
|
||||
onChange={(e) => this.setState({ ApiPort: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ width: '100%' }}
|
||||
type={'number'}
|
||||
min={1}
|
||||
max={65535}
|
||||
value={this.state.ApiPort}
|
||||
/>
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
<input
|
||||
onChange={(e) => this.setState({ TimeoutMs: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ width: '100%' }}
|
||||
type={'number'}
|
||||
min={1000}
|
||||
step={1000}
|
||||
value={this.state.TimeoutMs}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ height: 'var(--default_spacing)' }} />
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Text
|
||||
text={'Agent String (optional)'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
<Text
|
||||
text={'API Key (optional)'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<input
|
||||
onChange={(e) => this.setState({ AgentString: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ flex: '1' }}
|
||||
type={'text'}
|
||||
value={this.state.AgentString}
|
||||
/>
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
<input
|
||||
onChange={(e) => this.setState({ ApiPassword: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ flex: '1' }}
|
||||
type={'text'}
|
||||
value={this.state.ApiPassword}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ height: 'var(--default_spacing)' }} />
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Text
|
||||
text={'Authentication URL (premium)'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<input
|
||||
onChange={(e) => this.setState({ AuthURL: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
type={'text'}
|
||||
value={this.state.AuthURL}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ height: 'var(--default_spacing)' }} />
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Text
|
||||
text={'User Name (premium)'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
<Text
|
||||
text={'Password (premium)'}
|
||||
textAlign={'left'}
|
||||
type={'Heading2'}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<input
|
||||
onChange={(e) => this.setState({ AuthUser: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ flex: '1' }}
|
||||
type={'text'}
|
||||
value={this.state.AuthUser}
|
||||
/>
|
||||
<div style={{ width: 'var(--default_spacing)' }} />
|
||||
<input
|
||||
onChange={(e) => this.setState({ AuthPassword: e.target.value })}
|
||||
className={'ConfigurationItemInput'}
|
||||
style={{ flex: '1' }}
|
||||
type={'text'}
|
||||
value={this.state.AuthPassword}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ height: 'var(--default_spacing)' }} />
|
||||
<p>
|
||||
<b>
|
||||
{'Portal URL: ' +
|
||||
this.state.Protocol +
|
||||
'://' +
|
||||
this.state.HostNameOrIp +
|
||||
((this.state.Protocol === 'http' && this.state.ApiPort != 80) ||
|
||||
(this.state.Protocol === 'https' && this.state.ApiPort != 443)
|
||||
? ':' + this.state.ApiPort.toString()
|
||||
: '')}
|
||||
</b>
|
||||
</p>
|
||||
<div style={{ height: 'var(--default_spacing)' }} />
|
||||
</div>
|
||||
<Button clicked={this.handleSave}>Save</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
HostData: state.host.HostData,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
Close: () => dispatch(addEditHost(false)),
|
||||
completeAddEditHost: (host_data) =>
|
||||
dispatch(completeAddEditHost(true, host_data)),
|
||||
};
|
||||
};
|
||||
|
||||
AddEditHost.propTypes = {
|
||||
Close: PropTypes.func.isRequired,
|
||||
completeAddEditHost: PropTypes.func.isRequired,
|
||||
HostData: PropTypes.object,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AddEditHost);
|
||||
@@ -36,7 +36,7 @@ const default_state = {
|
||||
DisplayS3: false,
|
||||
HostNameOrIp: '',
|
||||
Name: '',
|
||||
Port: 20000,
|
||||
Port: 2000,
|
||||
Provider: Constants.S3_PROVIDER_LIST[0],
|
||||
Region: Constants.S3_REGION_PROVIDER_REGION[0],
|
||||
SecretKey: '',
|
||||
@@ -47,7 +47,7 @@ export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
class extends Component {
|
||||
class AddMount extends Component {
|
||||
state = {
|
||||
...default_state,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import './Configuration.css';
|
||||
import { connect } from 'react-redux';
|
||||
import { createDismissDisplay } from '../../utils.jsx';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
import ConfigurationItem from './ConfigurationItem/ConfigurationItem';
|
||||
@@ -35,6 +36,27 @@ class Configuration extends IPCContainer {
|
||||
}
|
||||
return itemA.value.filter((i) => !itemB.value.includes(i)).length !== 0;
|
||||
}
|
||||
if (itemA.type === 'host_list') {
|
||||
if (itemA.value.length !== itemB.value.length) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
itemA.value.filter((i) =>
|
||||
itemB.value.find(
|
||||
(j) =>
|
||||
j.HostNameOrIp === i.HostNameOrIp &&
|
||||
j.ApiPort === i.ApiPort &&
|
||||
j.Protocol === i.Protocol &&
|
||||
j.TimeoutMs === i.TimeoutMs &&
|
||||
j.AgentString === i.AgentString &&
|
||||
j.ApiPassword === i.ApiPassword &&
|
||||
j.AuthURL === i.AuthURL &&
|
||||
j.AuthUser === i.AuthUser &&
|
||||
j.AuthPassword === i.AuthPassword
|
||||
)
|
||||
).length === 0
|
||||
);
|
||||
}
|
||||
return itemA.value !== itemB.value;
|
||||
};
|
||||
|
||||
@@ -115,9 +137,11 @@ class Configuration extends IPCContainer {
|
||||
remote: template[key] ? template[key].remote : false,
|
||||
type: template[key] ? template[key].type : null,
|
||||
value:
|
||||
template[key] && template[key].type === 'object'
|
||||
template[key] &&
|
||||
(template[key].type === 'string_array' ||
|
||||
template[key].type === 'object')
|
||||
? config[key]
|
||||
: template[key] && template[key].type === 'string_array'
|
||||
: template[key] && template[key].type === 'host_list'
|
||||
? config[key]
|
||||
: config[key].toString(),
|
||||
};
|
||||
@@ -141,6 +165,8 @@ class Configuration extends IPCContainer {
|
||||
itemList[idx].value =
|
||||
target.type === 'textarea'
|
||||
? target.string_array
|
||||
: target.type === 'host_list'
|
||||
? target.value
|
||||
: target.value.toString();
|
||||
this.setState({
|
||||
ItemList: itemList,
|
||||
@@ -156,6 +182,8 @@ class Configuration extends IPCContainer {
|
||||
itemList[idx].value =
|
||||
target.type === 'textarea'
|
||||
? target.string_array
|
||||
: target.type === 'host_list'
|
||||
? target.value
|
||||
: target.value.toString();
|
||||
objectLookup[name] = itemList;
|
||||
this.setState({
|
||||
@@ -246,7 +274,11 @@ class Configuration extends IPCContainer {
|
||||
changedItems.push({
|
||||
Name: item.label,
|
||||
Value:
|
||||
item.type === 'string_array' ? item.value.join(';') : item.value,
|
||||
item.type === 'string_array'
|
||||
? item.value.join(';')
|
||||
: item.type === 'host_list'
|
||||
? JSON.stringify(item.value)
|
||||
: item.value,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -258,6 +290,8 @@ class Configuration extends IPCContainer {
|
||||
Value:
|
||||
item.type === 'string_array'
|
||||
? item.value.join(';')
|
||||
: item.type === 'host_list'
|
||||
? JSON.stringify(item.value)
|
||||
: item.value,
|
||||
});
|
||||
}
|
||||
@@ -402,23 +436,8 @@ class Configuration extends IPCContainer {
|
||||
return (
|
||||
<div className={'Configuration'}>
|
||||
{confirmSave}
|
||||
<Box dxDark dxStyle={{ padding: 'var(--default_spacing)' }}>
|
||||
<div
|
||||
style={{
|
||||
float: 'right',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
marginTop: '-4px',
|
||||
boxSizing: 'border-box',
|
||||
display: 'block',
|
||||
}}>
|
||||
<a
|
||||
href={'#'}
|
||||
onClick={this.checkSaveRequired}
|
||||
style={{ cursor: 'pointer' }}>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
<Box dxDark dxStyle={{ padding: '5px' }}>
|
||||
{createDismissDisplay(this.checkSaveRequired)}
|
||||
<h1 style={{ width: '100%', textAlign: 'center' }}>
|
||||
{(this.props.DisplayRemoteConfiguration
|
||||
? this.props.DisplayConfiguration.substr(6)
|
||||
|
||||
@@ -7,6 +7,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { notifyError, notifyInfo } from '../../../redux/actions/error_actions';
|
||||
import settings from '../../../assets/settings';
|
||||
import DropDown from '../../../components/UI/DropDown/DropDown';
|
||||
import HostList from '../../HostList/HostList';
|
||||
import Password from '../../../containers/UI/Password/Password';
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
@@ -80,6 +81,25 @@ export default connect(
|
||||
);
|
||||
break;
|
||||
|
||||
case 'host_list':
|
||||
data = (
|
||||
<HostList
|
||||
autoFocus={props.autoFocus}
|
||||
disabled={props.readOnly}
|
||||
onChange={(items) =>
|
||||
handleChanged({
|
||||
target: {
|
||||
type: 'host_list',
|
||||
value: items,
|
||||
},
|
||||
})
|
||||
}
|
||||
type={props.template.subtype}
|
||||
value={props.value}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'list':
|
||||
data = (
|
||||
<DropDown
|
||||
|
||||
0
src/containers/HostList/Host/Host.css
Normal file
0
src/containers/HostList/Host/Host.css
Normal file
69
src/containers/HostList/Host/Host.js
Normal file
69
src/containers/HostList/Host/Host.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { addEditHost } from '../../../redux/actions/host_actions';
|
||||
import { connect } from 'react-redux';
|
||||
import { faTrashAlt, faEdit } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
// const mapStateToProps = (state) => {
|
||||
// return {};
|
||||
// };
|
||||
//
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
addEditHost: (host_data, cb) => dispatch(addEditHost(true, host_data, cb)),
|
||||
};
|
||||
};
|
||||
|
||||
const Host = ({ allowDelete, addEditHost, value, onChange, onDelete }) => {
|
||||
const handleEditHost = () => {
|
||||
addEditHost(value, (changed, host_data) => {
|
||||
if (changed) {
|
||||
onChange(host_data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<div
|
||||
style={{
|
||||
flex: 0,
|
||||
paddingRight: 'calc(var(--default_spacing) * 1.25)',
|
||||
}}>
|
||||
<a href={'#'} onClick={handleEditHost}>
|
||||
<FontAwesomeIcon icon={faEdit} />
|
||||
</a>
|
||||
</div>
|
||||
{allowDelete ? (
|
||||
<div
|
||||
style={{
|
||||
flex: 0,
|
||||
paddingRight: 'calc(var(--default_spacing) * 1.25)',
|
||||
}}>
|
||||
<a href={'#'} onClick={onDelete}>
|
||||
<FontAwesomeIcon icon={faTrashAlt} />
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
<p>
|
||||
{value.HostNameOrIp +
|
||||
((value.Protocol === 'http' && value.ApiPort === 80) ||
|
||||
(value.Protocol === 'https' && value.ApiPort === 443)
|
||||
? ''
|
||||
: ':' + value.ApiPort)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Host.propTypes = {
|
||||
allowDelete: PropTypes.bool.isRequired,
|
||||
addEditHost: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onDelete: PropTypes.func.isRequired,
|
||||
value: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(Host);
|
||||
// export default Host;
|
||||
0
src/containers/HostList/HostList.css
Normal file
0
src/containers/HostList/HostList.css
Normal file
122
src/containers/HostList/HostList.js
Normal file
122
src/containers/HostList/HostList.js
Normal file
@@ -0,0 +1,122 @@
|
||||
import React from 'react';
|
||||
import './HostList.css';
|
||||
import Host from './Host/Host';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Component } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { confirmYesNo } from '../../redux/actions/common_actions';
|
||||
import { connect } from 'react-redux';
|
||||
import { addEditHost } from '../../redux/actions/host_actions';
|
||||
import { faPlusCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
class HostList extends Component {
|
||||
state = {
|
||||
items: [],
|
||||
};
|
||||
// autoFocus={props.autoFocus}
|
||||
// disabled={props.readOnly}
|
||||
// type={props.template.subtype}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({ items: this.props.value });
|
||||
}
|
||||
|
||||
componentWillUnmount() {}
|
||||
|
||||
checkDuplicates = () => {
|
||||
return false;
|
||||
};
|
||||
|
||||
handleAddHost = () => {
|
||||
this.props.addEditHost((changed, host_data) => {
|
||||
if (changed) {
|
||||
const items = [...this.state.items, host_data];
|
||||
this.updateItems(items);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
handleChanged = (host_data, index) => {
|
||||
const items = [...this.state.items];
|
||||
items[index] = host_data;
|
||||
this.updateItems(items);
|
||||
};
|
||||
|
||||
handleDeleted = (index) => {
|
||||
this.props.ConfirmRemoveHost(
|
||||
'Delete [' + this.state.items[index].HostNameOrIp + ']?',
|
||||
(confirmed) => {
|
||||
if (confirmed) {
|
||||
const items = [...this.state.items];
|
||||
items.splice(index, 1);
|
||||
this.updateItems(items);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
updateItems = (items) => {
|
||||
this.setState(
|
||||
{
|
||||
items,
|
||||
},
|
||||
() => {
|
||||
this.props.onChange(this.state.items);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
let idx = 0;
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<div
|
||||
style={{
|
||||
maxHeight: '80px',
|
||||
maxWidth: '260px',
|
||||
minWidth: '260px',
|
||||
backgroundColor: 'var(--control_background)',
|
||||
padding: 'var(--default_spacing)',
|
||||
overflowY: 'scroll',
|
||||
}}>
|
||||
{this.state.items.map((v, index) => {
|
||||
return (
|
||||
<Host
|
||||
key={idx++}
|
||||
onChange={(host_data) => this.handleChanged(host_data, index)}
|
||||
onDelete={() => this.handleDeleted(index)}
|
||||
allowDelete={this.state.items.length > 1}
|
||||
value={v}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<a
|
||||
href={'#'}
|
||||
onClick={this.handleAddHost}
|
||||
style={{
|
||||
marginTop: 'var(--default_spacing)',
|
||||
}}>
|
||||
<FontAwesomeIcon icon={faPlusCircle} />
|
||||
<b>{' Add Portal '}</b>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
addEditHost: (cb) => dispatch(addEditHost(true, null, cb)),
|
||||
ConfirmRemoveHost: (title, cb) => dispatch(confirmYesNo(title, cb)),
|
||||
};
|
||||
};
|
||||
|
||||
HostList.propTypes = {
|
||||
addEditHost: PropTypes.func.isRequired,
|
||||
ConfirmRemoveHost: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(HostList);
|
||||
@@ -1,15 +1,15 @@
|
||||
import React from 'react';
|
||||
import './PinnedManager.css';
|
||||
import { connect } from 'react-redux';
|
||||
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||
import { notifyApplicationBusy } from '../../redux/actions/common_actions';
|
||||
import { notifyError, notifyInfo } from '../../redux/actions/error_actions';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import { displayPinnedManager } from '../../redux/actions/pinned_manager_actions';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faFolder } from '@fortawesome/free-solid-svg-icons';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
import CheckBox from '../../components/UI/CheckBox/CheckBox';
|
||||
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { connect } from 'react-redux';
|
||||
import { displayPinnedManager } from '../../redux/actions/pinned_manager_actions';
|
||||
import { faFolder } from '@fortawesome/free-solid-svg-icons';
|
||||
import { notifyApplicationBusy } from '../../redux/actions/common_actions';
|
||||
import { notifyError, notifyInfo } from '../../redux/actions/error_actions';
|
||||
|
||||
const Constants = require('../../constants');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user