Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

integrate api mode standalone #159

Merged
merged 16 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions frontend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,3 @@
REACT_APP_SERVER_HOST=localhost
REACT_APP_SERVER_PORT=8000
REACT_APP_SERVER_PROTO=http

# running mode (true: standalone mode, false: multi-user mode)
REACT_APP_IS_STANDALONE=true
38 changes: 34 additions & 4 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { FC } from "react"
import { FC, useEffect } from "react"
import { useDispatch, useSelector } from "react-redux"
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom"

import { SnackbarProvider, SnackbarKey, useSnackbar } from "notistack"

import Close from "@mui/icons-material/Close"
import IconButton from "@mui/material/IconButton"

import Loading from "components/common/Loading"
import Layout from "components/Layout"
import { IS_STANDALONE } from "const/Mode"
import { RETRY_WAIT } from "const/Mode"
import Account from "pages/Account"
import AccountDelete from "pages/AccountDelete"
import AccountManager from "pages/AccountManager"
Expand All @@ -16,9 +18,37 @@ import Login from "pages/Login"
import ResetPassword from "pages/ResetPassword"
import Workspaces from "pages/Workspace"
import Workspace from "pages/Workspace/Workspace"
import { getModeStandalone } from "store/slice/Standalone/StandaloneActions"
import {
selectLoadingMode,
selectModeStandalone,
} from "store/slice/Standalone/StandaloneSeclector"
import { AppDispatch } from "store/store"

const App: FC = () => {
return (
const dispatch = useDispatch<AppDispatch>()
const isStandalone = useSelector(selectModeStandalone)
const loading = useSelector(selectLoadingMode)
const getMode = () => {
dispatch(getModeStandalone())
.unwrap()
.catch(() => {
new Promise((resolve) =>
setTimeout(resolve, RETRY_WAIT),
).then(() => {
getMode()
})
})
}

useEffect(() => {
getMode()
//eslint-disable-next-line
}, [])

return loading ? (
<Loading />
) : (
<SnackbarProvider
maxSnack={5}
action={(snackbarKey) => (
Expand All @@ -27,7 +57,7 @@ const App: FC = () => {
>
<BrowserRouter>
<Layout>
{IS_STANDALONE ? (
{isStandalone ? (
<Routes>
<Route path="/" element={<Workspace />} />
<Route path="*" element={<Navigate replace to="/" />} />
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/api/modeStandalone/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import axios from "utils/axios"

export const getModeStandaloneApi = async (): Promise<boolean> => {
const res = await axios.get("/is_standalone")
return res.data
}
6 changes: 4 additions & 2 deletions frontend/src/components/Layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FC } from "react"
import { useSelector } from "react-redux"
import { useLocation } from "react-router-dom"

import MenuIcon from "@mui/icons-material/Menu"
Expand All @@ -14,12 +15,13 @@ import Tooltips from "components/Layout/Tooltips"
import Logo from "components/logo.png"
import WorkspaceTabs from "components/Workspace/WorkspaceTabs"
import { APP_BAR_HEIGHT } from "const/Layout"
import { IS_STANDALONE } from "const/Mode"
import { selectModeStandalone } from "store/slice/Standalone/StandaloneSeclector"

const Header: FC<{
handleDrawerOpen: () => void
}> = ({ handleDrawerOpen }) => {
return IS_STANDALONE ? (
const isStandalone = useSelector(selectModeStandalone)
return isStandalone ? (
<StandaloneHeader />
) : (
<MultiUserHeader handleDrawerOpen={handleDrawerOpen} />
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Loading from "components/common/Loading"
import Header from "components/Layout/Header"
import LeftMenu from "components/Layout/LeftMenu"
import { APP_BAR_HEIGHT } from "const/Layout"
import { IS_STANDALONE } from "const/Mode"
import { selectModeStandalone } from "store/slice/Standalone/StandaloneSeclector"
import { getMe } from "store/slice/User/UserActions"
import { selectCurrentUser } from "store/slice/User/UserSelector"
import { AppDispatch } from "store/store"
Expand All @@ -22,13 +22,14 @@ const Layout = ({ children }: { children?: ReactNode }) => {
const location = useLocation()
const navigate = useNavigate()
const dispatch = useDispatch<AppDispatch>()
const isStandalone = useSelector(selectModeStandalone)

const [loading, setLoadingAuth] = useState(
!IS_STANDALONE && authRequiredPathRegex.test(location.pathname),
!isStandalone && authRequiredPathRegex.test(location.pathname),
)

useEffect(() => {
!IS_STANDALONE &&
!isStandalone &&
authRequiredPathRegex.test(location.pathname) &&
checkAuth()
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down Expand Up @@ -57,7 +58,7 @@ const Layout = ({ children }: { children?: ReactNode }) => {

if (loading) return <Loading />

return IS_STANDALONE || authRequiredPathRegex.test(location.pathname) ? (
return isStandalone || authRequiredPathRegex.test(location.pathname) ? (
<AuthedLayout>{children}</AuthedLayout>
) : (
<UnauthedLayout>{children}</UnauthedLayout>
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/Workspace/ToolBar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { memo } from "react"
import { useSelector } from "react-redux"
import { useNavigate } from "react-router-dom"

import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"
Expand All @@ -10,11 +11,12 @@ import { ImportWorkflowConfigButton } from "components/Workspace/FlowChart/Butto
import { NWBSettingButton } from "components/Workspace/FlowChart/Buttons/NWB"
import { RunButtons } from "components/Workspace/FlowChart/Buttons/RunButtons"
import { SnakemakeButton } from "components/Workspace/FlowChart/Buttons/Snakemake"
import { IS_STANDALONE } from "const/Mode"
import { UseRunPipelineReturnType } from "store/slice/Pipeline/PipelineHook"
import { selectModeStandalone } from "store/slice/Standalone/StandaloneSeclector"

export const ToolBar = memo(function ToolBar(props: UseRunPipelineReturnType) {
const navigate = useNavigate()
const isStandalone = useSelector(selectModeStandalone)
return (
<Box
style={{
Expand All @@ -30,7 +32,7 @@ export const ToolBar = memo(function ToolBar(props: UseRunPipelineReturnType) {
fontSize: "1rem",
}}
>
{!IS_STANDALONE && (
{!isStandalone && (
<Button onClick={() => navigate("/console/workspaces")}>
<ArrowBackIosIcon />
Workspaces
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/common/CurrentPipelineInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { useSelector } from "react-redux"

import { Typography, Grid, Popover } from "@mui/material"

import { IS_STANDALONE } from "const/Mode"
import {
selectCurrentPipelineName,
selectPipelineLatestUid,
} from "store/slice/Pipeline/PipelineSelectors"
import { selectModeStandalone } from "store/slice/Standalone/StandaloneSeclector"
import {
selectCurrentWorkspaceId,
selectCurrentWorkspaceName,
Expand All @@ -18,12 +18,13 @@ export const CurrentPipelineInfo: FC = () => {
const workspaceName = useSelector(selectCurrentWorkspaceName)
const workflowId = useSelector(selectPipelineLatestUid)
const workflowName = useSelector(selectCurrentPipelineName)
const isStandalone = useSelector(selectModeStandalone)

return (
<>
{workflowId && (
<>
{!IS_STANDALONE && (
{!isStandalone && (
<>
<Typography variant="body2" color="textSecondary">
WORKSPACE
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/const/Mode.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const IS_STANDALONE = !(process.env.REACT_APP_IS_STANDALONE === "false")
export const RETRY_WAIT = 5000
export const STANDALONE_WORKSPACE_ID = 1
15 changes: 12 additions & 3 deletions frontend/src/store/slice/Pipeline/PipelineHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useSnackbar, VariantType } from "notistack"

import { isRejected } from "@reduxjs/toolkit"

import { IS_STANDALONE, STANDALONE_WORKSPACE_ID } from "const/Mode"
import { STANDALONE_WORKSPACE_ID } from "const/Mode"
import { selectAlgorithmNodeNotExist } from "store/slice/AlgorithmNode/AlgorithmNodeSelectors"
import { getExperiments } from "store/slice/Experiments/ExperimentsActions"
import { clearExperiments } from "store/slice/Experiments/ExperimentsSlice"
Expand All @@ -25,6 +25,7 @@ import {
} from "store/slice/Pipeline/PipelineSelectors"
import { RUN_STATUS } from "store/slice/Pipeline/PipelineType"
import { selectRunPostData } from "store/slice/Run/RunSelectors"
import { selectModeStandalone } from "store/slice/Standalone/StandaloneSeclector"
import { fetchWorkflow } from "store/slice/Workflow/WorkflowActions"
import { getWorkspace } from "store/slice/Workspace/WorkspaceActions"
import { selectIsWorkspaceOwner } from "store/slice/Workspace/WorkspaceSelector"
Expand All @@ -42,14 +43,15 @@ export type UseRunPipelineReturnType = ReturnType<typeof useRunPipeline>
export function useRunPipeline() {
const dispatch = useDispatch<AppDispatch>()
const appDispatch: AppDispatch = useDispatch()
const isStandalone = useSelector(selectModeStandalone)
const navigate = useNavigate()
const location = useLocation()

const { workspaceId } = useParams<{ workspaceId: string }>()
const _workspaceId = Number(workspaceId)

useEffect(() => {
if (IS_STANDALONE) {
if (isStandalone) {
dispatch(setCurrentWorkspace(STANDALONE_WORKSPACE_ID))
dispatch(fetchWorkflow(STANDALONE_WORKSPACE_ID))
} else {
Expand All @@ -68,7 +70,14 @@ export function useRunPipeline() {
dispatch(clearExperiments())
dispatch(clearCurrentWorkspace())
}
}, [dispatch, appDispatch, navigate, _workspaceId, location.state])
}, [
dispatch,
appDispatch,
navigate,
_workspaceId,
location.state,
isStandalone,
])

const uid = useSelector(selectPipelineLatestUid)
const isCanceled = useSelector(selectPipelineIsCanceled)
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/store/slice/Standalone/StandaloneActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createAsyncThunk } from "@reduxjs/toolkit"

import { getModeStandaloneApi } from "api/modeStandalone"

export const getModeStandalone = createAsyncThunk<boolean>(
"/getModeStandalone",
async () => {
const response = await getModeStandaloneApi()
return response
},
)
4 changes: 4 additions & 0 deletions frontend/src/store/slice/Standalone/StandaloneSeclector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { RootState } from "store/store"

export const selectModeStandalone = (state: RootState) => state.mode.mode
export const selectLoadingMode = (state: RootState) => state.mode.loading
27 changes: 27 additions & 0 deletions frontend/src/store/slice/Standalone/StandaloneSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { createSlice } from "@reduxjs/toolkit"

import { getModeStandalone } from "store/slice/Standalone/StandaloneActions"
import { ModeType } from "store/slice/Standalone/StandaloneType"

const initialState: ModeType = {
mode: undefined,
loading: true,
}

export const modeStandaloneSlice = createSlice({
name: "modeStandalone",
initialState,
reducers: {},
extraReducers(build) {
build
.addCase(getModeStandalone.pending, (state) => {
state.loading = true
})
.addCase(getModeStandalone.fulfilled, (state, action) => {
state.mode = action.payload
state.loading = false
})
},
})

export default modeStandaloneSlice.reducer
4 changes: 4 additions & 0 deletions frontend/src/store/slice/Standalone/StandaloneType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type ModeType = {
mode?: boolean
loading: boolean
}
4 changes: 2 additions & 2 deletions frontend/src/store/slice/Workspace/WorkspaceSelector.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IS_STANDALONE } from "const/Mode"
import { selectModeStandalone } from "store/slice/Standalone/StandaloneSeclector"
import { RootState } from "store/store"

export const selectWorkspace = (state: RootState) => state.workspace
Expand Down Expand Up @@ -27,6 +27,6 @@ export const selectIsLoadingWorkspaceList = (state: RootState) =>
state.workspace.loading

export const selectIsWorkspaceOwner = (state: RootState) =>
IS_STANDALONE
selectModeStandalone(state)
? true
: state.workspace.currentWorkspace.ownerId === state.user.currentUser?.id
1 change: 1 addition & 0 deletions frontend/src/store/slice/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export { default as hdf5Reducer } from "./HDF5/HDF5Slice"
export { default as experimentsReducer } from "./Experiments/ExperimentsSlice"
export { default as workspaceReducer } from "./Workspace/WorkspaceSlice"
export { default as userReducer } from "./User/UserSlice"
export { default as modeStandalone } from "./Standalone/StandaloneSlice"
2 changes: 2 additions & 0 deletions frontend/src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
experimentsReducer,
workspaceReducer,
userReducer,
modeStandalone,
} from "store/slice"

export const rootReducer = combineReducers({
Expand All @@ -43,6 +44,7 @@ export const rootReducer = combineReducers({
experiments: experimentsReducer,
workspace: workspaceReducer,
user: userReducer,
mode: modeStandalone,
})

export const store = configureStore({
Expand Down
8 changes: 7 additions & 1 deletion studio/__main_unit__.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,13 @@ def skip_dependencies():

@app.on_event("startup")
async def startup_event():
logging.info('"Studio" application startup complete.')
mode = "standalone" if MODE.IS_STANDALONE else "multiuser"
logging.info(f'"Studio" application startup complete. [mode: {mode}]')


@app.get("/is_standalone", response_model=bool, tags=["others"])
async def is_standalone():
return MODE.IS_STANDALONE


@app.get("/")
Expand Down