import * as React from 'react';
import { Grid, Paper, Toolbar, StyleRulesCallback, withStyles, WithStyles, TablePagination, IconButton, Tooltip } from '@material-ui/core';
-import MoreVertIcon from "@material-ui/icons/MoreVert";
import { ColumnSelector } from "../column-selector/column-selector";
import { DataTable, DataColumns } from "../data-table/data-table";
import { DataColumn, SortDirection } from "../data-table/data-column";
import { DataTableFilterItem } from '../data-table-filters/data-table-filters';
import { SearchInput } from '../search-input/search-input';
import { ArvadosTheme } from "~/common/custom-theme";
+import { MoreOptionsIcon } from '~/components/icon/icon';
type CssRules = 'searchBox' | "toolbar" | "footer" | "root" | 'moreOptionsButton';
<Grid container justify="center">
<Tooltip title="More options" disableFocusListener>
<IconButton className={this.props.classes.moreOptionsButton} onClick={event => this.props.onContextMenu(event, item)}>
- <MoreVertIcon />
+ <MoreOptionsIcon />
</IconButton>
</Tooltip>
</Grid>
import { DragDropContextProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { initAdvanceFormProjectsTree } from '~/store/search-bar/search-bar-actions';
+import { repositoryActionSet } from '~/views-components/context-menu/action-sets/repository-action-set';
console.log(`Starting arvados [${getBuildInfo()}]`);
addMenuActionSet(ContextMenuKind.PROCESS, processActionSet);
addMenuActionSet(ContextMenuKind.PROCESS_RESOURCE, processResourceActionSet);
addMenuActionSet(ContextMenuKind.TRASH, trashActionSet);
+addMenuActionSet(ContextMenuKind.REPOSITORY, repositoryActionSet);
fetchConfig()
.then(({ config, apiHost }) => {
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Resource } from "~/models/resource";
+
+export interface RepositoriesResource extends Resource {
+ name: string;
+ cloneUrls: string[];
+}
LOG = "arvados#log",
PROCESS = "arvados#containerRequest",
PROJECT = "arvados#group",
+ REPOSITORY = "arvados#repository",
USER = "arvados#user",
WORKFLOW = "arvados#workflow",
NONE = "arvados#none"
CONTAINER_REQUEST = 'xvhdp',
GROUP = 'j7d0g',
LOG = '57u5n',
+ REPOSITORY = 's0uqq',
USER = 'tpzed',
WORKFLOW = '7fd4e',
}
return ResourceKind.LOG;
case ResourceObjectType.WORKFLOW:
return ResourceKind.WORKFLOW;
+ case ResourceObjectType.REPOSITORY:
+ return ResourceKind.REPOSITORY;
default:
return undefined;
}
import { History, Location } from 'history';
import { RootStore } from '~/store/store';
-import { matchProcessRoute, matchProcessLogRoute, matchProjectRoute, matchCollectionRoute, matchFavoritesRoute, matchTrashRoute, matchRootRoute, matchSharedWithMeRoute, matchRunProcessRoute, matchWorkflowRoute, matchSearchResultsRoute } from './routes';
-import { loadProject, loadCollection, loadFavorites, loadTrash, loadProcess, loadProcessLog } from '~/store/workbench/workbench-actions';
+import { matchProcessRoute, matchProcessLogRoute, matchProjectRoute, matchCollectionRoute, matchFavoritesRoute, matchTrashRoute, matchRootRoute, matchSharedWithMeRoute, matchRunProcessRoute, matchWorkflowRoute, matchSearchResultsRoute, matchRepositoriesRoute } from './routes';
+import { loadProject, loadCollection, loadFavorites, loadTrash, loadProcess, loadProcessLog, loadRepositories } from '~/store/workbench/workbench-actions';
import { navigateToRootProject } from '~/store/navigation/navigation-action';
import { loadSharedWithMe, loadRunProcess, loadWorkflow, loadSearchResults } from '~//store/workbench/workbench-actions';
const trashMatch = matchTrashRoute(pathname);
const processMatch = matchProcessRoute(pathname);
const processLogMatch = matchProcessLogRoute(pathname);
+ const repositoryMatch = matchRepositoriesRoute(pathname);
const searchResultsMatch = matchSearchResultsRoute(pathname);
const sharedWithMeMatch = matchSharedWithMeRoute(pathname);
const runProcessMatch = matchRunProcessRoute(pathname);
store.dispatch(loadWorkflow);
} else if (searchResultsMatch) {
store.dispatch(loadSearchResults);
+ } else if(repositoryMatch) {
+ store.dispatch(loadRepositories);
}
};
FAVORITES: '/favorites',
TRASH: '/trash',
PROCESS_LOGS: `/process-logs/:id(${RESOURCE_UUID_PATTERN})`,
+ REPOSITORIES: '/repositories',
SHARED_WITH_ME: '/shared-with-me',
RUN_PROCESS: '/run-process',
WORKFLOWS: '/workflows',
export const matchRunProcessRoute = (route: string) =>
matchPath(route, { path: Routes.RUN_PROCESS });
-
+
export const matchWorkflowRoute = (route: string) =>
matchPath<ResourceRouteParams>(route, { path: Routes.WORKFLOWS });
export const matchSearchResultsRoute = (route: string) =>
matchPath<ResourceRouteParams>(route, { path: Routes.SEARCH_RESULTS });
+
+export const matchRepositoriesRoute = (route: string) =>
+ matchPath<ResourceRouteParams>(route, { path: Routes.REPOSITORIES });
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { AxiosInstance } from "axios";
+import { CommonResourceService } from "~/services/common-service/common-resource-service";
+import { RepositoriesResource } from '~/models/repositories';
+import { ApiActions } from '~/services/api/api-actions';
+
+ export class RepositoriesService extends CommonResourceService<RepositoriesResource> {
+ constructor(serverApi: AxiosInstance, actions: ApiActions) {
+ super(serverApi, "repositories", actions);
+ }
+
+ getAllPermissions() {
+ return CommonResourceService.defaultResponse(
+ this.serverApi
+ .get('repositories/get_all_permissions'),
+ this.actions
+ );
+ }
+}
\ No newline at end of file
import { WorkflowService } from "~/services/workflow-service/workflow-service";
import { SearchService } from '~/services/search-service/search-service';
import { PermissionService } from "~/services/permission-service/permission-service";
+import { RepositoriesService } from '~/services/repositories-service/repositories-service';
export type ServiceRepository = ReturnType<typeof createServices>;
const logService = new LogService(apiClient, actions);
const permissionService = new PermissionService(apiClient, actions);
const projectService = new ProjectService(apiClient, actions);
+ const repositoriesService = new RepositoriesService(apiClient, actions);
const userService = new UserService(apiClient, actions);
const workflowService = new WorkflowService(apiClient, actions);
logService,
permissionService,
projectService,
+ repositoriesService,
searchService,
tagService,
userService,
import { UserResource } from '~/models/user';
import { isSidePanelTreeCategory } from '~/store/side-panel-tree/side-panel-tree-actions';
import { extractUuidKind, ResourceKind } from '~/models/resource';
-import { matchProcessRoute } from '~/routes/routes';
import { Process } from '~/store/processes/process';
export const contextMenuActions = unionize({
}));
};
+export const openRepositoryContextMenu = (event: React.MouseEvent<HTMLElement>) =>
+ (dispatch: Dispatch, getState: () => RootState) => {
+ dispatch<any>(openContextMenu(event, {
+ name: '',
+ uuid: '',
+ ownerUuid: '',
+ kind: ResourceKind.REPOSITORY,
+ menuKind: ContextMenuKind.REPOSITORY
+ }));
+ };
+
export const openRootProjectContextMenu = (event: React.MouseEvent<HTMLElement>, projectUuid: string) =>
(dispatch: Dispatch, getState: () => RootState) => {
const res = getResource<UserResource>(projectUuid)(getState().resources);
export const navigateToRunProcess = push(Routes.RUN_PROCESS);
export const navigateToSearchResults = push(Routes.SEARCH_RESULTS);
+
+export const navigateToRepositories = push(Routes.REPOSITORIES);
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch } from "redux";
+import { bindDataExplorerActions } from '~/store/data-explorer/data-explorer-action';
+import { RootState } from '~/store/store';
+import { ServiceRepository } from "~/services/services";
+import { navigateToRepositories } from "~/store/navigation/navigation-action";
+import { unionize, ofType, UnionOf } from "~/common/unionize";
+
+export const repositoriesActions = unionize({
+ SET_REPOSITORIES: ofType<any>(),
+});
+
+ export type RepositoriesActions = UnionOf<typeof repositoriesActions>;
+
+export const REPOSITORIES_PANEL = 'repositoriesPanel';
+
+const repositoriesBindedActions = bindDataExplorerActions(REPOSITORIES_PANEL);
+
+export const openRepositoriesPanel = () =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch<any>(navigateToRepositories);
+ };
+
+export const loadRepositoriesData = () =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const repositories = await services.repositoriesService.list();
+ dispatch(repositoriesActions.SET_REPOSITORIES(repositories.items));
+ };
+
+export const loadRepositoriesPanel = () =>
+ (dispatch: Dispatch) => {
+ dispatch(repositoriesBindedActions.REQUEST_ITEMS());
+ };
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { repositoriesActions, RepositoriesActions } from '~/store/repositories/repositories-actions';
+import { RepositoriesResource } from '~/models/repositories';
+
+interface Repositories {
+ items: RepositoriesResource[];
+}
+
+const initialState: Repositories = {
+ items: []
+};
+
+export const repositoriesReducer = (state = initialState, action: RepositoriesActions): Repositories =>
+ repositoriesActions.match(action, {
+ SET_REPOSITORIES: items => ({ ...state, items }),
+ default: () => state
+ });
\ No newline at end of file
import { SEARCH_RESULTS_PANEL_ID } from '~/store/search-results-panel/search-results-panel-actions';
import { SearchResultsMiddlewareService } from './search-results-panel/search-results-middleware-service';
import { resourcesDataReducer } from "~/store/resources-data/resources-data-reducer";
+import { repositoriesReducer } from '~/store/repositories/repositories-reducer';
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
progressIndicator: progressIndicatorReducer,
runProcessPanel: runProcessPanelReducer,
appInfo: appInfoReducer,
- searchBar: searchBarReducer
+ searchBar: searchBarReducer,
+ repositories: repositoriesReducer
});
// SPDX-License-Identifier: AGPL-3.0
import { Dispatch } from 'redux';
-import { RootState } from "../store";
+import { RootState } from "~/store/store";
import { loadDetailsPanel } from '~/store/details-panel/details-panel-action';
-import { snackbarActions } from '../snackbar/snackbar-actions';
-import { loadFavoritePanel } from '../favorite-panel/favorite-panel-action';
+import { snackbarActions } from '~/store/snackbar/snackbar-actions';
+import { loadFavoritePanel } from '~/store/favorite-panel/favorite-panel-action';
import { openProjectPanel, projectPanelActions, setIsProjectPanelTrashed } from '~/store/project-panel/project-panel-action';
-import { activateSidePanelTreeItem, initSidePanelTree, SidePanelTreeCategory, loadSidePanelTreeProjects } from '../side-panel-tree/side-panel-tree-actions';
-import { loadResource, updateResources } from '../resources/resources-actions';
+import { activateSidePanelTreeItem, initSidePanelTree, SidePanelTreeCategory, loadSidePanelTreeProjects } from '~/store/side-panel-tree/side-panel-tree-actions';
+import { loadResource, updateResources } from '~/store/resources/resources-actions';
import { favoritePanelActions } from '~/store/favorite-panel/favorite-panel-action';
import { projectPanelColumns } from '~/views/project-panel/project-panel';
import { favoritePanelColumns } from '~/views/favorite-panel/favorite-panel';
import { matchRootRoute } from '~/routes/routes';
-import { setSidePanelBreadcrumbs, setProcessBreadcrumbs, setSharedWithMeBreadcrumbs, setTrashBreadcrumbs } from '../breadcrumbs/breadcrumbs-actions';
-import { navigateToProject } from '../navigation/navigation-action';
+import { setSidePanelBreadcrumbs, setProcessBreadcrumbs, setSharedWithMeBreadcrumbs, setTrashBreadcrumbs, setBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
+import { navigateToProject } from '~/store/navigation/navigation-action';
import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
import { ServiceRepository } from '~/services/services';
-import { getResource } from '../resources/resources';
-import { getProjectPanelCurrentUuid } from '../project-panel/project-panel-action';
+import { getResource } from '~/store/resources/resources';
+import { getProjectPanelCurrentUuid } from '~/store/project-panel/project-panel-action';
import * as projectCreateActions from '~/store/projects/project-create-actions';
import * as projectMoveActions from '~/store/projects/project-move-actions';
import * as projectUpdateActions from '~/store/projects/project-update-actions';
import * as collectionCopyActions from '~/store/collections/collection-copy-actions';
import * as collectionUpdateActions from '~/store/collections/collection-update-actions';
import * as collectionMoveActions from '~/store/collections/collection-move-actions';
-import * as processesActions from '../processes/processes-actions';
+import * as processesActions from '~/store/processes/processes-actions';
import * as processMoveActions from '~/store/processes/process-move-actions';
import * as processUpdateActions from '~/store/processes/process-update-actions';
import * as processCopyActions from '~/store/processes/process-copy-actions';
import { trashPanelColumns } from "~/views/trash-panel/trash-panel";
import { loadTrashPanel, trashPanelActions } from "~/store/trash-panel/trash-panel-action";
-import { initProcessLogsPanel } from '../process-logs-panel/process-logs-panel-actions';
+import { initProcessLogsPanel } from '~/store/process-logs-panel/process-logs-panel-actions';
import { loadProcessPanel } from '~/store/process-panel/process-panel-actions';
import { sharedWithMePanelActions } from '~/store/shared-with-me-panel/shared-with-me-panel-actions';
-import { loadSharedWithMePanel } from '../shared-with-me-panel/shared-with-me-panel-actions';
+import { loadSharedWithMePanel } from '~/store/shared-with-me-panel/shared-with-me-panel-actions';
import { CopyFormDialogData } from '~/store/copy-dialog/copy-dialog';
import { loadWorkflowPanel, workflowPanelActions } from '~/store/workflow-panel/workflow-panel-actions';
import { workflowPanelColumns } from '~/views/workflow-panel/workflow-panel-view';
import { progressIndicatorActions } from '~/store/progress-indicator/progress-indicator-actions';
-import { getProgressIndicator } from '../progress-indicator/progress-indicator-reducer';
+import { getProgressIndicator } from '~/store/progress-indicator/progress-indicator-reducer';
import { ResourceKind, extractUuidKind } from '~/models/resource';
import { FilterBuilder } from '~/services/api/filter-builder';
import { GroupContentsResource } from '~/services/groups-service/groups-service';
import { CollectionResource } from "~/models/collection";
import { searchResultsPanelActions, loadSearchResultsPanel } from '~/store/search-results-panel/search-results-panel-actions';
import { searchResultsPanelColumns } from '~/views/search-results-panel/search-results-panel-view';
+import { loadRepositoriesPanel } from '~/store/repositories/repositories-actions';
export const WORKBENCH_LOADING_SCREEN = 'workbenchLoadingScreen';
await dispatch(loadSearchResultsPanel());
});
+export const loadRepositories = handleFirstTimeLoad(
+ async (dispatch: Dispatch<any>) => {
+ await dispatch(loadRepositoriesPanel());
+ dispatch(setBreadcrumbs([{ label: 'Repositories' }]));
+ });
+
const finishLoadingProject = (project: GroupContentsResource | string) =>
async (dispatch: Dispatch<any>) => {
const uuid = typeof project === 'string' ? project : project.uuid;
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
+import { AdvancedIcon, RemoveIcon, ShareIcon } from "~/components/icon/icon";
+import { openFileRemoveDialog, openRenameFileDialog } from '~/store/collection-panel/collection-panel-files/collection-panel-files-actions';
+
+export const repositoryActionSet: ContextMenuActionSet = [[{
+ name: "Attributes",
+ icon: AdvancedIcon,
+ execute: (dispatch, resource) => {
+ dispatch<any>(openRenameFileDialog({ name: resource.name, id: resource.uuid }));
+ }
+}, {
+ name: "Share",
+ icon: ShareIcon,
+ execute: (dispatch, resource) => {
+ dispatch<any>(openRenameFileDialog({ name: resource.name, id: resource.uuid }));
+ }
+}, {
+ name: "Advanced",
+ icon: AdvancedIcon,
+ execute: (dispatch, resource) => {
+ dispatch<any>(openFileRemoveDialog(resource.uuid));
+ }
+},
+{
+ name: "Remove",
+ icon: RemoveIcon,
+ execute: (dispatch, resource) => {
+ dispatch<any>(openFileRemoveDialog(resource.uuid));
+ }
+}]];
TRASHED_COLLECTION = 'TrashedCollection',
PROCESS = "Process",
PROCESS_RESOURCE = 'ProcessResource',
- PROCESS_LOGS = "ProcessLogs"
+ PROCESS_LOGS = "ProcessLogs",
+ REPOSITORY = "Repository"
}
import { DispatchProp, connect } from 'react-redux';
import { logout } from "~/store/auth/auth-action";
import { RootState } from "~/store/store";
-import { openCurrentTokenDialog } from '../../store/current-token-dialog/current-token-dialog-actions';
+import { openCurrentTokenDialog } from '~/store/current-token-dialog/current-token-dialog-actions';
+import { openRepositoriesPanel } from "~/store/repositories/repositories-actions";
interface AccountMenuProps {
user?: User;
<MenuItem>
{getUserFullname(user)}
</MenuItem>
+ <MenuItem onClick={() => dispatch(openRepositoriesPanel())}>Repositories</MenuItem>
<MenuItem onClick={() => dispatch(openCurrentTokenDialog)}>Current token</MenuItem>
<MenuItem>My account</MenuItem>
<MenuItem onClick={() => dispatch(logout())}>Logout</MenuItem>
import { Toolbar, IconButton, Tooltip, Grid } from "@material-ui/core";
import { DetailsIcon } from "~/components/icon/icon";
import { Breadcrumbs } from "~/views-components/breadcrumbs/breadcrumbs";
-import { detailsPanelActions } from "~/store/details-panel/details-panel-action";
import { connect } from 'react-redux';
import { RootState } from '~/store/store';
-import { matchWorkflowRoute } from '~/routes/routes';
+import { matchWorkflowRoute, matchRepositoriesRoute } from '~/routes/routes';
import { toggleDetailsPanel } from '~/store/details-panel/details-panel-action';
interface MainContentBarProps {
return !!match;
};
+const isRepositoriesPath = ({ router }: RootState) => {
+ const pathname = router.location ? router.location.pathname : '';
+ const match = matchRepositoriesRoute(pathname);
+ return !!match;
+};
+
export const MainContentBar = connect((state: RootState) => ({
- buttonVisible: !isWorkflowPath(state)
+ buttonVisible: !isWorkflowPath(state) && !isRepositoriesPath(state)
}), {
onDetailsPanelToggle: toggleDetailsPanel
})((props: MainContentBarProps) =>
<Breadcrumbs />
</Grid>
<Grid item>
- {props.buttonVisible ? <Tooltip title="Additional Info">
+ {props.buttonVisible && <Tooltip title="Additional Info">
<IconButton color="inherit" onClick={props.onDetailsPanelToggle}>
<DetailsIcon />
</IconButton>
- </Tooltip> : null}
+ </Tooltip>}
</Grid>
</Grid>
</Toolbar>);
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Grid, Typography, Button, Card, CardContent, TableBody, TableCell, TableHead, TableRow, Table, Tooltip, IconButton } 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 { Dispatch, compose } from 'redux';
+import { RootState } from '~/store/store';
+import { HelpIcon, AddIcon, MoreOptionsIcon } from '~/components/icon/icon';
+import { loadRepositoriesData } from '~/store/repositories/repositories-actions';
+import { RepositoriesResource } from '~/models/repositories';
+import { openRepositoryContextMenu } from '~/store/context-menu/context-menu-actions';
+
+
+type CssRules = 'link' | 'button' | 'icon' | 'iconRow' | 'moreOptionsButton' | 'moreOptions' | 'cloneUrls';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ link: {
+ textDecoration: 'none',
+ color: theme.palette.primary.main,
+ "&:hover": {
+ color: theme.palette.primary.dark,
+ transition: 'all 0.5s ease'
+ }
+ },
+ button: {
+ textAlign: 'right',
+ alignSelf: 'center'
+ },
+ icon: {
+ cursor: 'pointer',
+ color: theme.palette.grey["500"],
+ "&:hover": {
+ color: theme.palette.common.black,
+ transition: 'all 0.5s ease'
+ }
+ },
+ iconRow: {
+ paddingTop: theme.spacing.unit * 2,
+ textAlign: 'right'
+ },
+ moreOptionsButton: {
+ padding: 0
+ },
+ moreOptions: {
+ textAlign: 'right',
+ '&:last-child': {
+ paddingRight: 0
+ }
+ },
+ cloneUrls: {
+ whiteSpace: 'pre-wrap'
+ }
+});
+
+const mapStateToProps = (state: RootState) => {
+ return {
+ repositories: state.repositories.items
+ };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch): Pick<RepositoriesActionProps, 'onOptionsMenuOpen' | 'loadRepositories'> => ({
+ loadRepositories: () => dispatch<any>(loadRepositoriesData()),
+ onOptionsMenuOpen: (event) => {
+ dispatch<any>(openRepositoryContextMenu(event));
+ },
+});
+
+interface RepositoriesActionProps {
+ loadRepositories: () => void;
+ onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>) => void;
+}
+
+interface RepositoriesDataProps {
+ repositories: RepositoriesResource[];
+}
+
+
+type RepositoriesProps = RepositoriesDataProps & RepositoriesActionProps & WithStyles<CssRules>;
+
+export const RepositoriesPanel = compose(
+ withStyles(styles),
+ connect(mapStateToProps, mapDispatchToProps))(
+ class extends React.Component<RepositoriesProps> {
+ componentDidMount() {
+ this.props.loadRepositories();
+ }
+ render() {
+ const { classes, repositories, onOptionsMenuOpen } = this.props;
+ console.log(repositories);
+ return (
+ <Card>
+ <CardContent>
+ <Grid container direction="row">
+ <Grid item xs={8}>
+ <Typography variant="body2">
+ When you are using an Arvados virtual machine, you should clone the https:// URLs. This will authenticate automatically using your API token. <br />
+ In order to clone git repositories using SSH, <Link to='' className={classes.link}>add an SSH key to your account</Link> and clone the git@ URLs.
+ </Typography>
+ </Grid>
+ <Grid item xs={4} className={classes.button}>
+ <Button variant="contained" color="primary">
+ <AddIcon /> NEW REPOSITORY
+ </Button>
+ </Grid>
+ </Grid>
+ <Grid item xs={12}>
+ <div className={classes.iconRow}>
+ <Tooltip title="Sample git quick start">
+ <IconButton className={classes.moreOptionsButton}>
+ <HelpIcon className={classes.icon} />
+ </IconButton>
+ </Tooltip>
+ </div>
+ </Grid>
+ <Grid item xs={12}>
+ {repositories && <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell>Name</TableCell>
+ <TableCell>URL</TableCell>
+ <TableCell />
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ {repositories.map((repository, index) =>
+ <TableRow key={index}>
+ <TableCell>{repository.name}</TableCell>
+ <TableCell className={classes.cloneUrls}>{repository.cloneUrls.join("\n")}</TableCell>
+ <TableCell className={classes.moreOptions}>
+ <Tooltip title="More options" disableFocusListener>
+ <IconButton onClick={onOptionsMenuOpen} className={classes.moreOptionsButton}>
+ <MoreOptionsIcon />
+ </IconButton>
+ </Tooltip>
+ </TableCell>
+ </TableRow>)}
+ </TableBody>
+ </Table>}
+ </Grid>
+ </CardContent>
+ </Card>
+ );
+ }
+ }
+ );
\ No newline at end of file
import { AdvancedTabDialog } from '~/views-components/advanced-tab-dialog/advanced-tab-dialog';
import { ProcessInputDialog } from '~/views-components/process-input-dialog/process-input-dialog';
import { ProjectPropertiesDialog } from '~/views-components/project-properties-dialog/project-properties-dialog';
+import { RepositoriesPanel } from '~/views/repositories-panel/repositories-panel';
type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
<Route path={Routes.RUN_PROCESS} component={RunProcessPanel} />
<Route path={Routes.WORKFLOWS} component={WorkflowPanel} />
<Route path={Routes.SEARCH_RESULTS} component={SearchResultsPanel} />
+ <Route path={Routes.REPOSITORIES} component={RepositoriesPanel} />
</Switch>
</Grid>
</Grid>