import { History, Location } from 'history';
import { RootStore } from '~/store/store';
-import { matchProcessRoute, matchProcessLogRoute, matchProjectRoute, matchCollectionRoute, matchFavoritesRoute, matchTrashRoute, matchRootRoute } from './routes';
+import { matchProcessRoute, matchProcessLogRoute, matchProjectRoute, matchCollectionRoute, matchFavoritesRoute, matchTrashRoute, matchRootRoute, matchSharedWithMeRoute } from './routes';
import { loadProject, loadCollection, loadFavorites, loadTrash, loadProcess, loadProcessLog } from '~/store/workbench/workbench-actions';
import { navigateToRootProject } from '~/store/navigation/navigation-action';
+import { navigateToSharedWithMe } from '../store/navigation/navigation-action';
+import { loadSharedWithMe } from '../store/workbench/workbench-actions';
export const addRouteChangeHandlers = (history: History, store: RootStore) => {
const handler = handleLocationChange(store);
const trashMatch = matchTrashRoute(pathname);
const processMatch = matchProcessRoute(pathname);
const processLogMatch = matchProcessLogRoute(pathname);
-
+ const sharedWithMeMatch = matchSharedWithMeRoute(pathname);
+
if (projectMatch) {
store.dispatch(loadProject(projectMatch.params.id));
} else if (collectionMatch) {
store.dispatch(loadProcessLog(processLogMatch.params.id));
} else if (rootMatch) {
store.dispatch(navigateToRootProject);
+ } else if (sharedWithMeMatch) {
+ store.dispatch(loadSharedWithMe);
}
};
PROCESSES: `/processes/:id(${RESOURCE_UUID_PATTERN})`,
FAVORITES: '/favorites',
TRASH: '/trash',
- PROCESS_LOGS: `/process-logs/:id(${RESOURCE_UUID_PATTERN})`
+ PROCESS_LOGS: `/process-logs/:id(${RESOURCE_UUID_PATTERN})`,
+ SHARED_WITH_ME: '/shared-with-me',
};
export const getResourceUrl = (uuid: string) => {
export const matchProcessLogRoute = (route: string) =>
matchPath<ResourceRouteParams>(route, { path: Routes.PROCESS_LOGS });
+
+export const matchSharedWithMeRoute = (route: string) =>
+ matchPath(route, { path: Routes.SHARED_WITH_ME });
if (rootProjectUuid) {
dispatch(navigateToProject(rootProjectUuid));
}
-};
\ No newline at end of file
+};
+
+export const navigateToSharedWithMe = push(Routes.SHARED_WITH_ME);
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { DataExplorerMiddlewareService } from '../data-explorer/data-explorer-middleware-service';
+import { RootState } from "../store";
+import { ServiceRepository } from "~/services/services";
+import { Dispatch, MiddlewareAPI } from "redux";
+
+export class SharedWithMeMiddlewareService extends DataExplorerMiddlewareService {
+ constructor(private services: ServiceRepository, id: string) {
+ super(id);
+ }
+
+ async requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
+ return;
+ }
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { bindDataExplorerActions } from "../data-explorer/data-explorer-action";
+import { Dispatch } from 'redux';
+import { ServiceRepository } from "~/services/services";
+import { RootState } from '~/store/store';
+
+export const SHARED_WITH_ME_PANEL_ID = "sharedWithMePanel";
+export const sharedWithMePanelActions = bindDataExplorerActions(SHARED_WITH_ME_PANEL_ID);
+
+export const loadSharedWithMePanel = () =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(sharedWithMePanelActions.REQUEST_ITEMS());
+ };
+
+
import { Dispatch } from 'redux';
import { isSidePanelTreeCategory, SidePanelTreeCategory } from '~/store/side-panel-tree/side-panel-tree-actions';
-import { navigateToFavorites, navigateTo, navigateToTrash } from '../navigation/navigation-action';
+import { navigateToFavorites, navigateTo, navigateToTrash, navigateToSharedWithMe } from '../navigation/navigation-action';
import { snackbarActions } from '~/store/snackbar/snackbar-actions';
export const navigateFromSidePanel = (id: string) =>
return navigateToFavorites;
case SidePanelTreeCategory.TRASH:
return navigateToTrash;
+ case SidePanelTreeCategory.SHARED_WITH_ME:
+ return navigateToSharedWithMe;
default:
return sidePanelTreeCategoryNotAvailable(id);
}
import { TRASH_PANEL_ID } from "~/store/trash-panel/trash-panel-action";
import { processLogsPanelReducer } from './process-logs-panel/process-logs-panel-reducer';
import { processPanelReducer } from '~/store/process-panel/process-panel-reducer';
+import { SHARED_WITH_ME_PANEL_ID } from '~/store/shared-with-me-panel/shared-with-me-panel-actions';
+import { SharedWithMeMiddlewareService } from './shared-with-me-panel/shared-with-me-middleware-service';
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
const trashPanelMiddleware = dataExplorerMiddleware(
new TrashPanelMiddlewareService(services, TRASH_PANEL_ID)
);
+ const sharedWithMePanelMiddleware = dataExplorerMiddleware(
+ new SharedWithMeMiddlewareService(services, SHARED_WITH_ME_PANEL_ID)
+ );
const middlewares: Middleware[] = [
routerMiddleware(history),
thunkMiddleware.withExtraArgument(services),
projectPanelMiddleware,
favoritePanelMiddleware,
- trashPanelMiddleware
+ trashPanelMiddleware,
+ sharedWithMePanelMiddleware,
];
const enhancer = composeEnhancers(applyMiddleware(...middlewares));
return createStore(rootReducer, enhancer);
import { loadTrashPanel, trashPanelActions } from "~/store/trash-panel/trash-panel-action";
import { initProcessLogsPanel } from '../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';
export const loadWorkbench = () =>
dispatch(projectPanelActions.SET_COLUMNS({ columns: projectPanelColumns }));
dispatch(favoritePanelActions.SET_COLUMNS({ columns: favoritePanelColumns }));
dispatch(trashPanelActions.SET_COLUMNS({ columns: trashPanelColumns }));
+ dispatch(sharedWithMePanelActions.SET_COLUMNS({ columns: projectPanelColumns }));
dispatch<any>(initSidePanelTree());
if (router.location) {
const match = matchRootRoute(router.location.pathname);
await dispatch<any>(activateSidePanelTreeItem(process.containerRequest.ownerUuid));
dispatch<any>(setProcessBreadcrumbs(uuid));
dispatch(loadDetailsPanel(uuid));
-
+
};
export const loadProcessLog = (uuid: string) =>
dispatch<any>(loadProject(currentProjectPanelUuid));
}
};
+
+export const loadSharedWithMe = (dispatch: Dispatch) => {
+ dispatch<any>(activateSidePanelTreeItem(SidePanelTreeCategory.SHARED_WITH_ME));
+ dispatch<any>(loadSharedWithMePanel());
+ dispatch<any>(setSidePanelBreadcrumbs(SidePanelTreeCategory.SHARED_WITH_ME));
+};
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
+import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
+import { connect, DispatchProp } from 'react-redux';
+import { RootState } from '~/store/store';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { ShareMeIcon } from '~/components/icon/icon';
+import { ResourcesState } from "~/store/resources/resources";
+import { navigateTo } from "~/store/navigation/navigation-action";
+import { loadDetailsPanel } from "~/store/details-panel/details-panel-action";
+import { PanelDefaultView } from '~/components/panel-default-view/panel-default-view';
+import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
+import { SHARED_WITH_ME_PANEL_ID } from '~/store/shared-with-me-panel/shared-with-me-panel-actions';
+
+type CssRules = "toolbar" | "button";
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ toolbar: {
+ paddingBottom: theme.spacing.unit * 3,
+ textAlign: "right"
+ },
+ button: {
+ marginLeft: theme.spacing.unit
+ },
+});
+
+interface SharedWithMePanelDataProps {
+ resources: ResourcesState;
+}
+
+type SharedWithMePanelProps = SharedWithMePanelDataProps & DispatchProp & WithStyles<CssRules>;
+
+export const SharedWithMePanel = withStyles(styles)(
+ connect((state: RootState) => ({
+ resources: state.resources
+ }))(
+ class extends React.Component<SharedWithMePanelProps> {
+ render() {
+ return this.hasAnyTrashedResources()
+ ? <DataExplorer
+ id={SHARED_WITH_ME_PANEL_ID}
+ onRowClick={this.handleRowClick}
+ onRowDoubleClick={this.handleRowDoubleClick}
+ onContextMenu={this.handleContextMenu}
+ contextMenuColumn={false}
+ dataTableDefaultView={<DataTableDefaultView icon={ShareMeIcon} />} />
+ : <PanelDefaultView
+ icon={ShareMeIcon}
+ messages={['No shared items.']} />;
+ }
+
+ hasAnyTrashedResources = () => {
+ // TODO: implement check if there is anything in the trash,
+ // without taking pagination into the account
+ return false;
+ }
+
+ handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
+ // const resource = getResource<TrashableResource>(resourceUuid)(this.props.resources);
+ // if (resource) {
+ // this.props.dispatch<any>(openContextMenu(event, {
+ // name: '',
+ // uuid: resource.uuid,
+ // ownerUuid: resource.ownerUuid,
+ // isTrashed: resource.isTrashed,
+ // kind: resource.kind,
+ // menuKind: ContextMenuKind.TRASH
+ // }));
+ // }
+ }
+
+ handleRowDoubleClick = (uuid: string) => {
+ this.props.dispatch<any>(navigateTo(uuid));
+ }
+
+ handleRowClick = (uuid: string) => {
+ this.props.dispatch(loadDetailsPanel(uuid));
+ }
+ }
+ )
+);
import { TrashPanel } from "~/views/trash-panel/trash-panel";
import { MainContentBar } from '../../views-components/main-content-bar/main-content-bar';
import { Grid } from '@material-ui/core';
+import { SharedWithMePanel } from '../shared-with-me-panel/shared-with-me-panel';
type CssRules = 'root' | 'contentWrapper' | 'content' | 'appBar';
<Route path={Routes.PROCESSES} component={ProcessPanel} />
<Route path={Routes.TRASH} component={TrashPanel} />
<Route path={Routes.PROCESS_LOGS} component={ProcessLogPanel} />
+ <Route path={Routes.SHARED_WITH_ME} component={SharedWithMePanel} />
</Switch>
</Grid>
</Grid>