{
name: "Column 1",
render: () => <span />,
-- selected: true
++ selected: true,
++ configurable: true
},
{
name: "Column 2",
{
name: "Column 1",
render: () => <span />,
-- selected: true
++ selected: true,
++ configurable: true
},
{
name: "Column 2",
render: () => <span />,
-- selected: false
++ selected: false,
++ configurable: true
},
{
name: "Column 3",
render: () => <span />,
-- selected: true
++ selected: true,
++ configurable: true
}
];
const columnsConfigurator = mount(<ColumnSelector columns={columns} onColumnToggle={jest.fn()} />);
{
name: "Column 1",
render: () => <span />,
-- selected: true
++ selected: true,
++ configurable: true
}
];
const onColumnToggle = jest.fn();
--- /dev/null
-import { MiddlewareAPI } from "../../../node_modules/redux";
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+
+ import { DataExplorerMiddlewareService } from "./data-explorer-middleware-service";
+ import { dataExplorerMiddleware } from "./data-explorer-middleware";
-
- it("initializes columns in the store", () => {
- const config = {
- id: "Id",
- columns: [{
- name: "Column",
- selected: true,
- configurable: false,
- render: jest.fn()
- }],
- requestItems: jest.fn(),
- setApi: jest.fn()
- };
- const service = new ServiceMock(config);
- const api = {
- getState: jest.fn(),
- dispatch: jest.fn()
- };
- const next = jest.fn();
- dataExplorerMiddleware(service)(api)(next);
- expect(next)
- .toHaveBeenCalledWith(dataExplorerActions.SET_COLUMNS({ id: service.getId(), columns: service.getColumns() }));
- });
-
++import { MiddlewareAPI } from "redux";
+ import { DataColumns } from "../../components/data-table/data-table";
+ import { dataExplorerActions } from "./data-explorer-action";
+
+
+ describe("DataExplorerMiddleware", () => {
- expect(next).toHaveBeenCalledTimes(4);
++
+ it("handles only actions that are identified by service id", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [{
+ name: "Column",
+ selected: true,
+ configurable: false,
+ render: jest.fn()
+ }],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.SET_PAGE({ id: "OtherId", page: 0 }));
+ middleware(dataExplorerActions.SET_PAGE({ id: "ServiceId", page: 0 }));
+ middleware(dataExplorerActions.SET_PAGE({ id: "OtherId", page: 0 }));
+ expect(api.dispatch).toHaveBeenCalledWith(dataExplorerActions.REQUEST_ITEMS({ id: "ServiceId" }));
+ expect(api.dispatch).toHaveBeenCalledTimes(1);
+ });
+
+ it("handles REQUEST_ITEMS action", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [{
+ name: "Column",
+ selected: true,
+ configurable: false,
+ render: jest.fn()
+ }],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.REQUEST_ITEMS({ id: "ServiceId" }));
+ expect(config.requestItems).toHaveBeenCalled();
+ });
+
+ it("handles SET_PAGE action", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.SET_PAGE({ id: service.getId(), page: 0 }));
+ expect(api.dispatch).toHaveBeenCalledTimes(1);
+ });
+
+ it("handles SET_ROWS_PER_PAGE action", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.SET_ROWS_PER_PAGE({ id: service.getId(), rowsPerPage: 0 }));
+ expect(api.dispatch).toHaveBeenCalledTimes(1);
+ });
+
+ it("handles SET_FILTERS action", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.SET_FILTERS({ id: service.getId(), columnName: "", filters: [] }));
+ expect(api.dispatch).toHaveBeenCalledTimes(2);
+ });
+
+ it("handles SET_ROWS_PER_PAGE action", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.SET_ROWS_PER_PAGE({ id: service.getId(), rowsPerPage: 0 }));
+ expect(api.dispatch).toHaveBeenCalledTimes(1);
+ });
+
+ it("handles TOGGLE_SORT action", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.TOGGLE_SORT({ id: service.getId(), columnName: "" }));
+ expect(api.dispatch).toHaveBeenCalledTimes(1);
+ });
+
+ it("handles SET_SEARCH_VALUE action", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.SET_SEARCH_VALUE({ id: service.getId(), searchValue: "" }));
+ expect(api.dispatch).toHaveBeenCalledTimes(2);
+ });
+
+ it("forwards other actions", () => {
+ const config = {
+ id: "ServiceId",
+ columns: [],
+ requestItems: jest.fn(),
+ setApi: jest.fn()
+ };
+ const service = new ServiceMock(config);
+ const api = {
+ getState: jest.fn(),
+ dispatch: jest.fn()
+ };
+ const next = jest.fn();
+ const middleware = dataExplorerMiddleware(service)(api)(next);
+ middleware(dataExplorerActions.SET_COLUMNS({ id: service.getId(), columns: [] }));
+ middleware(dataExplorerActions.SET_ITEMS({ id: service.getId(), items: [], rowsPerPage: 0, itemsAvailable: 0, page: 0 }));
+ middleware(dataExplorerActions.TOGGLE_COLUMN({ id: service.getId(), columnName: "" }));
+ expect(api.dispatch).toHaveBeenCalledTimes(0);
- requestItems: (api: MiddlewareAPI) => void;
- setApi: () => void;
++ expect(next).toHaveBeenCalledTimes(3);
+ });
+
+ });
+
+ class ServiceMock extends DataExplorerMiddlewareService {
+ constructor(private config: {
+ id: string,
+ columns: DataColumns<any>,
++ requestItems: (api: MiddlewareAPI) => void
+ }) {
+ super(config.id);
+ }
+
+ getColumns() {
+ return this.config.columns;
+ }
+
+ requestItems(api: MiddlewareAPI) {
+ this.config.requestItems(api);
+ }
+ }
import { push } from "react-router-redux";
import { TreeItemStatus } from "../../components/tree/tree";
import { findTreeItem } from "../project/project-reducer";
- import { dataExplorerActions } from "../data-explorer/data-explorer-action";
- import { PROJECT_PANEL_ID } from "../../views/project-panel/project-panel";
import { RootState } from "../store";
import { Resource, ResourceKind } from "../../models/resource";
+ import { projectPanelActions } from "../project-panel/project-panel-action";
+import { getCollectionUrl } from "../../models/collection";
+import { getProjectUrl } from "../../models/project";
export const getResourceUrl = <T extends Resource>(resource: T): string => {
switch (resource.kind) {
import { reducer as formReducer } from 'redux-form';
import { FavoritesState, favoritesReducer } from './favorites/favorites-reducer';
import { snackbarReducer, SnackbarState } from './snackbar/snackbar-reducer';
+ import { dataExplorerMiddleware } from "./data-explorer/data-explorer-middleware";
+ import { FAVORITE_PANEL_ID } from "./favorite-panel/favorite-panel-action";
+ import { PROJECT_PANEL_ID } from "./project-panel/project-panel-action";
+ import { ProjectPanelMiddlewareService } from "./project-panel/project-panel-middleware-service";
+ import { FavoritePanelMiddlewareService } from "./favorite-panel/favorite-panel-middleware-service";
+import { CollectionCreatorState, collectionCreationReducer } from './collections/creator/collection-creator-reducer';
+import { CollectionPanelState, collectionPanelReducer } from './collection-panel/collection-panel-reducer';
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
--- /dev/null
- import { FAVORITE_PANEL_ID } from "../../../views/favorite-panel/favorite-panel";
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContextMenuActionSet } from "../context-menu-action-set";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
+import { toggleFavorite } from "../../../store/favorites/favorites-actions";
+import { dataExplorerActions } from "../../../store/data-explorer/data-explorer-action";
- dispatch<any>(dataExplorerActions.REQUEST_ITEMS({ id: FAVORITE_PANEL_ID }));
+import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, ProvenanceGraphIcon, AdvancedIcon, RemoveIcon } from "../../../components/icon/icon";
++import { favoritePanelActions } from "../../../store/favorite-panel/favorite-panel-action";
+
+export const collectionActionSet: ContextMenuActionSet = [[
+ {
+ icon: RenameIcon,
+ name: "Edit collection",
+ execute: (dispatch, resource) => {
+ // add code
+ }
+ },
+ {
+ icon: ShareIcon,
+ name: "Share",
+ execute: (dispatch, resource) => {
+ // add code
+ }
+ },
+ {
+ icon: MoveToIcon,
+ name: "Move to",
+ execute: (dispatch, resource) => {
+ // add code
+ }
+ },
+ {
+ component: ToggleFavoriteAction,
+ execute: (dispatch, resource) => {
+ dispatch<any>(toggleFavorite(resource)).then(() => {
++ dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
+ });
+ }
+ },
+ {
+ icon: CopyIcon,
+ name: "Copy to project",
+ execute: (dispatch, resource) => {
+ // add code
+ }
+ },
+ {
+ icon: DetailsIcon,
+ name: "View details",
+ execute: (dispatch, resource) => {
+ // add code
+ }
+ },
+ {
+ icon: ProvenanceGraphIcon,
+ name: "Provenance graph",
+ execute: (dispatch, resource) => {
+ // add code
+ }
+ },
+ {
+ icon: AdvancedIcon,
+ name: "Advanced",
+ execute: (dispatch, resource) => {
+ // add code
+ }
+ },
+ {
+ icon: RemoveIcon,
+ name: "Remove",
+ execute: (dispatch, resource) => {
+ // add code
+ }
+ }
+]];
// SPDX-License-Identifier: AGPL-3.0
import { ContextMenuActionSet } from "../context-menu-action-set";
-import { ToggleFavoriteAction } from "./favorite-action";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
import { toggleFavorite } from "../../../store/favorites/favorites-actions";
- import { dataExplorerActions } from "../../../store/data-explorer/data-explorer-action";
- import { FAVORITE_PANEL_ID } from "../../../views/favorite-panel/favorite-panel";
+ import { favoritePanelActions } from "../../../store/favorite-panel/favorite-panel-action";
export const favoriteActionSet: ContextMenuActionSet = [[{
component: ToggleFavoriteAction,
import { ContextMenuActionSet } from "../context-menu-action-set";
import { projectActions } from "../../../store/project/project-action";
import { NewProjectIcon } from "../../../components/icon/icon";
-import { ToggleFavoriteAction } from "./favorite-action";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
import { toggleFavorite } from "../../../store/favorites/favorites-actions";
- import { dataExplorerActions } from "../../../store/data-explorer/data-explorer-action";
- import { FAVORITE_PANEL_ID } from "../../../views/favorite-panel/favorite-panel";
+ import { favoritePanelActions } from "../../../store/favorite-panel/favorite-panel-action";
export const projectActionSet: ContextMenuActionSet = [[{
icon: NewProjectIcon,
import { RootState } from "../../store/store";
import { DialogProjectCreate } from "../dialog-create/dialog-project-create";
import { projectActions, createProject, getProjectList } from "../../store/project/project-action";
- import { dataExplorerActions } from "../../store/data-explorer/data-explorer-action";
- import { PROJECT_PANEL_ID } from "../../views/project-panel/project-panel";
+ import { projectPanelActions } from "../../store/project-panel/project-panel-action";
+import { snackbarActions } from "../../store/snackbar/snackbar-actions";
const mapStateToProps = (state: RootState) => ({
open: state.projects.creator.opened
(dispatch: Dispatch, getState: () => RootState) => {
const { ownerUuid } = getState().projects.creator;
return dispatch<any>(createProject(data)).then(() => {
- dispatch(dataExplorerActions.REQUEST_ITEMS({ id: PROJECT_PANEL_ID }));
+ dispatch(snackbarActions.OPEN_SNACKBAR({
+ message: "Created a new project",
+ hideDuration: 2000
+ }));
+ dispatch(projectPanelActions.REQUEST_ITEMS());
dispatch<any>(getProjectList(ownerUuid));
});
};
import { SortDirection } from '../../components/data-table/data-column';
import { ResourceKind } from '../../models/resource';
import { resourceLabel } from '../../common/labels';
- import { ProjectIcon, CollectionIcon, ProcessIcon, DefaultIcon, FavoriteIcon } from '../../components/icon/icon';
import { ArvadosTheme } from '../../common/custom-theme';
- import { FavoriteStar } from '../../views-components/favorite-star/favorite-star';
+ import { renderName, renderStatus, renderType, renderOwner, renderFileSize, renderDate } from '../../views-components/data-explorer/renderers';
-import { PROJECT_PANEL_ID } from "../../store/project-panel/project-panel-action";
type CssRules = "toolbar" | "button";
import { ProjectResource } from '../../models/project';
import { ResourceKind } from '../../models/resource';
import { ContextMenu, ContextMenuKind } from "../../views-components/context-menu/context-menu";
- import { FavoritePanel, FAVORITE_PANEL_ID } from "../favorite-panel/favorite-panel";
+ import { FavoritePanel } from "../favorite-panel/favorite-panel";
import { CurrentTokenDialog } from '../../views-components/current-token-dialog/current-token-dialog';
+import { dataExplorerActions } from '../../store/data-explorer/data-explorer-action';
import { Snackbar } from '../../views-components/snackbar/snackbar';
+ import { favoritePanelActions } from '../../store/favorite-panel/favorite-panel-action';
+import { CreateCollectionDialog } from '../../views-components/create-collection-dialog/create-collection-dialog';
+import { CollectionPanel } from '../collection-panel/collection-panel';
+import { loadCollection } from '../../store/collection-panel/collection-panel-action';
+import { getCollectionUrl } from '../../models/collection';
const drawerWidth = 240;
const appBarHeight = 100;