Add module unload confirmations
This commit is contained in:
parent
d85083abd6
commit
ab8f7d698c
|
@ -907,7 +907,7 @@ class Graph extends React.Component {
|
|||
} else if (
|
||||
(selected.type === 'sink' || selected.type === 'source') &&
|
||||
pai &&
|
||||
typeof pai.moduleIndex === 'number'
|
||||
pai.moduleIndex >= 0
|
||||
) {
|
||||
this.props.unloadModuleByIndex(pai.moduleIndex);
|
||||
}
|
||||
|
@ -1288,6 +1288,7 @@ module.exports = connect(
|
|||
}),
|
||||
dispatch => bindActionCreators(omit([
|
||||
'serverInfo',
|
||||
'unloadModuleByIndex',
|
||||
], merge(pulseActions, iconsActions)), dispatch),
|
||||
null,
|
||||
{ withRef: true },
|
||||
|
|
160
components/modals/index.js
Normal file
160
components/modals/index.js
Normal file
|
@ -0,0 +1,160 @@
|
|||
|
||||
const {
|
||||
mapObjIndexed,
|
||||
map,
|
||||
merge,
|
||||
path,
|
||||
} = require('ramda');
|
||||
|
||||
const r = require('r-dom');
|
||||
|
||||
const React = require('react');
|
||||
|
||||
const Modal = require('react-modal');
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
const { bindActionCreators } = require('redux');
|
||||
|
||||
const {
|
||||
pulse: pulseActions,
|
||||
preferences: preferencesActions,
|
||||
} = require('../../actions');
|
||||
|
||||
const {
|
||||
getPaiByTypeAndIndex,
|
||||
} = require('../../selectors');
|
||||
|
||||
const { modules } = require('../../constants/pulse');
|
||||
|
||||
const Checkbox = require('../checkbox');
|
||||
const Button = require('../button');
|
||||
|
||||
Modal.setAppElement('#root');
|
||||
|
||||
Modal.defaultStyles = {
|
||||
overlay: {},
|
||||
content: {},
|
||||
};
|
||||
|
||||
class ConfirmationModal extends React.PureComponent {
|
||||
render() {
|
||||
const { target, confirmation, onConfirm, onCancel } = this.props;
|
||||
|
||||
return r(Modal, {
|
||||
isOpen: Boolean(confirmation),
|
||||
onRequestClose: onCancel,
|
||||
}, [
|
||||
confirmation === 'unloadModuleByIndex' && r(React.Fragment, [
|
||||
r.h3('Module unload confirmation'),
|
||||
|
||||
target && r.p([
|
||||
'You are about to unload ',
|
||||
r.code(target.name),
|
||||
'.',
|
||||
'This may not be easily undoable and may impair sound playback on your system.',
|
||||
]),
|
||||
]),
|
||||
|
||||
r(Checkbox, {
|
||||
checked: this.props.preferences.doNotAskForConfirmations,
|
||||
onChange: () => this.props.toggle('doNotAskForConfirmations'),
|
||||
}, 'Do not ask for confirmations'),
|
||||
|
||||
r.div({
|
||||
className: 'button-group',
|
||||
}, [
|
||||
r(Button, {
|
||||
onClick: onCancel,
|
||||
}, 'Cancel'),
|
||||
|
||||
r(Button, {
|
||||
onClick: onConfirm,
|
||||
autoFocus: true,
|
||||
}, 'Confirm'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class Modals extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.initialState = {
|
||||
target: null,
|
||||
confirmation: null,
|
||||
continuation: null,
|
||||
};
|
||||
this.state = this.initialState;
|
||||
|
||||
this.handleCancel = this.handleCancel.bind(this);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props) {
|
||||
return {
|
||||
actions: mapObjIndexed((f, name) => function (...args) {
|
||||
const continuation = () => {
|
||||
props[name](...args);
|
||||
this.setState(this.initialState);
|
||||
};
|
||||
|
||||
if (props.preferences.doNotAskForConfirmations) {
|
||||
return continuation();
|
||||
}
|
||||
|
||||
const target = f(...args);
|
||||
|
||||
if (!target) {
|
||||
return continuation();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
target,
|
||||
continuation,
|
||||
confirmation: name,
|
||||
});
|
||||
}, {
|
||||
unloadModuleByIndex(index) {
|
||||
const pai = getPaiByTypeAndIndex('module', index)({ pulse: props });
|
||||
|
||||
if (pai && path([ pai.name, 'confirmUnload' ], modules)) {
|
||||
return pai;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
handleCancel() {
|
||||
this.setState(this.initialState);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { preferences, toggle, children } = this.props;
|
||||
const { actions, target, confirmation, continuation } = this.state;
|
||||
|
||||
return r(React.Fragment, [
|
||||
...children({ actions: map(a => a.bind(this), actions) }),
|
||||
|
||||
r(ConfirmationModal, {
|
||||
target,
|
||||
confirmation,
|
||||
onConfirm: continuation,
|
||||
onCancel: this.handleCancel,
|
||||
|
||||
preferences,
|
||||
toggle,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(
|
||||
state => ({
|
||||
infos: state.pulse.infos,
|
||||
preferences: state.preferences,
|
||||
}),
|
||||
dispatch => bindActionCreators(merge(pulseActions, preferencesActions), dispatch),
|
||||
)(Modals);
|
|
@ -153,6 +153,13 @@ class Preferences extends React.Component {
|
|||
|
||||
r.hr(),
|
||||
|
||||
r.div([
|
||||
r(Checkbox, {
|
||||
checked: this.props.preferences.doNotAskForConfirmations,
|
||||
onChange: () => this.props.actions.toggle('doNotAskForConfirmations'),
|
||||
}, 'Do not ask for confirmations'),
|
||||
]),
|
||||
|
||||
r.div([
|
||||
r(Checkbox, {
|
||||
checked: this.props.preferences.showDebugInfo,
|
||||
|
|
|
@ -31,8 +31,43 @@ const things = [ {
|
|||
key: 'sourceOutputs',
|
||||
} ];
|
||||
|
||||
const modules = {
|
||||
'module-alsa-sink': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
'module-alsa-source': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
'module-alsa-card': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
'module-oss': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
'module-solaris': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
|
||||
'module-cli': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
'module-cli-protocol-unix': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
'module-simple-protocol-unix': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
'module-esound-protocol-unix': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
'module-native-protocol-unix': {
|
||||
confirmUnload: true,
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
PA_VOLUME_NORM,
|
||||
|
||||
things,
|
||||
modules,
|
||||
};
|
||||
|
|
22
index.css
22
index.css
|
@ -37,6 +37,11 @@ div[tabindex="-1"]:focus {
|
|||
top: 1px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.label {
|
||||
user-select: none;
|
||||
|
||||
|
@ -234,6 +239,23 @@ div[tabindex="-1"]:focus {
|
|||
border-top: 1px solid var(--borders);
|
||||
}
|
||||
|
||||
.ReactModal__Overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content : center;
|
||||
}
|
||||
|
||||
.ReactModal__Content {
|
||||
background: var(--themeBgColor);
|
||||
border: 1px solid var(--borders);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.view-wrapper .graph .edge-mouse-handler {
|
||||
stroke-width: 30px;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
"react-digraph": "^5.1.3",
|
||||
"react-dom": "^16.6.0",
|
||||
"react-hotkeys": "^1.1.4",
|
||||
"react-modal": "^3.6.1",
|
||||
"react-redux": "^5.1.0",
|
||||
"recompose": "^0.30.0",
|
||||
"redux": "^4.0.1",
|
||||
|
|
|
@ -23,6 +23,7 @@ const initialState = {
|
|||
maxVolume: 1.5,
|
||||
volumeStep: 1 / 20,
|
||||
|
||||
doNotAskForConfirmations: false,
|
||||
showDebugInfo: false,
|
||||
};
|
||||
|
||||
|
|
10
renderer.js
10
renderer.js
|
@ -14,17 +14,21 @@ const Preferences = require('./components/preferences');
|
|||
const Log = require('./components/log');
|
||||
const { HotKeys } = require('./components/hot-keys');
|
||||
const { MenuProvider } = require('./components/menu');
|
||||
const Modals = require('./components/modals');
|
||||
|
||||
const theme = require('./utils/theme');
|
||||
|
||||
const Root = () => r(ReduxProvider, {
|
||||
store: createStore(),
|
||||
}, r(MenuProvider, {}, r(HotKeys, {}, ({ graphRef, cardsRef, preferencesRef }) => [
|
||||
r(Graph, { ref: graphRef }),
|
||||
}, r(MenuProvider, {
|
||||
}, r(HotKeys, {
|
||||
}, ({ graphRef, cardsRef, preferencesRef }) => r(Modals, {
|
||||
}, ({ actions }) => [
|
||||
r(Graph, { ref: graphRef, ...actions }),
|
||||
r(Cards, { ref: cardsRef }),
|
||||
r(Preferences, { ref: preferencesRef }),
|
||||
r(Log),
|
||||
])));
|
||||
]))));
|
||||
|
||||
Object.entries(theme.colors).forEach(([ key, value ]) => {
|
||||
document.body.style.setProperty('--' + key, value);
|
||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -2334,6 +2334,11 @@ execa@^0.9.0:
|
|||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
exenv@^1.2.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||
integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
|
||||
|
||||
exit-hook@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
|
||||
|
@ -4936,7 +4941,7 @@ promise@^7.1.1:
|
|||
dependencies:
|
||||
asap "~2.0.3"
|
||||
|
||||
prop-types@^15.5.6, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2:
|
||||
prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2:
|
||||
version "15.6.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||
integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==
|
||||
|
@ -5113,6 +5118,16 @@ react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.2:
|
|||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-modal@^3.6.1:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.6.1.tgz#54d27a1ec2b493bbc451c7efaa3557b6af82332d"
|
||||
integrity sha512-vAhnawahH1fz8A5x/X/1X20KHMe6Q0mkfU5BKPgKSVPYhMhsxtRbNHSitsoJ7/oP27xZo3naZZlwYuuzuSO1xw==
|
||||
dependencies:
|
||||
exenv "^1.2.0"
|
||||
prop-types "^15.5.10"
|
||||
react-lifecycles-compat "^3.0.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
react-redux@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.0.tgz#948b1e2686473d1999092bcfb32d0dc43d33f667"
|
||||
|
|
Loading…
Reference in New Issue
Block a user