[ARVADOS-WORKBENCH2] created: 1.2.0-914-ga0aedfc
Git user
git at public.curoverse.com
Mon Nov 19 10:45:26 EST 2018
at a0aedfcf68e7b3d4caeee3e36d776ca0b34780bf (commit)
commit a0aedfcf68e7b3d4caeee3e36d776ca0b34780bf
Author: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
Date: Mon Nov 19 16:45:05 2018 +0100
repositories-panel-init
Feature #13865
Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
diff --git a/src/components/data-explorer/data-explorer.tsx b/src/components/data-explorer/data-explorer.tsx
index 08f52d0..f863ba1 100644
--- a/src/components/data-explorer/data-explorer.tsx
+++ b/src/components/data-explorer/data-explorer.tsx
@@ -4,13 +4,13 @@
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';
@@ -127,7 +127,7 @@ export const DataExplorer = withStyles(styles)(
<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>
diff --git a/src/index.tsx b/src/index.tsx
index efe3a57..922720a 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -48,6 +48,7 @@ import { getBuildInfo } from '~/common/app-info';
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()}]`);
@@ -64,6 +65,7 @@ addMenuActionSet(ContextMenuKind.TRASHED_COLLECTION, trashedCollectionActionSet)
addMenuActionSet(ContextMenuKind.PROCESS, processActionSet);
addMenuActionSet(ContextMenuKind.PROCESS_RESOURCE, processResourceActionSet);
addMenuActionSet(ContextMenuKind.TRASH, trashActionSet);
+addMenuActionSet(ContextMenuKind.REPOSITORY, repositoryActionSet);
fetchConfig()
.then(({ config, apiHost }) => {
diff --git a/src/models/repositories.ts b/src/models/repositories.ts
new file mode 100644
index 0000000..63494bc
--- /dev/null
+++ b/src/models/repositories.ts
@@ -0,0 +1,10 @@
+// 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[];
+}
diff --git a/src/models/resource.ts b/src/models/resource.ts
index b8156cf..520520f 100644
--- a/src/models/resource.ts
+++ b/src/models/resource.ts
@@ -28,6 +28,7 @@ export enum ResourceKind {
LOG = "arvados#log",
PROCESS = "arvados#containerRequest",
PROJECT = "arvados#group",
+ REPOSITORY = "arvados#repository",
USER = "arvados#user",
WORKFLOW = "arvados#workflow",
NONE = "arvados#none"
@@ -39,6 +40,7 @@ export enum ResourceObjectType {
CONTAINER_REQUEST = 'xvhdp',
GROUP = 'j7d0g',
LOG = '57u5n',
+ REPOSITORY = 's0uqq',
USER = 'tpzed',
WORKFLOW = '7fd4e',
}
@@ -73,6 +75,8 @@ export const extractUuidKind = (uuid: string = '') => {
return ResourceKind.LOG;
case ResourceObjectType.WORKFLOW:
return ResourceKind.WORKFLOW;
+ case ResourceObjectType.REPOSITORY:
+ return ResourceKind.REPOSITORY;
default:
return undefined;
}
diff --git a/src/routes/route-change-handlers.ts b/src/routes/route-change-handlers.ts
index ef9e9eb..a4a53d7 100644
--- a/src/routes/route-change-handlers.ts
+++ b/src/routes/route-change-handlers.ts
@@ -4,8 +4,8 @@
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';
@@ -23,6 +23,7 @@ const handleLocationChange = (store: RootStore) => ({ pathname }: Location) => {
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);
@@ -50,5 +51,7 @@ const handleLocationChange = (store: RootStore) => ({ pathname }: Location) => {
store.dispatch(loadWorkflow);
} else if (searchResultsMatch) {
store.dispatch(loadSearchResults);
+ } else if(repositoryMatch) {
+ store.dispatch(loadRepositories);
}
};
diff --git a/src/routes/routes.ts b/src/routes/routes.ts
index e5f3493..5dbecb4 100644
--- a/src/routes/routes.ts
+++ b/src/routes/routes.ts
@@ -16,6 +16,7 @@ export const Routes = {
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',
@@ -70,9 +71,12 @@ export const matchSharedWithMeRoute = (route: string) =>
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
diff --git a/src/services/repositories-service/repositories-service.ts b/src/services/repositories-service/repositories-service.ts
new file mode 100644
index 0000000..4bc6602
--- /dev/null
+++ b/src/services/repositories-service/repositories-service.ts
@@ -0,0 +1,22 @@
+// 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
diff --git a/src/services/services.ts b/src/services/services.ts
index 5adf10b..2bc955f 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -24,6 +24,7 @@ import { ApiActions } from "~/services/api/api-actions";
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>;
@@ -42,6 +43,7 @@ export const createServices = (config: Config, actions: ApiActions) => {
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);
@@ -68,6 +70,7 @@ export const createServices = (config: Config, actions: ApiActions) => {
logService,
permissionService,
projectService,
+ repositoriesService,
searchService,
tagService,
userService,
diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts
index 32bc47b..a59f376 100644
--- a/src/store/context-menu/context-menu-actions.ts
+++ b/src/store/context-menu/context-menu-actions.ts
@@ -12,7 +12,6 @@ import { ProjectResource } from '~/models/project';
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({
@@ -60,6 +59,17 @@ export const openCollectionFilesContextMenu = (event: React.MouseEvent<HTMLEleme
}));
};
+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);
diff --git a/src/store/navigation/navigation-action.ts b/src/store/navigation/navigation-action.ts
index b63fc2c..ce59969 100644
--- a/src/store/navigation/navigation-action.ts
+++ b/src/store/navigation/navigation-action.ts
@@ -61,3 +61,5 @@ export const navigateToSharedWithMe = push(Routes.SHARED_WITH_ME);
export const navigateToRunProcess = push(Routes.RUN_PROCESS);
export const navigateToSearchResults = push(Routes.SEARCH_RESULTS);
+
+export const navigateToRepositories = push(Routes.REPOSITORIES);
diff --git a/src/store/repositories/repositories-actions.ts b/src/store/repositories/repositories-actions.ts
new file mode 100644
index 0000000..7f953b8
--- /dev/null
+++ b/src/store/repositories/repositories-actions.ts
@@ -0,0 +1,36 @@
+// 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
diff --git a/src/store/repositories/repositories-reducer.ts b/src/store/repositories/repositories-reducer.ts
new file mode 100644
index 0000000..f277c31
--- /dev/null
+++ b/src/store/repositories/repositories-reducer.ts
@@ -0,0 +1,20 @@
+// 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
diff --git a/src/store/store.ts b/src/store/store.ts
index fa2a5be..5e648c9 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -43,6 +43,7 @@ import { searchBarReducer } from './search-bar/search-bar-reducer';
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' &&
@@ -111,5 +112,6 @@ const createRootReducer = (services: ServiceRepository) => combineReducers({
progressIndicator: progressIndicatorReducer,
runProcessPanel: runProcessPanelReducer,
appInfo: appInfoReducer,
- searchBar: searchBarReducer
+ searchBar: searchBarReducer,
+ repositories: repositoriesReducer
});
diff --git a/src/store/workbench/workbench-actions.ts b/src/store/workbench/workbench-actions.ts
index aaf8f26..c6440fd 100644
--- a/src/store/workbench/workbench-actions.ts
+++ b/src/store/workbench/workbench-actions.ts
@@ -3,23 +3,23 @@
// 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';
@@ -27,21 +27,21 @@ import * as collectionCreateActions from '~/store/collections/collection-create-
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';
@@ -53,6 +53,7 @@ import { collectionPanelActions } from "~/store/collection-panel/collection-pane
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';
@@ -390,6 +391,12 @@ export const loadSearchResults = handleFirstTimeLoad(
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;
diff --git a/src/views-components/context-menu/action-sets/repository-action-set.ts b/src/views-components/context-menu/action-sets/repository-action-set.ts
new file mode 100644
index 0000000..2f3a985
--- /dev/null
+++ b/src/views-components/context-menu/action-sets/repository-action-set.ts
@@ -0,0 +1,34 @@
+// 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));
+ }
+}]];
diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx
index b6d2b91..30ecc98 100644
--- a/src/views-components/context-menu/context-menu.tsx
+++ b/src/views-components/context-menu/context-menu.tsx
@@ -68,5 +68,6 @@ export enum ContextMenuKind {
TRASHED_COLLECTION = 'TrashedCollection',
PROCESS = "Process",
PROCESS_RESOURCE = 'ProcessResource',
- PROCESS_LOGS = "ProcessLogs"
+ PROCESS_LOGS = "ProcessLogs",
+ REPOSITORY = "Repository"
}
diff --git a/src/views-components/main-app-bar/account-menu.tsx b/src/views-components/main-app-bar/account-menu.tsx
index fdd8123..c643fef 100644
--- a/src/views-components/main-app-bar/account-menu.tsx
+++ b/src/views-components/main-app-bar/account-menu.tsx
@@ -10,7 +10,8 @@ import { UserPanelIcon } from "~/components/icon/icon";
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;
@@ -30,6 +31,7 @@ export const AccountMenu = connect(mapStateToProps)(
<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>
diff --git a/src/views-components/main-content-bar/main-content-bar.tsx b/src/views-components/main-content-bar/main-content-bar.tsx
index b047837..2039f6b 100644
--- a/src/views-components/main-content-bar/main-content-bar.tsx
+++ b/src/views-components/main-content-bar/main-content-bar.tsx
@@ -6,10 +6,9 @@ import * as React from "react";
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 {
@@ -23,8 +22,14 @@ const isWorkflowPath = ({ router }: RootState) => {
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) =>
@@ -34,11 +39,11 @@ export const MainContentBar = connect((state: RootState) => ({
<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>);
diff --git a/src/views/repositories-panel/repositories-panel.tsx b/src/views/repositories-panel/repositories-panel.tsx
new file mode 100644
index 0000000..3d2d32c
--- /dev/null
+++ b/src/views/repositories-panel/repositories-panel.tsx
@@ -0,0 +1,150 @@
+// 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
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 8d1fb67..d0509d0 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -48,6 +48,7 @@ import { SharingDialog } from '~/views-components/sharing-dialog/sharing-dialog'
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';
@@ -117,6 +118,7 @@ export const WorkbenchPanel =
<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>
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list