From 9a57bab4e4f59a84c0c34a69edf860cfb4d7d9e3 Mon Sep 17 00:00:00 2001 From: gbischof Date: Fri, 11 Feb 2022 13:39:09 -0500 Subject: [PATCH 1/5] add a drawer for the console output --- src/App.tsx | 42 +++++++++++++++++------ src/ConsoleDrawer.tsx | 80 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 src/ConsoleDrawer.tsx diff --git a/src/App.tsx b/src/App.tsx index c51bd24..350b933 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import { HistoricalPlanList } from './HistoricalPlanList'; import { CurrentPlan } from './CurrentPlan'; import { AppBar, Grid, IconButton, Popover, Toolbar } from '@material-ui/core'; import { PlanDrawer } from './PlanDrawer'; +import { ConsoleDrawer } from './ConsoleDrawer'; import { PlanFormContainer } from './PlanFormContainer'; import nsls2Background from "./assets/nsls2_background.png"; import logo from './assets/bluesky-logo.svg'; @@ -93,7 +94,8 @@ interface IState { queue: string; onQueueChange: (queue: string) => void; files: File[]; - drawerOpen: boolean; + actionDrawerOpen: boolean; + consoleDrawerOpen: boolean; planFormVisible: boolean; } @@ -145,7 +147,8 @@ class App extends React.Component { queue: "Start", onQueueChange: this.handleQueueChange, files: [], - drawerOpen: false, + actionDrawerOpen: false, + consoleDrawerOpen: false, planFormVisible: false, }; @@ -166,9 +169,12 @@ class App extends React.Component { - + Actions + + Console + logo { - - + { private handleSelectPlan = (selectedPlan: string) => { - this.closeDrawer() + this.closeActionDrawer() this.showPlanForm() this.setState({ selectedPlan: selectedPlan }); // Check this line this.setState({ editItemUid: ""}); @@ -256,15 +262,31 @@ class App extends React.Component { }); } - private toggleDrawer(){ + private toggleActionDrawer(){ + this.setState({ + actionDrawerOpen: !this.state.actionDrawerOpen + }) + if (this.state.consoleDrawerOpen){ + this.setState({ + consoleDrawerOpen: false + }) + } + } + + private toggleConsoleDrawer(){ this.setState({ - drawerOpen: !this.state.drawerOpen + consoleDrawerOpen: !this.state.consoleDrawerOpen }) + if (this.state.actionDrawerOpen){ + this.setState({ + actionDrawerOpen: false + }) + } } - private closeDrawer(){ + private closeActionDrawer(){ this.setState({ - drawerOpen: false + actionDrawerOpen: false }) } diff --git a/src/ConsoleDrawer.tsx b/src/ConsoleDrawer.tsx new file mode 100644 index 0000000..3533f97 --- /dev/null +++ b/src/ConsoleDrawer.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import Drawer from '@material-ui/core/Drawer'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; +import { addQueueStop, IAllowedPlans, submitExcel } from './queueserver'; +import { Avatar, Box, Button, ListItemSecondaryAction, MenuItem, Typography } from '@material-ui/core'; +import { Star } from '@material-ui/icons'; +import { BulkAdd } from './bulk'; + +type IProps = { + open: boolean +}; + +type IState = { + open: boolean; +} + +const styles = (theme: { zIndex: { drawer: number; }; }) => ({ + appBar: { + // Make the app bar z-index always one more than the drawer z-index + zIndex: theme.zIndex.drawer + 1, + }, +}); + +export class ConsoleDrawer extends React.Component{ + + constructor(props: IProps) { + super(props); + this.state = { + open: true } + } + + render() { + return ( +
+ + +
+ + + + Queue Actions + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ ); + } +} From 12372d0aa59873513512d1f7c64295bc6e27b8d3 Mon Sep 17 00:00:00 2001 From: gbischof Date: Fri, 11 Feb 2022 14:11:14 -0500 Subject: [PATCH 2/5] add redux-websocket --- package.json | 1 + src/store.tsx | 21 +++++++++++++++++++++ yarn.lock | 9 ++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index bcf9fa7..7ab9a64 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.0.1", "private": true, "dependencies": { + "@giantmachines/redux-websocket": "^1.5.1", "@material-ui/core": "latest", "@material-ui/icons": "latest", "@types/react": "latest", diff --git a/src/store.tsx b/src/store.tsx index 51b9945..8153a68 100644 --- a/src/store.tsx +++ b/src/store.tsx @@ -30,6 +30,27 @@ const rootReducer = combineReducers({ status: statusReducer, }) +const createMySocketMiddleware = (url: any) => { + return storeAPI => { + let socket = createMyWebsocket(url); + + socket.on("message", (message: any) => { + storeAPI.dispatch({ + type : "SOCKET_MESSAGE_RECEIVED", + payload : message + }); + }); + + return next => action => { + if(action.type == "SEND_WEBSOCKET_MESSAGE") { + socket.send(action.payload); + return; + } + return next(action); + } + } +} + export default function configureStore(): Store { const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore(rootReducer, undefined, composeEnhancers(applyMiddleware(thunk))); diff --git a/yarn.lock b/yarn.lock index ed9429a..9655ebd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1084,6 +1084,13 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@giantmachines/redux-websocket@^1.5.1": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@giantmachines/redux-websocket/-/redux-websocket-1.5.1.tgz#90a335f531d31a54e1217d051014cde0f69dd28b" + integrity sha512-s/vyWsfjyCK7lRWgRk4gjV1mg0E6kjxcKE1y4wUrE4kBf3Vvtj64g/fIe1w6Jw5UaoABrEjm4XxQVOXOAaOSAg== + dependencies: + redux "~4" + "@humanwhocodes/config-array@^0.9.2": version "0.9.2" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz" @@ -7292,7 +7299,7 @@ redux-thunk@*, redux-thunk@^2.3.0: resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.1.tgz" integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q== -redux@^4.0.0, redux@^4.0.5: +redux@^4.0.0, redux@^4.0.5, redux@~4: version "4.1.2" resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz" integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== From 5d51f279569f20da2059f638ba5baf51e7b1c75d Mon Sep 17 00:00:00 2001 From: gbischof Date: Fri, 11 Feb 2022 14:28:53 -0500 Subject: [PATCH 3/5] I think the websocket is setup now --- src/index.tsx | 4 +++- src/store.tsx | 26 ++++---------------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 0c7bd24..0c3f457 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -9,9 +9,9 @@ import { IApplicationState } from './store' import theme from './theme'; import { Routes, Route } from 'react-router-dom'; import { BrowserRouter as Router } from 'react-router-dom'; - import App from './App' import UserPage from './user' +import { connect } from '@giantmachines/redux-websocket'; interface IProps { @@ -31,6 +31,8 @@ const Root: React.FunctionComponent = props => { }; export const store = configureStore(); +// Connect websocket +store.dispatch(connect(process.env.REACT_APP_HTTP_SERVER || 'http://localhost:60610' + 'stream_console_output')); ReactDOM.render( diff --git a/src/store.tsx b/src/store.tsx index 8153a68..b054e8d 100644 --- a/src/store.tsx +++ b/src/store.tsx @@ -5,6 +5,8 @@ import { planObjectsReducer, planReducer, planSubmitReducer, import { IStatus, IPlanState, IPlanObjectsState, IPlanSubmitState, IPlanModifyState, IAllowedPlansState, IHistoricalPlansState} from "./queueserver" import { userReducer } from "./userreducers" import { IUserState } from "./facility" +import reduxWebsocket from '@giantmachines/redux-websocket'; +import { connect } from '@giantmachines/redux-websocket'; export interface IApplicationState { plan: IPlanState; @@ -30,29 +32,9 @@ const rootReducer = combineReducers({ status: statusReducer, }) -const createMySocketMiddleware = (url: any) => { - return storeAPI => { - let socket = createMyWebsocket(url); - - socket.on("message", (message: any) => { - storeAPI.dispatch({ - type : "SOCKET_MESSAGE_RECEIVED", - payload : message - }); - }); - - return next => action => { - if(action.type == "SEND_WEBSOCKET_MESSAGE") { - socket.send(action.payload); - return; - } - return next(action); - } - } -} - export default function configureStore(): Store { const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; - const store = createStore(rootReducer, undefined, composeEnhancers(applyMiddleware(thunk))); + const reduxWebsocketMiddleware = reduxWebsocket(); + const store = createStore(rootReducer, undefined, composeEnhancers(applyMiddleware(thunk, reduxWebsocketMiddleware))); return store; } \ No newline at end of file From fc30612a20fdb11d785d6ccee3fffae07c5014a6 Mon Sep 17 00:00:00 2001 From: gbischof Date: Wed, 16 Feb 2022 15:54:08 -0500 Subject: [PATCH 4/5] setup most of the redux part for the websocket --- src/HistoricalPlanList.tsx | 1 - src/index.tsx | 2 +- src/planreducers.ts | 26 ++++++++++++++++++++++++- src/queueserver.ts | 40 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/HistoricalPlanList.tsx b/src/HistoricalPlanList.tsx index 5741d2d..118f615 100644 --- a/src/HistoricalPlanList.tsx +++ b/src/HistoricalPlanList.tsx @@ -71,7 +71,6 @@ export class HistoricalPlanList extends React.Component run_uids: {JSON.stringify(planObject.result.run_uids)} - diff --git a/src/index.tsx b/src/index.tsx index 0c3f457..4c1eb0c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -32,7 +32,7 @@ const Root: React.FunctionComponent = props => { export const store = configureStore(); // Connect websocket -store.dispatch(connect(process.env.REACT_APP_HTTP_SERVER || 'http://localhost:60610' + 'stream_console_output')); +store.dispatch(connect(process.env.REACT_APP_HTTP_SERVER || 'http://localhost:60610/' + 'stream_console_output')); ReactDOM.render( diff --git a/src/planreducers.ts b/src/planreducers.ts index 9fb841b..a6f68b7 100644 --- a/src/planreducers.ts +++ b/src/planreducers.ts @@ -5,7 +5,8 @@ import { IPlanState, IPlanObjectsState, IAllowedPlansState, AllowedPlansActions, AllowedPlansActionTypes, IAllowedPlans, IHistoricalPlansState, HistoricalPlansActions, - HistoricalPlansActionTypes, IStatus } from "./queueserver"; + HistoricalPlansActionTypes, IStatus, + IConsoleOutput, ConsoleOutputActions, ConsoleOutputActionTypes } from "./queueserver"; import { getQueuedPlans, getHistoricalPlans } from './planactions'; import { store } from "./index" @@ -290,3 +291,26 @@ export const queueModifyReducer: Reducer = ( } } }; + + + +const initialConsoleOutputState: IConsoleOutput = { + output: "" +}; + +export const consoleOutputReducer: Reducer = ( + state = initialConsoleOutputState, + action +) => { + switch (action.type) { + case ConsoleOutputActionTypes.OPEN: { + return state; + } + case ConsoleOutputActionTypes.CLOSED: { + return state; + } + default: { + return state; + } + } +}; \ No newline at end of file diff --git a/src/queueserver.ts b/src/queueserver.ts index 75938a5..4c03073 100644 --- a/src/queueserver.ts +++ b/src/queueserver.ts @@ -239,6 +239,42 @@ export type PlanActions = | IPlanModifyQueueAction | IPlanModifyQueueLoadingAction + +export enum ConsoleOutputActionTypes { + WEBSOCKETCONNECT = "REDUX_WEBSOCKET::WEBSOCKET_CONNECT", + ERROR = "REDUX_WEBSOCKET::ERROR", + OPEN = "REDUX_WEBSOCKET::OPEN", + CLOSED = "REDUX_WEBSOCKET::CLOSED", + MESSAGE = "REDUX_WEBSOCKET::MESSAGE" +} + +export interface IConsoleOutputWebsocketConnectAction { + type: ConsoleOutputActionTypes.WEBSOCKETCONNECT +} + +export interface IConsoleOutputErrorAction { + type: ConsoleOutputActionTypes.ERROR +} + +export interface IConsoleOutputOpenAction { + type: ConsoleOutputActionTypes.OPEN +} + +export interface IConsoleOutputClosedAction { + type: ConsoleOutputActionTypes.CLOSED +} + +export interface IConsoleOutputMessageAction { + type: ConsoleOutputActionTypes.MESSAGE +} + +export type ConsoleOutputActions = + | IConsoleOutputErrorAction + | IConsoleOutputMessageAction + | IConsoleOutputOpenAction + | IConsoleOutputClosedAction + | IConsoleOutputWebsocketConnectAction + export interface IPlanState { readonly plan: IPlan; readonly planLoading: boolean; @@ -271,6 +307,10 @@ export interface IStatus { task_results_uid: string } +export interface IConsoleOutput { + output: string +} + export const getStatus = async(): Promise => { const res = await axiosInstance.get('/status'); return res.data; From f4602c9531d491027f96f7e4bc43a568642c443d Mon Sep 17 00:00:00 2001 From: gbischof Date: Thu, 17 Feb 2022 15:47:27 -0500 Subject: [PATCH 5/5] seems to be working, but I think server side needs to be updated --- src/index.tsx | 2 +- src/planreducers.ts | 8 +++++++- src/queueserver.ts | 9 ++++----- src/store.tsx | 8 +++++--- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 4c1eb0c..27b1288 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -32,7 +32,7 @@ const Root: React.FunctionComponent = props => { export const store = configureStore(); // Connect websocket -store.dispatch(connect(process.env.REACT_APP_HTTP_SERVER || 'http://localhost:60610/' + 'stream_console_output')); +store.dispatch(connect(process.env.REACT_APP_HTTP_SERVER || 'ws://localhost:60610/' + 'stream_console_output')); ReactDOM.render( diff --git a/src/planreducers.ts b/src/planreducers.ts index a6f68b7..8f35c56 100644 --- a/src/planreducers.ts +++ b/src/planreducers.ts @@ -304,9 +304,15 @@ export const consoleOutputReducer: Reducer ) => { switch (action.type) { case ConsoleOutputActionTypes.OPEN: { + console.log("OPEN REDUCER", action) return state; } - case ConsoleOutputActionTypes.CLOSED: { + case ConsoleOutputActionTypes.CONNECT: { + console.log("CONNECT REDUCER", action) + return state; + } + case ConsoleOutputActionTypes.ERROR: { + console.log("ERROR REDUCER", action) return state; } default: { diff --git a/src/queueserver.ts b/src/queueserver.ts index 4c03073..c1920a2 100644 --- a/src/queueserver.ts +++ b/src/queueserver.ts @@ -239,17 +239,16 @@ export type PlanActions = | IPlanModifyQueueAction | IPlanModifyQueueLoadingAction - export enum ConsoleOutputActionTypes { - WEBSOCKETCONNECT = "REDUX_WEBSOCKET::WEBSOCKET_CONNECT", + CONNECT = "REDUX_WEBSOCKET::CONNECT", ERROR = "REDUX_WEBSOCKET::ERROR", OPEN = "REDUX_WEBSOCKET::OPEN", CLOSED = "REDUX_WEBSOCKET::CLOSED", MESSAGE = "REDUX_WEBSOCKET::MESSAGE" } -export interface IConsoleOutputWebsocketConnectAction { - type: ConsoleOutputActionTypes.WEBSOCKETCONNECT +export interface IConsoleOutputConnectAction { + type: ConsoleOutputActionTypes.CONNECT } export interface IConsoleOutputErrorAction { @@ -273,7 +272,7 @@ export type ConsoleOutputActions = | IConsoleOutputMessageAction | IConsoleOutputOpenAction | IConsoleOutputClosedAction - | IConsoleOutputWebsocketConnectAction + | IConsoleOutputConnectAction export interface IPlanState { readonly plan: IPlan; diff --git a/src/store.tsx b/src/store.tsx index b054e8d..d3b99af 100644 --- a/src/store.tsx +++ b/src/store.tsx @@ -1,12 +1,12 @@ import { applyMiddleware, combineReducers, createStore, Store, compose } from "redux" import thunk from "redux-thunk" import { planObjectsReducer, planReducer, planSubmitReducer, - environmentModifyReducer, queueModifyReducer, allowedPlansReducer, historicalPlansReducer, statusReducer } from "./planreducers" -import { IStatus, IPlanState, IPlanObjectsState, IPlanSubmitState, IPlanModifyState, IAllowedPlansState, IHistoricalPlansState} from "./queueserver" + environmentModifyReducer, queueModifyReducer, allowedPlansReducer, historicalPlansReducer, statusReducer, consoleOutputReducer } from "./planreducers" +import { IStatus, IPlanState, IPlanObjectsState, IPlanSubmitState, IPlanModifyState, IAllowedPlansState, IHistoricalPlansState, IConsoleOutput} from "./queueserver" import { userReducer } from "./userreducers" import { IUserState } from "./facility" import reduxWebsocket from '@giantmachines/redux-websocket'; -import { connect } from '@giantmachines/redux-websocket'; + export interface IApplicationState { plan: IPlanState; @@ -18,6 +18,7 @@ export interface IApplicationState { queue: IPlanModifyState; user: IUserState; status: IStatus; + output: IConsoleOutput; } const rootReducer = combineReducers({ @@ -30,6 +31,7 @@ const rootReducer = combineReducers({ queue: queueModifyReducer, user: userReducer, status: statusReducer, + output: consoleOutputReducer }) export default function configureStore(): Store {