import { History, Location } from 'history';
import { RootStore } from '~/store/store';
-import { matchProcessRoute, matchProcessLogRoute, matchProjectRoute, matchCollectionRoute, matchFavoritesRoute, matchTrashRoute } from './routes';
+import { matchProcessRoute, matchProcessLogRoute, matchProjectRoute, matchCollectionRoute, matchFavoritesRoute, matchTrashRoute, matchRootRoute } from './routes';
import { loadProject, loadCollection, loadFavorites, loadTrash, loadProcess, loadProcessLog } from '~/store/workbench/workbench-actions';
+import { navigateToRootProject } from '~/store/navigation/navigation-action';
export const addRouteChangeHandlers = (history: History, store: RootStore) => {
const handler = handleLocationChange(store);
};
const handleLocationChange = (store: RootStore) => ({ pathname }: Location) => {
+ const rootMatch = matchRootRoute(pathname);
const projectMatch = matchProjectRoute(pathname);
const collectionMatch = matchCollectionRoute(pathname);
const favoriteMatch = matchFavoritesRoute(pathname);
store.dispatch(loadProcess(processMatch.params.id));
} else if (processLogMatch) {
store.dispatch(loadProcessLog(processLogMatch.params.id));
+ } else if (rootMatch) {
+ store.dispatch(navigateToRootProject);
}
};
import { ResourceKind, extractUuidKind } from '~/models/resource';
import { getCollectionUrl } from "~/models/collection";
import { getProjectUrl } from "~/models/project";
-
import { SidePanelTreeCategory } from '../side-panel-tree/side-panel-tree-actions';
import { Routes, getProcessUrl, getProcessLogUrl } from '~/routes/routes';
+import { RootState } from '~/store/store';
+import { ServiceRepository } from '~/services/services';
export const navigateTo = (uuid: string) =>
async (dispatch: Dispatch) => {
export const navigateToProcess = compose(push, getProcessUrl);
-export const navigateToProcessLogs = compose(push, getProcessLogUrl);
\ No newline at end of file
+export const navigateToProcessLogs = compose(push, getProcessLogUrl);
+
+export const navigateToRootProject = (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const rootProjectUuid = services.authService.getUuid();
+ if(rootProjectUuid){
+ dispatch(navigateToProject(rootProjectUuid));
+ }
+};
\ No newline at end of file
import { DropdownMenu } from "~/components/dropdown-menu/dropdown-menu";
import { Button, MenuItem, IconButton } from "@material-ui/core";
import { User } from "~/models/user";
+import { MemoryRouter } from 'react-router-dom';
configure({ adapter: new Adapter() });
it("renders all components and the menu for authenticated user if user prop has value", () => {
const mainAppBar = mount(
- <MainAppBar
- {...mockMainAppBarProps({ user })}
- />
+ <MemoryRouter>
+ <MainAppBar
+ {...mockMainAppBarProps({ user })}
+ />
+ </MemoryRouter>
);
expect(mainAppBar.find(SearchBar)).toHaveLength(1);
expect(mainAppBar.find(Breadcrumbs)).toHaveLength(1);
it("renders only the menu for anonymous user if user prop is undefined", () => {
const menuItems = { accountMenu: [], helpMenu: [], anonymousMenu: [{ label: 'Sign in' }] };
const mainAppBar = mount(
- <MainAppBar
- {...mockMainAppBarProps({ user: undefined, menuItems })}
- />
+ <MemoryRouter>
+ <MainAppBar
+ {...mockMainAppBarProps({ user: undefined, menuItems })}
+ />
+ </MemoryRouter>
);
expect(mainAppBar.find(SearchBar)).toHaveLength(0);
expect(mainAppBar.find(Breadcrumbs)).toHaveLength(0);
it("communicates with <SearchBar />", () => {
const onSearch = jest.fn();
const mainAppBar = mount(
- <MainAppBar
- {...mockMainAppBarProps({ searchText: 'search text', searchDebounce: 2000, onSearch, user })}
- />
+ <MemoryRouter>
+ <MainAppBar
+ {...mockMainAppBarProps({ searchText: 'search text', searchDebounce: 2000, onSearch, user })}
+ />
+ </MemoryRouter>
);
const searchBar = mainAppBar.find(SearchBar);
expect(searchBar.prop("value")).toBe("search text");
const onMenuItemClick = jest.fn();
const menuItems = { accountMenu: [{ label: "log out" }], helpMenu: [], anonymousMenu: [] };
const mainAppBar = mount(
- <MainAppBar
- {...mockMainAppBarProps({ menuItems, onMenuItemClick, user })}
- />
+ <MemoryRouter>
+ <MainAppBar
+ {...mockMainAppBarProps({ menuItems, onMenuItemClick, user })}
+ />
+ </MemoryRouter>
);
mainAppBar.find(DropdownMenu).at(0).find(IconButton).simulate("click");
import * as React from "react";
import { AppBar, Toolbar, Typography, Grid, IconButton, Badge, Button, MenuItem } from "@material-ui/core";
+import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { Link } from "react-router-dom";
import { User, getUserFullname } from "~/models/user";
import { SearchBar } from "~/components/search-bar/search-bar";
import { DropdownMenu } from "~/components/dropdown-menu/dropdown-menu";
import { DetailsIcon, NotificationIcon, UserPanelIcon, HelpIcon } from "~/components/icon/icon";
+import { Routes } from '~/routes/routes';
+
+type CssRules = 'link';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ link: {
+ textDecoration: 'none',
+ color: 'inherit'
+ }
+});
export interface MainAppBarMenuItem {
label: string;
onDetailsPanelToggle: () => void;
}
-export type MainAppBarProps = MainAppBarDataProps & MainAppBarActionProps;
+export type MainAppBarProps = MainAppBarDataProps & MainAppBarActionProps & WithStyles<CssRules>;
-export const MainAppBar: React.SFC<MainAppBarProps> = (props) => {
- return <AppBar position="static">
- <Toolbar>
- <Grid container justify="space-between">
- <Grid item xs={3}>
- <Typography variant="headline" color="inherit" noWrap>
- Arvados 2
- </Typography>
- <Typography variant="body1" color="inherit" noWrap >
- {props.buildInfo}
- </Typography>
- </Grid>
- <Grid item xs={6} container alignItems="center">
- {
- props.user && <SearchBar
- value={props.searchText}
- onSearch={props.onSearch}
- debounce={props.searchDebounce}
- />
- }
+export const MainAppBar = withStyles(styles)(
+ (props: MainAppBarProps) => {
+ return <AppBar position="static">
+ <Toolbar>
+ <Grid container justify="space-between">
+ <Grid item xs={3}>
+ <Typography variant="headline" color="inherit" noWrap>
+ <Link to={Routes.ROOT} className={props.classes.link}>
+ Arvados 2
+ </Link>
+ </Typography>
+ <Typography variant="body1" color="inherit" noWrap >
+ {props.buildInfo}
+ </Typography>
+ </Grid>
+ <Grid item xs={6} container alignItems="center">
+ {
+ props.user && <SearchBar
+ value={props.searchText}
+ onSearch={props.onSearch}
+ debounce={props.searchDebounce}
+ />
+ }
+ </Grid>
+ <Grid item xs={3} container alignItems="center" justify="flex-end">
+ {
+ props.user ? renderMenuForUser(props) : renderMenuForAnonymous(props)
+ }
+ </Grid>
</Grid>
- <Grid item xs={3} container alignItems="center" justify="flex-end">
- {
- props.user ? renderMenuForUser(props) : renderMenuForAnonymous(props)
- }
- </Grid>
- </Grid>
- </Toolbar>
- <Toolbar >
- {props.user && <props.breadcrumbs />}
- {props.user && <IconButton color="inherit" onClick={props.onDetailsPanelToggle}>
- <DetailsIcon />
- </IconButton>
- }
- </Toolbar>
- </AppBar>;
-};
+ </Toolbar>
+ <Toolbar >
+ {props.user && <props.breadcrumbs />}
+ {props.user && <IconButton color="inherit" onClick={props.onDetailsPanelToggle}>
+ <DetailsIcon />
+ </IconButton>
+ }
+ </Toolbar>
+ </AppBar>;
+ }
+);
const renderMenuForUser = ({ user, menuItems, onMenuItemClick }: MainAppBarProps) => {
return (