diff --git a/package.json b/package.json index 3bf54e71e..417cd50fb 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "tslint": "tsc", "all": "eslint './src/**/*.ts*' & react-scripts test --all & tsc" }, + "homepage": "/login", "browserslist": { "production": [ ">0.2%", diff --git a/src/constants/routes.ts b/src/constants/routes.ts index e44552df1..2d0ecf0fa 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -1,3 +1,3 @@ import { routePaths } from '../routes/routePaths'; export const loggedOutRoute = routePaths.login; -export const loggedInRoute = routePaths.home; +export const loggedInRoute = routePaths.home(':string'); diff --git a/src/redux/reducers/projectsReducer.ts b/src/redux/reducers/projectsReducer.ts index aff7938ff..b9af9aec7 100644 --- a/src/redux/reducers/projectsReducer.ts +++ b/src/redux/reducers/projectsReducer.ts @@ -1,3 +1,4 @@ +import { DEFAULT_PROJECT_NAME } from '../../constants'; import { camelCaseArray } from '../../utils/camelCase'; import { projectActionTypes } from '../actionTypes'; import { byKeyInsert, idsInsert } from './reducerHelpers'; @@ -7,7 +8,7 @@ export interface State { byId: Record; myProjectIds: TId[]; selectedProject: string; - projectStats: any + projectStats: any; } type ProjectsPayload = Projects[]; @@ -25,20 +26,20 @@ export const initialState: State = { byId: {}, myProjectIds: [], selectedProject: '', - projectStats: {} + projectStats: {}, }; const newState = ( state: State, projects: Projects[], defaultSelectedProject?: string, - projectStats?: object + projectStats?: object, ): State => ({ ...state, ids: idsInsert(state.ids, projects), byId: byKeyInsert(state.byId, projects), selectedProject: defaultSelectedProject as string, - projectStats: projectStats + projectStats: projectStats, }); const projectsReducer = ( @@ -55,7 +56,7 @@ const projectsReducer = ( (project: Projects) => project.id, ); if (action.requestParams.selectDefault === undefined) { - const defaultSelectedProject = projects[0].name; + const defaultSelectedProject = DEFAULT_PROJECT_NAME; return { ...newState(state, projects, defaultSelectedProject), myProjectIds, @@ -73,22 +74,21 @@ const projectsReducer = ( const myProjectIds: TId[] = allProjects.map( (project: Projects) => project.id, ); - + return { ...newState(state, allProjects, seletecdProject), myProjectIds, }; } - case projectActionTypes.getMyProjectStats.success: { // const { projectStats } = action.payload as any; const projectStats = action.payload; - - return { ...newState(state, projectStats) }; + + return { ...newState(state, projectStats) }; } - default: + default: return state; } }; diff --git a/src/routes/appRoutesConfig.tsx b/src/routes/appRoutesConfig.tsx index f302f23db..dbf1ebb2b 100644 --- a/src/routes/appRoutesConfig.tsx +++ b/src/routes/appRoutesConfig.tsx @@ -53,7 +53,7 @@ const routes = [ }, }, { - path: routePaths.home, + path: routePaths.home(':string'), Component: Home, visibility: { authentication: RouteVisibilityAuthentication.authenticatedOnly, diff --git a/src/routes/routePaths.tsx b/src/routes/routePaths.tsx index 06bb719a1..27e753edf 100644 --- a/src/routes/routePaths.tsx +++ b/src/routes/routePaths.tsx @@ -7,12 +7,11 @@ export const routePaths = { signup: '/signup', userEmail: `/user-email`, forgot: '/forgot-password', - home: '/', + home: (project: string): string => `/projects/${project}`, pipelines: { base: `/pipelines`, list: (project: string): string => `/projects/${project}/pipelines/list`, - allRuns: (project: string): string => - `/projects/${project}/pipelines/all-runs`, + allRuns: (project: string): string => `/projects/${project}/all-runs`, }, pipeline: { base: (id: TId): string => `/pipelines/${id}`, @@ -63,11 +62,11 @@ export const routePaths = { `/components/${pipelineId}/runs/${id}/tensorboard`, }, run: { - base: (runId: TId): string => `/runs/${runId}`, + base: (runId: TId): string => `/all-runs/${runId}`, statistics: (project: string, id: TId, type?: string): string => - `/projects/${project}/runs/${id}/dag`, + `/projects/${project}/all-runs/${id}/dag`, results: (project: string, runId: TId): string => - `/projects/${project}/runs/${runId}/configuration`, + `/projects/${project}/all-runs/${runId}/configuration`, tensorboard: (runId: TId): string => `/runs/${runId}/tensorboard`, }, }, diff --git a/src/routes/utils/replaceRouteIfNeeded.ts b/src/routes/utils/replaceRouteIfNeeded.ts index 81f727a86..f7aa4b471 100644 --- a/src/routes/utils/replaceRouteIfNeeded.ts +++ b/src/routes/utils/replaceRouteIfNeeded.ts @@ -1,83 +1,9 @@ -// import { RouteVisibilityAuthentication } from '../RouteVisibility'; -// import { loggedOutRoute, loggedInRoute } from '../../constants'; - -// const isUnauthenticatedOrMissingRoute = ( -// currentLocation: any | undefined, -// ): boolean => -// currentLocation -// ? currentLocation.visibility && -// currentLocation.visibility.authentication === -// RouteVisibilityAuthentication.unauthenticatedOnly -// : false; - -// const isAuthenticatedOrMissingRoute = ( -// currentLocation: any | undefined, -// ): boolean => -// currentLocation -// ? currentLocation.visibility && -// currentLocation.visibility.authentication === -// RouteVisibilityAuthentication.authenticatedOnly -// : false; - -// let timeout = null as any; - -// export const replaceRouteIfNeeded = ({ -// user, -// isAuthenticated, -// currentLocation, -// replaceRoute, -// routeFromSearchParam, -// }: { -// user: any; -// isAuthenticated: any; -// currentLocation: any | undefined; -// replaceRoute: (arg1: string) => void; -// routeFromSearchParam: null | string; -// }): void => { -// clearTimeout(timeout); - -// const routeToReplace = () => { -// return isAuthenticated ? loggedInRoute : loggedOutRoute; -// }; -// const replaceToLoggedInRoute = -// isAuthenticated && isUnauthenticatedOrMissingRoute(currentLocation); - -// const replaceToLoggedOutRoute = -// !isAuthenticated && isAuthenticatedOrMissingRoute(currentLocation); - -// const replaceToLoggedInRouteForEmailOptedIn = -// isAuthenticated && -// user?.emailOptedIn === null && -// currentLocation?.path !== `/user-email`; -// const shouldReplaceRoute = -// replaceToLoggedInRoute || -// replaceToLoggedOutRoute || -// replaceToLoggedInRouteForEmailOptedIn; - -// if (shouldReplaceRoute) { -// timeout = setTimeout(() => { -// let route = routeToReplace(); -// if (user?.emailOptedIn === null) { -// route = `/user-email`; -// } -// console.log(currentLocation, 'currentLocation', routeFromSearchParam); - -// if (replaceToLoggedOutRoute && currentLocation) { -// route = `${route}?route=${currentLocation.path}`; -// } else if (replaceToLoggedInRoute && routeFromSearchParam) { -// route = routeFromSearchParam; -// } - -// replaceRoute(route); -// }, 0); -// } -// }; - import { RouteInterface, RouteVisibilityAuthentication, } from '../RouteVisibility'; -import { loggedOutRoute } from '../../constants'; +import { loggedOutRoute, DEFAULT_PROJECT_NAME } from '../../constants'; +import { routePaths } from '../routePaths'; const isUnauthenticatedOrMissingRoute = ( currentLocation: RouteInterface | undefined, @@ -117,7 +43,12 @@ export const replaceRouteIfNeeded = ({ clearTimeout(timeout); const routeToReplace = () => { - const logRoute = user?.emailOptedIn === null ? `/user-email` : '/'; + // const url = window.location.search; + const logRoute = + user?.emailOptedIn === null + ? `/user-email` + : routePaths.home(DEFAULT_PROJECT_NAME); + return isAuthenticated ? logRoute : loggedOutRoute; }; const replaceToLoggedInRoute = diff --git a/src/ui/layouts/Home.tsx b/src/ui/layouts/Home.tsx index 614c4112d..8e66fd658 100644 --- a/src/ui/layouts/Home.tsx +++ b/src/ui/layouts/Home.tsx @@ -40,6 +40,7 @@ import { pipelinePagesActions, runPagesActions, } from '../../redux/actions'; +import { NotFound } from '../../ui/layouts/NotFound'; import Tour from './Tour'; @@ -84,6 +85,7 @@ export const Home: React.FC = () => { const stackComponentsTypes: any[] = useSelector( stackComponentSelectors.stackComponentTypes, ); + const [notFound, setNotFound] = useState(false); const selectedProject = useSelector(projectSelectors.selectedProject); const projects = useSelector(projectSelectors.myProjects); @@ -119,32 +121,52 @@ export const Home: React.FC = () => { { headers: { Authorization: `bearer ${authToken}` } }, ); - await dispatch( - projectsActions.getSelectedProject({ - allProjects: projects, - seletecdProject: selectedProject - ? selectedProject - : DEFAULT_PROJECT_NAME, - }), - ); - await dispatch( - pipelinesActions.getMy({ - project: selectedProject ? selectedProject : DEFAULT_PROJECT_NAME, - onSuccess: () => stopLoad(), - onFailure: () => stopLoad(), - }), - ); + // await dispatch( + // projectsActions.getMy({ + // selectDefault: false, + // selectedProject: selectedProject, + // onSuccess: () => stopLoad(), + // onFailure: () => stopLoad(), + // }), + // ); + + // await dispatch( + // projectsActions.getSelectedProject({ + // allProjects: projects, + // seletecdProject: selectedProject + // ? selectedProject + // : DEFAULT_PROJECT_NAME, + // }), + // ); + + // await dispatch( + // pipelinesActions.getMy({ + // project: selectedProject ? selectedProject : DEFAULT_PROJECT_NAME, + // onSuccess: () => stopLoad(), + // onFailure: () => stopLoad(), + // }), + // ); setDashboardData(data); setFetching(false); - } catch (err) { - // @ts-ignore + } catch (e) { dispatch( showToasterAction({ - description: translate('toasts.successful.passwordText'), - type: toasterTypes.success, + description: 'Not found', + type: toasterTypes.failure, }), ); + + await dispatch( + projectsActions.getMy({ + selectDefault: false, + selectedProject: DEFAULT_PROJECT_NAME, + onSuccess: () => setNotFound(true), + onFailure: () => stopLoad(), + }), + ); + + // push(routePaths.home(DEFAULT_PROJECT_NAME)); } }; getDashboardData(); @@ -166,6 +188,8 @@ export const Home: React.FC = () => { setBox(''); setIsHover(false); }; + console.log(notFound, 'notFound'); + if (notFound) return ; return ( diff --git a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedHeader.tsx b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedHeader.tsx index d76523712..8e8d85c1b 100644 --- a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedHeader.tsx +++ b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedHeader.tsx @@ -42,6 +42,7 @@ import cn from 'classnames'; import css from './../../../../../ui/components/inputs/index.module.scss'; import { ProjectPopup } from './ProjectPopup'; import CookieConsent from 'react-cookie-consent'; +// import { endpoints } from '../../../../../api/endpoints'; export const AuthenticatedHeader: React.FC<{ setMobileMenuOpen: (val: boolean) => void; @@ -57,35 +58,60 @@ export const AuthenticatedHeader: React.FC<{ const dispatch = useDispatch(); const { push } = usePushRoute(); const locationPath = useLocationPath(); - useEffect(() => { - const intervalId = setInterval(() => { - //assign interval to a variable to clear it. - dispatch( - projectsActions.getMy({ selectDefault: false, selectedProject }), - ); - }, 5000); - return () => clearInterval(intervalId); - //This is important - }); - useEffect(() => { - return history.listen((location) => { - console.log(`You changed the page to: ${location.pathname}`); - }); - }, [history]); + // useEffect(() => { + // const intervalId = setInterval(() => { + // //assign interval to a variable to clear it. + // dispatch( + // projectsActions.getMy({ selectDefault: false, selectedProject }), + // ); + // }, 5000); + // return () => clearInterval(intervalId); + // //This is important + // }); + // useEffect(() => { + // return history.listen((location) => { + // console.log(location) + // // window._mfq.push(['newPageView', location.pathname]); + // }) + // }, [history]) useEffect(() => { if (locationPath.includes('projects')) { - const selectedProject = locationPath.split('/')[2]; + const projectFromUrl = locationPath.split('/')[2]; + + if (selectedProject !== projectFromUrl && user) { + push(routePaths.home(projectFromUrl)); + } + dispatch( projectsActions.getMy({ selectDefault: false, - selectedProject, + selectedProject: projectFromUrl ? projectFromUrl : selectedProject, }), ); } - // debugger; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + + // useEffect(() => { + // return () => { + // if (window.performance) { + // console.info('window.performance works fine on this browser'); + // } + // if (performance.navigation.type == performance.navigation.TYPE_RELOAD) { + // console.info('This page is reloaded'); + // } else { + // if (selectedProject != window.location.pathname.split('/')[2]) { + // console.log( + // 'reloaded', + // selectedProject, + // window.location.pathname.split('/')[2], + // ); + // push(routePaths.home(window.location.pathname.split('/')[2])); + // } + // } + // }; + // }); if (!user) return null; const userFullName = user.fullName || user.name || DEFAULT_FULL_NAME; @@ -97,6 +123,7 @@ export const AuthenticatedHeader: React.FC<{ }; const startLoad = () => { + // debugger; dispatch(pipelinePagesActions.setFetching({ fetching: true })); dispatch(runPagesActions.setFetching({ fetching: true })); dispatch(stackPagesActions.setFetching({ fetching: true })); @@ -111,8 +138,8 @@ export const AuthenticatedHeader: React.FC<{ const onChange = (e: any) => { e.preventDefault(); startLoad(); - console.log(locationPath, 'test'); - history.push('/'); + + history.push(routePaths.home(e?.target?.value)); dispatch( projectsActions.getSelectedProject({ allProjects: projects, @@ -148,13 +175,37 @@ export const AuthenticatedHeader: React.FC<{ {!window.location.href?.includes('settings') && ( <> + {console.log( + selectedProject, + DEFAULT_PROJECT_NAME, + 'locationPath', + )} - + + @@ -125,12 +161,12 @@ export const ProjectPopup: React.FC<{ disabled={name === '' || submitting} loading={submitting} onClick={handleCreateProject} - >Create + > + Create - ); -}; \ No newline at end of file +}; diff --git a/src/ui/layouts/pipelines/PipelineDetail/useService.ts b/src/ui/layouts/pipelines/PipelineDetail/useService.ts index aabadbccb..8fdba54b7 100644 --- a/src/ui/layouts/pipelines/PipelineDetail/useService.ts +++ b/src/ui/layouts/pipelines/PipelineDetail/useService.ts @@ -2,7 +2,10 @@ import { PipelineDetailRouteParams } from '.'; import { pipelinesActions } from '../../../../redux/actions'; -import { pipelineSelectors } from '../../../../redux/selectors'; +import { + pipelineSelectors, + projectSelectors, +} from '../../../../redux/selectors'; import { useParams, useSelector } from '../../../hooks'; import { useDispatch } from 'react-redux'; import { pipelinePagesActions } from '../../../../redux/actions'; @@ -14,6 +17,7 @@ interface ServiceInterface { export const useService = (): ServiceInterface => { const dispatch = useDispatch(); + const selectedProject = useSelector(projectSelectors.selectedProject); const { id } = useParams(); useEffect(() => { diff --git a/src/ui/layouts/session/Login/index.tsx b/src/ui/layouts/session/Login/index.tsx index 91b325ae1..e4fce168f 100644 --- a/src/ui/layouts/session/Login/index.tsx +++ b/src/ui/layouts/session/Login/index.tsx @@ -19,7 +19,7 @@ import image from '../imageNew.png'; import { translate } from './translate'; import { routePaths } from '../../../../routes/routePaths'; import { Link } from 'react-router-dom'; -import { useDispatch, useLocationPath } from '../../../hooks'; +import { useDispatch, useLocationPath, useSelector } from '../../../hooks'; import { loginAction } from '../../../../redux/actions/session/loginAction'; import { @@ -29,11 +29,13 @@ import { userActions, } from '../../../../redux/actions'; import { toasterTypes } from '../../../../constants'; +import { projectSelectors } from '../../../../redux/selectors'; const Login: React.FC = () => { const [loading, setLoading] = useState(false); const dispatch = useDispatch(); const password = process.env.REACT_APP_PASSWORD; const username = process.env.REACT_APP_USERNAME; + const selectedProject = useSelector(projectSelectors.selectedProject); // const { push } = usePushRoute(); const locationPath = useLocationPath(); const login = async () => { @@ -63,16 +65,21 @@ const Login: React.FC = () => { setLoading(false); if (window.location.search.includes('projects')) { - const selectedProject = window.location.search.split('/')[2]; + const projectFromUrl = window.location.search.split('/')[2]; await dispatch( projectsActions.getMy({ selectDefault: false, - selectedProject, + selectedProject: projectFromUrl + ? projectFromUrl + : selectedProject, }), ); } else { - await dispatch(projectsActions.getMy({})); + await dispatch( + projectsActions.getMy({ selectDefault: false, selectedProject }), + ); } + // debugger; await dispatch(userActions.getMy({})); await dispatch(stackComponentsActions.getTypes()); // await push(routePaths.userEmail); diff --git a/src/ui/layouts/session/Login/useService.ts b/src/ui/layouts/session/Login/useService.ts index 3a3ca4956..4728734a6 100644 --- a/src/ui/layouts/session/Login/useService.ts +++ b/src/ui/layouts/session/Login/useService.ts @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { toasterTypes } from '../../../../constants'; +import { DEFAULT_PROJECT_NAME, toasterTypes } from '../../../../constants'; import { projectsActions, showToasterAction, @@ -7,8 +7,9 @@ import { userActions, } from '../../../../redux/actions'; import { loginAction } from '../../../../redux/actions/session/loginAction'; -import { useDispatch } from '../../../hooks'; +import { useDispatch, useSelector } from '../../../hooks'; import { translate } from './translate'; +import { projectSelectors } from '../../../../redux/selectors'; // import { routePaths } from '../../../../routes/routePaths'; interface ServiceInterface { @@ -23,6 +24,7 @@ interface ServiceInterface { export const useService = (): ServiceInterface => { const [loading, setLoading] = useState(false); + const selectedProject = useSelector(projectSelectors.selectedProject); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [hasSubmittedWithErrors, setHasSubmittedWithErrors] = useState(false); @@ -55,17 +57,28 @@ export const useService = (): ServiceInterface => { type: toasterTypes.success, }), ); + if (window.location.search.includes('projects')) { - const selectedProject = window.location.search.split('/')[2]; + const projectFromUrl = window.location.search.split('/')[2]; await dispatch( projectsActions.getMy({ selectDefault: false, - selectedProject, + selectedProject: projectFromUrl + ? projectFromUrl + : selectedProject, }), ); } else { - await dispatch(projectsActions.getMy({})); + await dispatch( + projectsActions.getMy({ + selectDefault: false, + selectedProject: selectedProject + ? selectedProject + : DEFAULT_PROJECT_NAME, + }), + ); } + await dispatch(userActions.getMy({})); await dispatch(stackComponentsActions.getTypes()); // await push(routePaths.userEmail); diff --git a/src/ui/layouts/session/UserEmail/Form.tsx b/src/ui/layouts/session/UserEmail/Form.tsx index 99957d524..ad587042a 100644 --- a/src/ui/layouts/session/UserEmail/Form.tsx +++ b/src/ui/layouts/session/UserEmail/Form.tsx @@ -123,7 +123,7 @@ export const Form: React.FC = () => { dispatch(projectsActions.getMy({})); } dispatch(stackComponentsActions.getTypes()); - push(loggedInRoute); + // push(loggedInRoute); }); } catch (err) { setSkipSubmitting(false); diff --git a/src/ui/layouts/session/UserEmail/index.tsx b/src/ui/layouts/session/UserEmail/index.tsx index 9ceff1723..58e30f87d 100644 --- a/src/ui/layouts/session/UserEmail/index.tsx +++ b/src/ui/layouts/session/UserEmail/index.tsx @@ -18,15 +18,15 @@ import image from '../imageNew.png'; import { getTranslateByScope } from '../../../../services'; import { routePaths } from '../../../../routes/routePaths'; import { sessionSelectors } from '../../../../redux/selectors'; -import { useDispatch, usePushRoute, useSelector } from '../../../hooks'; -import { loggedInRoute } from '../../../../constants'; +import { useDispatch, useSelector } from '../../../hooks'; +// import { loggedInRoute } from '../../../../constants'; import { Link } from 'react-router-dom'; import axios from 'axios'; import { stackComponentsActions } from '../../../../redux/actions'; const UserEmail: React.FC = () => { const translate = getTranslateByScope('ui.layouts.UserEmail'); - const { push } = usePushRoute(); + // const { push } = usePushRoute(); const dispatch = useDispatch(); const authToken = useSelector(sessionSelectors.authenticationToken); @@ -46,7 +46,7 @@ const UserEmail: React.FC = () => { if (data) { if (data?.email_opted_in !== null) { dispatch(stackComponentsActions.getTypes()); - push(loggedInRoute); + // push(loggedInRoute); } } setPageLoading(false);