[#38: Enhance new repertory release available notification - partial] [Added FocusTrap to modals]
This commit is contained in:
@@ -1,4 +1,8 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 1.1.5
|
||||||
|
* \#38: Enhance new repertory release available notification
|
||||||
|
* Added `FocusTrap` to modals
|
||||||
|
|
||||||
## 1.1.4
|
## 1.1.4
|
||||||
* \#39: Cleanup old releases and UI upgrades
|
* \#39: Cleanup old releases and UI upgrades
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"devtron": "^1.4.0",
|
"devtron": "^1.4.0",
|
||||||
"electron-debug": "^3.0.1",
|
"electron-debug": "^3.0.1",
|
||||||
"electron-log": "^4.0.6",
|
"electron-log": "^4.0.6",
|
||||||
|
"focus-trap-react": "^6.0.0",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"node-schedule": "^1.3.2",
|
"node-schedule": "^1.3.2",
|
||||||
"randomstring": "^1.1.5",
|
"randomstring": "^1.1.5",
|
||||||
|
|||||||
20
src/App.js
20
src/App.js
@@ -11,6 +11,7 @@ import InfoDetails from './components/InfoDetails/InfoDetails';
|
|||||||
import IPCContainer from './containers/IPCContainer/IPCContainer';
|
import IPCContainer from './containers/IPCContainer/IPCContainer';
|
||||||
import Loading from './components/UI/Loading/Loading';
|
import Loading from './components/UI/Loading/Loading';
|
||||||
import MountItems from './containers/MountItems/MountItems';
|
import MountItems from './containers/MountItems/MountItems';
|
||||||
|
import NewReleases from './components/NewReleases/NewReleases';
|
||||||
import {notifyError} from './redux/actions/error_actions';
|
import {notifyError} from './redux/actions/error_actions';
|
||||||
import Reboot from './components/Reboot/Reboot';
|
import Reboot from './components/Reboot/Reboot';
|
||||||
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
|
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
|
||||||
@@ -111,12 +112,26 @@ class App extends IPCContainer {
|
|||||||
!this.props.DismissDependencies &&
|
!this.props.DismissDependencies &&
|
||||||
this.props.AllowMount;
|
this.props.AllowMount;
|
||||||
|
|
||||||
|
const showNewReleases = !showConfig &&
|
||||||
|
!this.props.DisplayConfirmYesNo &&
|
||||||
|
!showDependencies &&
|
||||||
|
!this.props.DownloadActive &&
|
||||||
|
!this.props.DisplayError &&
|
||||||
|
!this.props.DisplayInfo &&
|
||||||
|
!this.props.InstallActive &&
|
||||||
|
!this.props.RebootRequired &&
|
||||||
|
!this.props.DisplaySelectAppPlatform &&
|
||||||
|
!showUpgrade &&
|
||||||
|
!this.props.DismissNewReleasesAvailable &&
|
||||||
|
(this.props.NewReleasesAvailable.length > 0);
|
||||||
|
|
||||||
const configDisplay = createModalConditionally(showConfig, <Configuration version={selectedVersion} remoteSupported={remoteSupported} />);
|
const configDisplay = createModalConditionally(showConfig, <Configuration version={selectedVersion} remoteSupported={remoteSupported} />);
|
||||||
const confirmDisplay = createModalConditionally(this.props.DisplayConfirmYesNo, <YesNo/>);
|
const confirmDisplay = createModalConditionally(this.props.DisplayConfirmYesNo, <YesNo/>);
|
||||||
const dependencyDisplay = createModalConditionally(showDependencies, <DependencyList/>);
|
const dependencyDisplay = createModalConditionally(showDependencies, <DependencyList/>);
|
||||||
const downloadDisplay = createModalConditionally(this.props.DownloadActive, <DownloadProgress/>);
|
const downloadDisplay = createModalConditionally(this.props.DownloadActive, <DownloadProgress />, false, true);
|
||||||
const errorDisplay = createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true);
|
const errorDisplay = createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true);
|
||||||
const infoDisplay = createModalConditionally(this.props.DisplayInfo, <InfoDetails/>, true);
|
const infoDisplay = createModalConditionally(this.props.DisplayInfo, <InfoDetails/>, true);
|
||||||
|
const newReleasesDisplay = createModalConditionally(showNewReleases, <NewReleases/>);
|
||||||
const rebootDisplay = createModalConditionally(this.props.RebootRequired, <Reboot />);
|
const rebootDisplay = createModalConditionally(this.props.RebootRequired, <Reboot />);
|
||||||
const selectAppPlatformDisplay = createModalConditionally(this.props.DisplaySelectAppPlatform, <SelectAppPlatform/>);
|
const selectAppPlatformDisplay = createModalConditionally(this.props.DisplaySelectAppPlatform, <SelectAppPlatform/>);
|
||||||
const upgradeDisplay = createModalConditionally(showUpgrade, <UpgradeUI/>);
|
const upgradeDisplay = createModalConditionally(showUpgrade, <UpgradeUI/>);
|
||||||
@@ -175,6 +190,7 @@ class App extends IPCContainer {
|
|||||||
{mainContent}
|
{mainContent}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{newReleasesDisplay}
|
||||||
{selectAppPlatformDisplay}
|
{selectAppPlatformDisplay}
|
||||||
{dependencyDisplay}
|
{dependencyDisplay}
|
||||||
{upgradeDisplay}
|
{upgradeDisplay}
|
||||||
@@ -201,12 +217,14 @@ const mapStateToProps = state => {
|
|||||||
DisplayError: state.error.DisplayError,
|
DisplayError: state.error.DisplayError,
|
||||||
DisplayInfo: state.error.DisplayInfo,
|
DisplayInfo: state.error.DisplayInfo,
|
||||||
DisplaySelectAppPlatform: state.common.DisplaySelectAppPlatform,
|
DisplaySelectAppPlatform: state.common.DisplaySelectAppPlatform,
|
||||||
|
DismissNewReleasesAvailable: state.relver.DismissNewReleasesAvailable,
|
||||||
DownloadActive: state.download.DownloadActive,
|
DownloadActive: state.download.DownloadActive,
|
||||||
InstallActive: state.install.InstallActive,
|
InstallActive: state.install.InstallActive,
|
||||||
InstalledVersion: state.relver.InstalledVersion,
|
InstalledVersion: state.relver.InstalledVersion,
|
||||||
LocationsLookup: state.relver.LocationsLookup,
|
LocationsLookup: state.relver.LocationsLookup,
|
||||||
MissingDependencies: state.install.MissingDependencies,
|
MissingDependencies: state.install.MissingDependencies,
|
||||||
MountsBusy: state.mounts.MountsBusy,
|
MountsBusy: state.mounts.MountsBusy,
|
||||||
|
NewReleasesAvailable: state.relver.NewReleasesAvailable,
|
||||||
Platform: state.common.Platform,
|
Platform: state.common.Platform,
|
||||||
ProviderState: state.mounts.ProviderState,
|
ProviderState: state.mounts.ProviderState,
|
||||||
RebootRequired: state.common.RebootRequired,
|
RebootRequired: state.common.RebootRequired,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default connect(mapStateToProps)(props => {
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{props.AllowDownload ?
|
{props.AllowDownload ?
|
||||||
<a href={void(0)}
|
<a href={'#'}
|
||||||
className={'DependencyLink'}
|
className={'DependencyLink'}
|
||||||
onClick={()=>{props.onDownload(); return false;}}><u>Install</u></a> :
|
onClick={()=>{props.onDownload(); return false;}}><u>Install</u></a> :
|
||||||
'Installing...'}
|
'Installing...'}
|
||||||
|
|||||||
28
src/components/NewReleases/NewRelease/NewRelease.js
Normal file
28
src/components/NewReleases/NewRelease/NewRelease.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as Constants from '../../../constants';
|
||||||
|
import Button from '../../UI/Button/Button';
|
||||||
|
|
||||||
|
export default ({release}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>{'[' + Constants.RELEASE_TYPES[release.Release].toUpperCase() + '] ' + release.Display }</h3>
|
||||||
|
<table cellSpacing={0} cellPadding={0} width="97%">
|
||||||
|
<tbody>
|
||||||
|
<tr style={{height: '4px'}}/>
|
||||||
|
<tr>
|
||||||
|
<td width="50%">
|
||||||
|
<Button buttonStyles={{width: '100%'}}>Changes</Button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div style={{width: 'var(--default_spacing)'}}/>
|
||||||
|
</td>
|
||||||
|
<td width="50%">
|
||||||
|
<Button buttonStyles={{width: '100%'}}>Install</Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style={{height: 'var(--default_spacing)'}}/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
11
src/components/NewReleases/NewReleases.css
Normal file
11
src/components/NewReleases/NewReleases.css
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.NewReleasesHeading {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.NewReleasesContent {
|
||||||
|
max-height: 60vh;
|
||||||
|
min-width: 50vw;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-bottom: var(--default_spacing);
|
||||||
|
}
|
||||||
35
src/components/NewReleases/NewReleases.js
Normal file
35
src/components/NewReleases/NewReleases.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import Box from '../UI/Box/Box';
|
||||||
|
import Button from '../UI/Button/Button';
|
||||||
|
import NewRelease from './NewRelease/NewRelease';
|
||||||
|
import './NewReleases.css';
|
||||||
|
import {setDismissNewReleasesAvailable} from '../../redux/actions/release_version_actions';
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
NewReleasesAvailable: state.relver.NewReleasesAvailable,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
dismissNewReleasesAvailable: () => dispatch(setDismissNewReleasesAvailable(true)),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||||
|
const newReleases = props.NewReleasesAvailable.map(i => {
|
||||||
|
return <NewRelease key={'new_release_' + i.Release + '_' + i.Version} release={i} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||||
|
<h1 className={'NewReleasesHeading'}>New Repertory Versions Available</h1>
|
||||||
|
<div className={'NewReleasesContent'}>
|
||||||
|
{newReleases}
|
||||||
|
</div>
|
||||||
|
<Button clicked={props.dismissNewReleasesAvailable}>Dismiss</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -4,6 +4,7 @@ import './Button.css';
|
|||||||
export default props => {
|
export default props => {
|
||||||
return (
|
return (
|
||||||
<button disabled={props.disabled}
|
<button disabled={props.disabled}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
className={'Button'}
|
className={'Button'}
|
||||||
style={props.buttonStyles}
|
style={props.buttonStyles}
|
||||||
onClick={props.clicked}>{props.children}</button>
|
onClick={props.clicked}>{props.children}</button>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export default props => {
|
|||||||
<div className={'CheckBoxOwner'}>
|
<div className={'CheckBoxOwner'}>
|
||||||
<label className='CheckBoxLabel'>{props.label}
|
<label className='CheckBoxLabel'>{props.label}
|
||||||
<input checked={JSON.parse(props.checked)}
|
<input checked={JSON.parse(props.checked)}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
onChange={props.changed}
|
onChange={props.changed}
|
||||||
type='checkbox'/>
|
type='checkbox'/>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export default props => {
|
|||||||
return (
|
return (
|
||||||
<div className={'DropDown'}>
|
<div className={'DropDown'}>
|
||||||
<select className={'DropDownSelect' + (props.auto ? ' Auto ' : '') + (props.alt ? ' Alt ' : '') }
|
<select className={'DropDownSelect' + (props.auto ? ' Auto ' : '') + (props.alt ? ' Alt ' : '') }
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
onChange={props.changed}
|
onChange={props.changed}
|
||||||
value={props.selected}>
|
value={props.selected}>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import './Modal.css'
|
import './Modal.css'
|
||||||
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
|
||||||
export default props => {
|
export default props => {
|
||||||
let modalStyles = [];
|
let modalStyles = [];
|
||||||
@@ -12,11 +14,14 @@ export default props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<FocusTrap active={!props.disableFocusTrap}>
|
||||||
<div
|
<div
|
||||||
className={modalStyles.join(' ')}
|
className={modalStyles.join(' ')}
|
||||||
onClick={props.clicked}>
|
onClick={props.clicked}>
|
||||||
<div className={contentStyles.join(' ')}>
|
<div className={contentStyles.join(' ')}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>
|
||||||
|
</FocusTrap>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
@@ -163,6 +163,8 @@ class Configuration extends IPCContainer {
|
|||||||
ObjectLookup: objectLookup,
|
ObjectLookup: objectLookup,
|
||||||
OriginalItemList: itemListCopy,
|
OriginalItemList: itemListCopy,
|
||||||
OriginalObjectLookup: objectLookupCopy,
|
OriginalObjectLookup: objectLookupCopy,
|
||||||
|
}, () => {
|
||||||
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.props.notifyError(arg.data.Error);
|
this.props.notifyError(arg.data.Error);
|
||||||
@@ -262,20 +264,7 @@ class Configuration extends IPCContainer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const configurationItems = this.state.ItemList
|
let autoFocus = true;
|
||||||
.map((k, i) => {
|
|
||||||
return (
|
|
||||||
((!this.state.IsRemoteMount || !k.hide_remote) && (!k.advanced || (this.state.ShowAdvanced && k.advanced))) ?
|
|
||||||
<ConfigurationItem advanced={k.advanced}
|
|
||||||
changed={e=>this.handleItemChanged(e, i)}
|
|
||||||
grouping={'Settings'}
|
|
||||||
items={this.state.Template[k.label].items}
|
|
||||||
key={i}
|
|
||||||
label={k.label}
|
|
||||||
template={this.state.Template[k.label]}
|
|
||||||
value={k.value}/> :
|
|
||||||
null)
|
|
||||||
});
|
|
||||||
|
|
||||||
let objectItems = [];
|
let objectItems = [];
|
||||||
for (const key of Object.keys(this.state.ObjectLookup)) {
|
for (const key of Object.keys(this.state.ObjectLookup)) {
|
||||||
@@ -285,9 +274,12 @@ class Configuration extends IPCContainer {
|
|||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
this.state.ObjectLookup[key].map((k, i) => {
|
this.state.ObjectLookup[key].map((k, i) => {
|
||||||
|
const shouldFocus = autoFocus;
|
||||||
|
autoFocus = false;
|
||||||
return (
|
return (
|
||||||
(!k.advanced || (this.state.ShowAdvanced && k.advanced && !k.remote) || this.showRemoteConfigItem(k, this.state.ObjectLookup[key])) ?
|
(!k.advanced || (this.state.ShowAdvanced && k.advanced && !k.remote) || this.showRemoteConfigItem(k, this.state.ObjectLookup[key])) ?
|
||||||
<ConfigurationItem advanced={k.advanced}
|
<ConfigurationItem advanced={k.advanced}
|
||||||
|
autoFocus={shouldFocus}
|
||||||
changed={e=>this.handleObjectItemChanged(e, key, i)}
|
changed={e=>this.handleObjectItemChanged(e, key, i)}
|
||||||
grouping={key}
|
grouping={key}
|
||||||
items={this.state.Template[key].template[k.label].items}
|
items={this.state.Template[key].template[k.label].items}
|
||||||
@@ -304,13 +296,33 @@ class Configuration extends IPCContainer {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configurationItems = this.state.ItemList
|
||||||
|
.map((k, i) => {
|
||||||
|
const shouldFocus = autoFocus;
|
||||||
|
autoFocus = false;
|
||||||
|
return (
|
||||||
|
((!this.state.IsRemoteMount || !k.hide_remote) && (!k.advanced || (this.state.ShowAdvanced && k.advanced))) ?
|
||||||
|
<ConfigurationItem advanced={k.advanced}
|
||||||
|
autoFocus={shouldFocus}
|
||||||
|
changed={e=>this.handleItemChanged(e, i)}
|
||||||
|
grouping={'Settings'}
|
||||||
|
items={this.state.Template[k.label].items}
|
||||||
|
key={i}
|
||||||
|
label={k.label}
|
||||||
|
template={this.state.Template[k.label]}
|
||||||
|
value={k.value}/> :
|
||||||
|
null
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'Configuration'}>
|
<div className={'Configuration'}>
|
||||||
{confirmSave}
|
{confirmSave}
|
||||||
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
<Box dxDark dxStyle={{padding: 'var(--default_spacing)'}}>
|
||||||
<div style={{float: 'right', margin: 0, padding: 0, marginTop: '-4px', boxSizing: 'border-box', display: 'block'}}>
|
<div style={{float: 'right', margin: 0, padding: 0, marginTop: '-4px', boxSizing: 'border-box', display: 'block'}}>
|
||||||
<b style={{cursor: 'pointer'}}
|
<a href={'#'}
|
||||||
onClick={this.checkSaveRequired}>X</b>
|
onClick={this.checkSaveRequired}
|
||||||
|
style={{cursor: 'pointer'}}>X</a>
|
||||||
</div>
|
</div>
|
||||||
<h1 style={{width: '100%', textAlign: 'center'}}>{(
|
<h1 style={{width: '100%', textAlign: 'center'}}>{(
|
||||||
this.props.DisplayRemoteConfiguration ?
|
this.props.DisplayRemoteConfiguration ?
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default connect(null, mapDispatchToProps)(props => {
|
|||||||
const handleChanged = (e) => {
|
const handleChanged = (e) => {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
if (target.type === 'checkbox') {
|
if (target.type === 'checkbox') {
|
||||||
target.value = e.target.checked ? "true" : "false";
|
target.value = e.target.checked ? 'true' : 'false';
|
||||||
}
|
}
|
||||||
props.changed(target);
|
props.changed(target);
|
||||||
};
|
};
|
||||||
@@ -30,49 +30,54 @@ export default connect(null, mapDispatchToProps)(props => {
|
|||||||
props.notifyInfo(props.label, description);
|
props.notifyInfo(props.label, description);
|
||||||
};
|
};
|
||||||
|
|
||||||
infoDisplay = <a href={void(0)}
|
infoDisplay = <a href={'#'}
|
||||||
className={'ConfigurationInfo'}
|
className={'ConfigurationInfo'}
|
||||||
onClick={()=>{displayInfo(); return false;}}><FontAwesomeIcon icon={faInfoCircle}/></a>;
|
onClick={()=>{displayInfo(); return false;}}><FontAwesomeIcon icon={faInfoCircle}/></a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let data;
|
let data;
|
||||||
switch (props.template.type) {
|
switch (props.template.type) {
|
||||||
case "bool":
|
case 'bool':
|
||||||
data = <CheckBox changed={handleChanged}
|
data = <CheckBox changed={handleChanged}
|
||||||
checked={props.value}
|
checked={props.value}
|
||||||
disabled={props.readOnly}/>;
|
disabled={props.readOnly}
|
||||||
|
autoFocus={props.autoFocus}/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "double":
|
case 'double':
|
||||||
data = <input min={0.0}
|
data = <input min={0.0}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
disabled={props.readOnly}
|
disabled={props.readOnly}
|
||||||
onChange={e=>handleChanged(e)}
|
onChange={e=>handleChanged(e)}
|
||||||
step={"0.01"}
|
step={'0.01'}
|
||||||
className={'ConfigurationItemInput'}
|
className={'ConfigurationItemInput'}
|
||||||
type={'number'}
|
type={'number'}
|
||||||
value={parseFloat(props.value).toFixed(2)}/>;
|
value={parseFloat(props.value).toFixed(2)}/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "list":
|
case 'list':
|
||||||
data = <DropDown alt
|
data = <DropDown alt
|
||||||
auto
|
auto
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
changed={handleChanged}
|
changed={handleChanged}
|
||||||
disabled={props.readOnly}
|
disabled={props.readOnly}
|
||||||
items={props.items}
|
items={props.items}
|
||||||
selected={props.value} />;
|
selected={props.value} />;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "string":
|
case 'string':
|
||||||
data = <input onChange={e=>handleChanged(e)}
|
data = <input onChange={e=>handleChanged(e)}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
className={'ConfigurationItemInput'}
|
className={'ConfigurationItemInput'}
|
||||||
disabled={props.readOnly}
|
disabled={props.readOnly}
|
||||||
type={'text'}
|
type={'text'}
|
||||||
value={props.value}/>;
|
value={props.value}/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "uint8":
|
case 'uint8':
|
||||||
data = <input max={255}
|
data = <input max={255}
|
||||||
min={0}
|
min={0}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
disabled={props.readOnly}
|
disabled={props.readOnly}
|
||||||
onChange={e=>handleChanged(e)}
|
onChange={e=>handleChanged(e)}
|
||||||
className={'ConfigurationItemInput'}
|
className={'ConfigurationItemInput'}
|
||||||
@@ -80,9 +85,10 @@ export default connect(null, mapDispatchToProps)(props => {
|
|||||||
value={props.value}/>;
|
value={props.value}/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "uint16":
|
case 'uint16':
|
||||||
data = <input max={65535}
|
data = <input max={65535}
|
||||||
min={0}
|
min={0}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
disabled={props.readOnly}
|
disabled={props.readOnly}
|
||||||
onChange={e=>handleChanged(e)}
|
onChange={e=>handleChanged(e)}
|
||||||
className={'ConfigurationItemInput'}
|
className={'ConfigurationItemInput'}
|
||||||
@@ -90,9 +96,10 @@ export default connect(null, mapDispatchToProps)(props => {
|
|||||||
value={props.value}/>;
|
value={props.value}/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "uint32":
|
case 'uint32':
|
||||||
data = <input max={4294967295}
|
data = <input max={4294967295}
|
||||||
min={0}
|
min={0}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
disabled={props.readOnly}
|
disabled={props.readOnly}
|
||||||
onChange={e=>handleChanged(e)}
|
onChange={e=>handleChanged(e)}
|
||||||
className={'ConfigurationItemInput'}
|
className={'ConfigurationItemInput'}
|
||||||
@@ -100,9 +107,10 @@ export default connect(null, mapDispatchToProps)(props => {
|
|||||||
value={props.value}/>;
|
value={props.value}/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "uint64":
|
case 'uint64':
|
||||||
data = <input max={18446744073709551615}
|
data = <input max={18446744073709551615}
|
||||||
min={0}
|
min={0}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
disabled={props.readOnly}
|
disabled={props.readOnly}
|
||||||
onChange={e=>handleChanged(e)}
|
onChange={e=>handleChanged(e)}
|
||||||
className={'ConfigurationItemInput'}
|
className={'ConfigurationItemInput'}
|
||||||
|
|||||||
@@ -152,8 +152,8 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
removeControl = (
|
removeControl = (
|
||||||
<a col={dimensions=>dimensions.columns - 6}
|
<a href={'#'}
|
||||||
href={void(0)}
|
col={dimensions=>dimensions.columns - 6}
|
||||||
onClick={handleRemoveMount}
|
onClick={handleRemoveMount}
|
||||||
row={secondRow + 3}
|
row={secondRow + 3}
|
||||||
style={removeStyle}>
|
style={removeStyle}>
|
||||||
|
|||||||
@@ -30,6 +30,9 @@
|
|||||||
|
|
||||||
a {
|
a {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
|
color: var(--text_color);
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ import {
|
|||||||
setDismissDependencies
|
setDismissDependencies
|
||||||
} from './install_actions';
|
} from './install_actions';
|
||||||
import {unmountAll} from './mount_actions';
|
import {unmountAll} from './mount_actions';
|
||||||
import {getIPCRenderer} from '../../utils';
|
import {
|
||||||
|
getIPCRenderer,
|
||||||
|
getNewReleases
|
||||||
|
} from '../../utils';
|
||||||
|
|
||||||
export const CLEAR_UI_UPGRADE = 'relver/clearUIUpgrade';
|
export const CLEAR_UI_UPGRADE = 'relver/clearUIUpgrade';
|
||||||
export const clearUIUpgrade = () => {
|
export const clearUIUpgrade = () => {
|
||||||
@@ -123,11 +126,22 @@ export const loadReleases = () => {
|
|||||||
...response.data.Locations[appPlatform],
|
...response.data.Locations[appPlatform],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const storedReleases = localStorage.getItem('releases');
|
||||||
|
let newReleases = [];
|
||||||
|
if (storedReleases && (storedReleases.length > 0)) {
|
||||||
|
newReleases = getNewReleases(JSON.parse(storedReleases).VersionLookup, versionLookup);
|
||||||
|
}
|
||||||
|
|
||||||
localStorage.setItem('releases', JSON.stringify({
|
localStorage.setItem('releases', JSON.stringify({
|
||||||
LocationsLookup: locationsLookup,
|
LocationsLookup: locationsLookup,
|
||||||
VersionLookup: versionLookup
|
VersionLookup: versionLookup
|
||||||
}));
|
}));
|
||||||
dispatchActions(locationsLookup, versionLookup);
|
dispatchActions(locationsLookup, versionLookup);
|
||||||
|
|
||||||
|
dispatch(setNewReleasesAvailable(newReleases));
|
||||||
|
if (getState().relver.NewReleasesAvailable.length > 0) {
|
||||||
|
dispatch(showWindow());
|
||||||
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
const releases = localStorage.getItem('releases');
|
const releases = localStorage.getItem('releases');
|
||||||
if (releases && (releases.length > 0)) {
|
if (releases && (releases.length > 0)) {
|
||||||
@@ -174,8 +188,10 @@ export const setActiveRelease = (release, version) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const setAllowDismissDependencies = createAction('relver/setAllowDismissDependencies');
|
export const setAllowDismissDependencies = createAction('relver/setAllowDismissDependencies');
|
||||||
|
export const setDismissNewReleasesAvailable = createAction('relver/setDismissNewReleasesAvailable');
|
||||||
export const setDismissUIUpgrade = createAction('relver/setDismissUIUpgrade');
|
export const setDismissUIUpgrade = createAction('relver/setDismissUIUpgrade');
|
||||||
export const setInstalledVersion = createAction('relver/setInstalledVersion');
|
export const setInstalledVersion = createAction('relver/setInstalledVersion');
|
||||||
|
export const setNewReleasesAvailable = createAction('relver/setNewReleasesAvailable');
|
||||||
|
|
||||||
export const SET_RELEASE_DATA = 'relver/setReleaseData';
|
export const SET_RELEASE_DATA = 'relver/setReleaseData';
|
||||||
export const setReleaseData = (locationsLookup, versionLookup)=> {
|
export const setReleaseData = (locationsLookup, versionLookup)=> {
|
||||||
|
|||||||
@@ -15,8 +15,10 @@ const versionLookup = Constants.RELEASE_TYPES.map(k=> {
|
|||||||
|
|
||||||
export const releaseVersionReducer = createReducer({
|
export const releaseVersionReducer = createReducer({
|
||||||
AllowDismissDependencies: false,
|
AllowDismissDependencies: false,
|
||||||
|
DismissNewReleasesAvailable: true,
|
||||||
InstalledVersion: 'none',
|
InstalledVersion: 'none',
|
||||||
LocationsLookup: {},
|
LocationsLookup: {},
|
||||||
|
NewReleasesAvailable: [],
|
||||||
Release: 0,
|
Release: 0,
|
||||||
ReleaseDefault: 0,
|
ReleaseDefault: 0,
|
||||||
ReleaseUpgradeAvailable: false,
|
ReleaseUpgradeAvailable: false,
|
||||||
@@ -49,6 +51,12 @@ export const releaseVersionReducer = createReducer({
|
|||||||
AllowDismissDependencies: action.payload,
|
AllowDismissDependencies: action.payload,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
[Actions.setDismissNewReleasesAvailable]: (state, action) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
DismissNewReleasesAvailable: action.payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
[Actions.setDismissUIUpgrade]: (state, action) => {
|
[Actions.setDismissUIUpgrade]: (state, action) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@@ -61,6 +69,13 @@ export const releaseVersionReducer = createReducer({
|
|||||||
InstalledVersion: action.payload,
|
InstalledVersion: action.payload,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[Actions.setNewReleasesAvailable]: (state, action) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
DismissNewReleasesAvailable: false,
|
||||||
|
NewReleasesAvailable: action.payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
[Actions.SET_RELEASE_DATA]: (state, action) => {
|
[Actions.SET_RELEASE_DATA]: (state, action) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
35
src/utils.js
35
src/utils.js
@@ -6,8 +6,8 @@ const ipcRenderer = (!process.versions.hasOwnProperty('electron') && window && w
|
|||||||
window.require('electron').ipcRenderer :
|
window.require('electron').ipcRenderer :
|
||||||
null;
|
null;
|
||||||
|
|
||||||
export const createModalConditionally = (condition, jsx, critical) => {
|
export const createModalConditionally = (condition, jsx, critical, disableFocusTrap) => {
|
||||||
const modalProps = {critical: critical};
|
const modalProps = {critical: critical, disableFocusTrap: disableFocusTrap};
|
||||||
return condition ? (<Modal {...modalProps}>{jsx}</Modal>) : null;
|
return condition ? (<Modal {...modalProps}>{jsx}</Modal>) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,6 +20,37 @@ export const getIPCRenderer = () => {
|
|||||||
return ipcRenderer;
|
return ipcRenderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getNewReleases = (existingReleases, newReleases) => {
|
||||||
|
const ret = [];
|
||||||
|
|
||||||
|
existingReleases = Constants.RELEASE_TYPES.reduce((map, release) => {
|
||||||
|
map[release] = [];
|
||||||
|
return map;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
if (existingReleases && newReleases) {
|
||||||
|
Constants.RELEASE_TYPES.forEach(release => {
|
||||||
|
newReleases[release]
|
||||||
|
.filter(version => !existingReleases[release].includes(version) && (version !== 'unavailable'))
|
||||||
|
.forEach(version => {
|
||||||
|
ret.splice(0, 0, {
|
||||||
|
Display: version,
|
||||||
|
Release: Constants.RELEASE_TYPES.indexOf(release),
|
||||||
|
Version: newReleases[release].indexOf(version),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.splice(0, 0, {
|
||||||
|
Display: '1.1.1',
|
||||||
|
Release: 0,
|
||||||
|
Version: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
export const getSelectedVersionFromState = state => {
|
export const getSelectedVersionFromState = state => {
|
||||||
return (state.relver.Version === -1) ?
|
return (state.relver.Version === -1) ?
|
||||||
'unavailable' :
|
'unavailable' :
|
||||||
|
|||||||
Reference in New Issue
Block a user