refactor(xod-client,xod-client-electron): make popups show/hide on actual actionType, not an abstract commands like “SHOW_POPUP”

This commit is contained in:
Kirill Shumilov
2017-05-15 17:01:05 +03:00
parent 7319fb8f99
commit 77d2ff55e6
16 changed files with 153 additions and 95 deletions

View File

@@ -4,7 +4,11 @@ import ReactDOM from 'react-dom';
import { Root, initialState } from 'xod-client';
import App from './view/containers/App';
const extraReducers = {};
import popupsReducer from './popups/reducer';
const extraReducers = {
popups: popupsReducer,
};
ReactDOM.render(
<Root

View File

@@ -0,0 +1,48 @@
import {
popupsReducer,
showOnlyPopup,
hideOnePopup,
POPUP_ID,
} from 'xod-client';
import {
UPLOAD,
UPLOAD_TO_ARDUINO,
} from '../upload/actionTypes';
import {
CREATE_WORKSPACE_REQUESTED,
SWITCH_WORKSPACE_REQUESTED,
CREATE_WORKSPACE,
SWITCH_WORKSPACE,
} from '../settings/actionTypes';
export default (state, action) => {
switch (action.type) {
case UPLOAD:
case UPLOAD_TO_ARDUINO: {
if (action.meta.status === 'started') {
return showOnlyPopup(POPUP_ID.UPLOADING, {}, state);
}
if (action.meta.status === 'deleted') {
return hideOnePopup(POPUP_ID.UPLOADING, state);
}
return state;
}
case CREATE_WORKSPACE_REQUESTED:
return showOnlyPopup(POPUP_ID.CREATING_WORKSPACE, action.payload, state);
case SWITCH_WORKSPACE_REQUESTED:
return showOnlyPopup(POPUP_ID.SWITCHING_WORKSPACE, action.payload, state);
case CREATE_WORKSPACE:
return hideOnePopup(POPUP_ID.CREATING_WORKSPACE, state);
case SWITCH_WORKSPACE:
return hideOnePopup(POPUP_ID.SWITCHING_WORKSPACE, state);
default:
return popupsReducer(state, action);
}
};

View File

@@ -0,0 +1,5 @@
export const CREATE_WORKSPACE_REQUESTED = 'CREATE_WORKSPACE_REQUESTED';
export const SWITCH_WORKSPACE_REQUESTED = 'SWITCH_WORKSPACE_REQUESTED';
export const CREATE_WORKSPACE = 'CREATE_WORKSPACE';
export const SWITCH_WORKSPACE = 'SWITCH_WORKSPACE';

View File

@@ -1,57 +1,24 @@
import R from 'ramda';
import { openWorkspace } from 'xod-client';
import {
SET_WORKSPACE,
CHECK_WORKSPACE,
CHANGE_WORKSPACE,
CREATE_WORKSPACE_REQUESTED,
SWITCH_WORKSPACE_REQUESTED,
CREATE_WORKSPACE,
SWITCH_WORKSPACE,
} from './actionTypes';
import { createAsyncAction } from '../view/actions';
export const setWorkspace = newPath => ({
type: SET_WORKSPACE,
payload: newPath,
export const requestCreateWorkspace = (path, force) => ({
type: CREATE_WORKSPACE_REQUESTED,
payload: { path, force },
});
export const requestSwitchWorkspace = opts => ({
type: SWITCH_WORKSPACE_REQUESTED,
payload: opts,
});
export const checkWorkspace = createAsyncAction({
eventName: 'checkWorkspace',
actionType: CHECK_WORKSPACE,
notify: false,
silent: true,
onComplete: (data, dispatch) => {
if (data.valid && data.libs) {
dispatch(openWorkspace(R.values(data.libs)));
return;
}
// ask user to define workspace
dispatch(setWorkspace(null));
},
onError: (data, dispatch) => {
// ask again
dispatch(setWorkspace(null));
},
export const createWorkspace = path => ({
type: CREATE_WORKSPACE,
payload: { path },
});
export const changeWorkspace = createAsyncAction({
eventName: 'changeWorkspace',
actionType: CHANGE_WORKSPACE,
messages: {
complete: 'Workspace has been changed!',
error: 'Failed to change workspace.',
},
silent: true,
onComplete: (data, dispatch) => {
dispatch(setWorkspace(data.path));
dispatch(openWorkspace(R.values(data.libs)));
},
onError: (data, dispatch) => {
// ask again
dispatch(setWorkspace(null));
},
export const switchWorkspace = path => ({
type: SWITCH_WORKSPACE,
payload: { path },
});
export default {
setWorkspace,
changeWorkspace,
};

View File

@@ -1,7 +1,9 @@
export const UPLOAD = 'UPLOAD';
export const UPLOAD_TO_ARDUINO = 'UPLOAD_TO_ARDUINO';
export const REQUEST_INSTALL_ARDUINO_IDE = 'REQUEST_INSTALL_ARDUINO_IDE';
export default {
UPLOAD,
UPLOAD_TO_ARDUINO,
REQUEST_INSTALL_ARDUINO_IDE,
};

View File

@@ -3,7 +3,7 @@ import { transpileForEspruino } from 'xod-js';
import { foldEither } from 'xod-func-tools';
import uploadToEspruino from 'xod-espruino-upload';
import { UPLOAD } from './actionTypes';
import { UPLOAD, REQUEST_INSTALL_ARDUINO_IDE } from './actionTypes';
const progressUpload = (dispatch, id) => (message, percentage) => dispatch(
client.progressProcess(
@@ -50,6 +50,11 @@ export const uploadToArduino = () => (dispatch) => {
};
};
export const requestInstallArduinoIDE = () => ({
type: REQUEST_INSTALL_ARDUINO_IDE,
payload: {},
});
export default {
upload,
uploadToArduino,

View File

@@ -20,6 +20,7 @@ import {
import * as actions from '../actions';
import * as uploadActions from '../../upload/actions';
import { getUploadProcess } from '../../upload/selectors';
import * as settingsActions from '../../settings/actions';
import { SAVE_PROJECT } from '../actionTypes';
import { UPLOAD, UPLOAD_TO_ARDUINO } from '../../upload/actionTypes';
import PopupSetWorkspace from '../../settings/components/PopupSetWorkspace';
@@ -93,10 +94,10 @@ class App extends client.App {
this.onArduinoPathChange = this.onArduinoPathChange.bind(this);
this.hideAllPopups = this.hideAllPopups.bind(this);
this.showPopupCreateProject = this.showPopupCreateProject.bind(this);
this.showPopupProjectSelection = this.showPopupProjectSelection.bind(this);
this.showPopupSetWorkspace = this.showPopupSetWorkspace.bind(this);
this.showPopupSetWorkspaceNotCancellable = this.showPopupSetWorkspaceNotCancellable.bind(this);
this.showPopupCreateProject = this.showPopupCreateProject.bind(this);
this.showArduinoIdeNotFoundPopup = this.showArduinoIdeNotFoundPopup.bind(this);
this.showCreateWorkspacePopup = this.showCreateWorkspacePopup.bind(this);
@@ -141,7 +142,6 @@ class App extends client.App {
}
onUpload() {
this.showUploadProgressPopup();
this.props.actions.upload();
}
@@ -149,7 +149,6 @@ class App extends client.App {
const { project, currentPatchPath } = this.props;
const proc = (processActions !== null) ? processActions : this.props.actions.uploadToArduino();
this.showUploadProgressPopup();
ipcRenderer.send(UPLOAD_TO_ARDUINO, {
pab,
project,
@@ -165,7 +164,6 @@ class App extends client.App {
}
if (payload.failure) {
if (payload.errorCode === ERROR_CODES.IDE_NOT_FOUND) {
this.hideAllPopups();
this.showArduinoIdeNotFoundPopup();
ipcRenderer.once('SET_ARDUINO_IDE',
(evt, response) => {
@@ -223,12 +221,12 @@ class App extends client.App {
}
onWorkspaceChange(val) {
this.hideAllPopups();
this.props.actions.switchWorkspace(val);
ipcRenderer.send(EVENTS.SWITCH_WORKSPACE, val);
}
onWorkspaceCreate(path) {
this.hideAllPopups();
this.props.actions.createWorkspace(path);
ipcRenderer.send(EVENTS.CREATE_WORKSPACE, path);
}
@@ -241,7 +239,6 @@ class App extends client.App {
}
onUploadPopupClose(id) {
this.hideAllPopups();
this.props.actions.deleteProcess(id, UPLOAD);
}
@@ -409,16 +406,8 @@ class App extends client.App {
Menu.setApplicationMenu(menu);
}
showUploadProgressPopup() {
this.props.actions.showPopup(client.POPUP_ID.UPLOADING);
}
showCodePopup() {
this.props.actions.showPopup(client.POPUP_ID.SHOWING_CODE, { code: this.state.code });
}
showPopupCreateProject() {
this.props.actions.showPopup(client.POPUP_ID.CREATING_PROJECT);
this.props.actions.requestCreateProject();
}
showPopupProjectSelection(projects) {
@@ -429,23 +418,23 @@ class App extends client.App {
status: REDUCER_STATUS.PENDING,
};
this.props.actions.showPopup(client.POPUP_ID.OPENING_PROJECT, data);
this.props.actions.requestOpenProject(data);
}
showArduinoIdeNotFoundPopup() {
this.props.actions.showPopup(client.POPUP_ID.ARDUINO_IDE_NOT_FOUND);
this.props.actions.requestInstallArduinoIDE();
}
showPopupSetWorkspace() {
this.props.actions.showPopup(client.POPUP_ID.SWITCHING_WORKSPACE, { disposable: false });
this.props.actions.requestSwitchWorkspace({ disposable: false });
}
showPopupSetWorkspaceNotCancellable() {
this.props.actions.showPopup(client.POPUP_ID.SWITCHING_WORKSPACE, { disposable: true });
this.props.actions.requestSwitchWorkspace({ disposable: true });
}
showCreateWorkspacePopup(path, force) {
this.props.actions.showPopup(client.POPUP_ID.CREATING_WORKSPACE, { path, force });
this.props.actions.requestCreateWorkspace(path, force);
}
hideAllPopups() {
@@ -562,6 +551,13 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators({
requestCreateProject: client.requestCreateProject,
requestOpenProject: client.requestOpenProject,
requestInstallArduinoIDE: uploadActions.requestInstallArduinoIDE,
requestSwitchWorkspace: settingsActions.requestSwitchWorkspace,
requestCreateWorkspace: settingsActions.requestCreateWorkspace,
createWorkspace: settingsActions.createWorkspace,
switchWorkspace: settingsActions.switchWorkspace,
createProject: client.createProject,
requestRenameProject: client.requestRenameProject,
setMode: client.setMode,

View File

@@ -1,3 +1,5 @@
export * from '../editor/actionTypes';
export * from '../project/actionTypes';
export * from '../messages/actionTypes';
export const SHOW_CODE = 'SHOW_CODE';

View File

@@ -2,6 +2,9 @@ import {
undoPatch,
redoPatch,
} from '../project/actions';
import {
SHOW_CODE,
} from './actionTypes';
import { getCurrentPatchPath } from '../editor/selectors';
export const undoCurrentPatch = () => (dispatch, getState) => {
@@ -14,6 +17,11 @@ export const redoCurrentPatch = () => (dispatch, getState) => {
if (currentPatchPath) dispatch(redoPatch(currentPatchPath));
};
export const showCode = code => ({
actionType: SHOW_CODE,
payload: { code },
});
export * from '../editor/actions';
export * from '../project/actions';
export * from '../messages/actions';

View File

@@ -69,8 +69,7 @@ export default class App extends React.Component {
this.props.actions.addError(error.message);
},
(code) => {
this.setState({ code });
this.showCodePopup();
this.props.actions.showCode(code);
},
eitherCode
);
@@ -87,5 +86,6 @@ App.propTypes = {
actions: React.PropTypes.shape({
addError: React.PropTypes.func.isRequired,
importProject: React.PropTypes.func.isRequired,
showCode: React.PropTypes.func.isRequired,
}),
};

View File

@@ -16,6 +16,8 @@ import * as EditorConstants from './editor/constants';
import * as UtilsConstants from './utils/constants';
import * as PopupConstants from './popups/constants';
import popupsReducer, { showOnlyPopup, hideOnePopup } from './popups/reducer';
import * as BrowserUtils from './utils/browser';
import * as MenuUtils from './utils/menu';
import sanctuaryPropType from './utils/sanctuaryPropType';
@@ -70,6 +72,8 @@ export { default as DevTools } from './core/containers/DevTools';
export { default as initialState } from './core/state';
export { default as popupsReducer, showOnlyPopup, hideOnePopup } from './popups/reducer';
export default Object.assign({
App,
Root,
@@ -86,6 +90,9 @@ export default Object.assign({
menu: MenuUtils,
sanctuaryPropType,
initialState,
popupsReducer,
showOnlyPopup,
hideOnePopup,
},
UtilsSelectors,
EditorSelectors,

View File

@@ -1,4 +1,3 @@
export const SHOW_POPUP = 'SHOW_POPUP';
export const HIDE_ALL_POPUPS = 'HIDE_ALL_POPUPS';
export default {};

View File

@@ -1,12 +1,4 @@
import { SHOW_POPUP, HIDE_ALL_POPUPS } from './actionTypes';
export const showPopup = (popupId, data = {}) => ({
type: SHOW_POPUP,
payload: {
id: popupId,
data,
},
});
import { HIDE_ALL_POPUPS } from './actionTypes';
export const hideAllPopups = () => ({
type: HIDE_ALL_POPUPS,

View File

@@ -9,7 +9,6 @@ import {
PROJECT_RENAME_REQUESTED,
} from '../projectBrowser/actionTypes';
import {
SHOW_POPUP,
HIDE_ALL_POPUPS,
} from './actionTypes';
@@ -17,8 +16,15 @@ import {
PATCH_ADD,
PATCH_DELETE,
PATCH_RENAME,
PROJECT_CREATE_REQUESTED,
PROJECT_OPEN_REQUESTED,
PROJECT_CREATE,
PROJECT_OPEN,
PROJECT_RENAME,
} from '../project/actionTypes';
import {
SHOW_CODE,
} from '../core/actionTypes';
// =============================================================================
//
@@ -46,7 +52,7 @@ const showPopup = R.curry(
const hideAll = R.map(hidePopup);
// :: State -> State
const hideOnePopup = R.curry(
export const hideOnePopup = R.curry(
(id, state) => R.over(
R.lensProp(id),
hidePopup,
@@ -64,7 +70,7 @@ const showOnePopup = R.curry(
);
// :: State -> State
const showOnlyPopup = R.curry(
export const showOnlyPopup = R.curry(
(id, data, state) => R.compose(
showOnePopup(id, data),
hideAll
@@ -80,34 +86,38 @@ const popupsReducer = (state = initialState, action) => {
switch (action.type) {
case PATCH_CREATE_REQUESTED:
return showOnlyPopup(POPUP_ID.CREATING_PATCH, {}, state);
case PATCH_RENAME_REQUESTED:
return showOnlyPopup(POPUP_ID.RENAMING_PATCH, {}, state);
case PATCH_DELETE_REQUESTED:
return showOnlyPopup(POPUP_ID.DELETING_PATCH, {}, state);
case PROJECT_CREATE_REQUESTED:
return showOnlyPopup(POPUP_ID.CREATING_PROJECT, {}, state);
case PROJECT_OPEN_REQUESTED:
return showOnlyPopup(POPUP_ID.OPENING_PROJECT, action.payload, state);
case PROJECT_RENAME_REQUESTED:
return showOnlyPopup(POPUP_ID.RENAMING_PROJECT, {}, state);
case SHOW_CODE:
return showOnlyPopup(POPUP_ID.SHOWING_CODE, action.payload, state);
case PATCH_ADD:
return hideOnePopup(POPUP_ID.CREATING_PATCH, state);
case PATCH_RENAME:
return hideOnePopup(POPUP_ID.RENAMING_PATCH, state);
case PATCH_DELETE:
return hideOnePopup(POPUP_ID.DELETING_PATCH, state);
case PROJECT_CREATE:
return hideOnePopup(POPUP_ID.CREATING_PROJECT, state);
case PROJECT_OPEN:
return hideOnePopup(POPUP_ID.OPENING_PROJECT, state);
case PROJECT_RENAME:
return hideOnePopup(POPUP_ID.RENAMING_PROJECT, state);
case HIDE_ALL_POPUPS:
return initialState;
case SHOW_POPUP:
return showOnlyPopup(action.payload.id, action.payload.data, state);
default:
return state;
}

View File

@@ -1,3 +1,6 @@
export const PROJECT_CREATE_REQUESTED = 'PROJECT_CREATE_REQUESTED';
export const PROJECT_OPEN_REQUESTED = 'PROJECT_OPEN_REQUESTED';
export const PROJECT_CREATE = 'PROJECT_CREATE';
export const PROJECT_RENAME = 'PROJECT_RENAME';
export const PROJECT_OPEN = 'PROJECT_OPEN';

View File

@@ -6,6 +6,16 @@ import * as ActionType from './actionTypes';
import { isPatchPathTaken } from './utils';
import { getCurrentPatchPath } from '../editor/selectors';
export const requestCreateProject = () => ({
type: ActionType.PROJECT_CREATE_REQUESTED,
payload: {},
});
export const requestOpenProject = data => ({
type: ActionType.PROJECT_OPEN_REQUESTED,
payload: data,
});
export const createProject = projectName => (dispatch) => {
if (!isValidIdentifier(projectName)) {
return dispatch(addError(PROJECT_BROWSER_ERRORS.INVALID_PROJECT_NAME));