Arvados-DCO-1.1-Signed-off-by: Daniel Kutyła <daniel.kutyla@contractors.roche.com>1~
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export const sortByProperty = (propName: string) => (obj1: any, obj2: any) => {
+ const prop1 = obj1[propName];
+ const prop2 = obj2[propName];
+
+ if (prop1 > prop2) {
+ return 1;
+ }
+
+ if (prop1 < prop2) {
+ return -1;
+ }
+
+ return 0;
+};
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+const STORE_COPY_KEY = 'storeCopy';
+
+export const copyStore = (store: any) => {
+ const { localStorage } = window;
+ const state = store.getState();
+ const storeCopy = JSON.parse(JSON.stringify(state));
+ storeCopy.router.location.pathname = '/';
+
+ if (localStorage) {
+ localStorage.setItem(STORE_COPY_KEY, JSON.stringify(storeCopy));
+ }
+};
+
+export const restoreStore = () => {
+ let storeCopy = null;
+ const { localStorage } = window;
+
+ if (localStorage && localStorage.getItem(STORE_COPY_KEY)) {
+ storeCopy = localStorage.getItem(STORE_COPY_KEY);
+ localStorage.removeItem(STORE_COPY_KEY);
+ }
+
+ return storeCopy;
+};
import { Config } from './config';
const REDIRECT_TO_KEY = 'redirectTo';
+export const REDIRECT_TO_APPLY_TO_PATH = 'redirectToApplyToPath';
export const storeRedirects = () => {
- if (window.location.href.indexOf(REDIRECT_TO_KEY) > -1) {
- const { location: { href }, localStorage } = window;
- const redirectUrl = href.split(`${REDIRECT_TO_KEY}=`)[1];
+ let redirectUrl;
+ const { location: { href }, localStorage } = window;
+ const applyToPath = href.indexOf(REDIRECT_TO_APPLY_TO_PATH) > -1;
- if (localStorage) {
- localStorage.setItem(REDIRECT_TO_KEY, redirectUrl);
+ if (href.indexOf(REDIRECT_TO_KEY) > -1) {
+ redirectUrl = href.split(`${REDIRECT_TO_KEY}=`)[1];
+ }
+
+ if (localStorage && redirectUrl) {
+ localStorage.setItem(REDIRECT_TO_KEY, redirectUrl);
+
+ if (applyToPath) {
+ localStorage.setItem(REDIRECT_TO_APPLY_TO_PATH, 'true');
}
}
};
if (localStorage && localStorage.getItem(REDIRECT_TO_KEY)) {
const redirectUrl = localStorage.getItem(REDIRECT_TO_KEY);
localStorage.removeItem(REDIRECT_TO_KEY);
+ const applyToPath = localStorage.getItem(REDIRECT_TO_APPLY_TO_PATH);
+
if (redirectUrl) {
- const sep = redirectUrl.indexOf("?") > -1 ? "&" : "?";
- window.location.href = `${keepWebServiceUrl}${redirectUrl}${sep}api_token=${token}`;
+ if (applyToPath === 'true') {
+ localStorage.removeItem(REDIRECT_TO_APPLY_TO_PATH);
+ setTimeout(() => {
+ window.location.pathname = redirectUrl;
+ }, 0);
+ } else {
+ const sep = redirectUrl.indexOf("?") > -1 ? "&" : "?";
+ window.location.href = `${keepWebServiceUrl}${redirectUrl}${sep}api_token=${token}`;
+ }
}
}
};
//
// SPDX-License-Identifier: AGPL-3.0
-import { Dispatch } from 'redux';
+import * as copy from 'copy-to-clipboard';
import { ResourceKind } from '~/models/resource';
-import { unionize, ofType } from '~/common/unionize';
+import { getClipboardUrl } from '~/views-components/context-menu/actions/helpers';
-export const openInNewTabActions = unionize({
- COPY_STORE: ofType<{}>(),
- OPEN_COLLECTION_IN_NEW_TAB: ofType<string>(),
- OPEN_PROJECT_IN_NEW_TAB: ofType<string>()
-});
-
-export const openInNewTabAction = (resource: any) => (dispatch: Dispatch) => {
+const getUrl = (resource: any) => {
+ let url = null;
const { uuid, kind } = resource;
- dispatch(openInNewTabActions.COPY_STORE());
-
if (kind === ResourceKind.COLLECTION) {
- dispatch(openInNewTabActions.OPEN_COLLECTION_IN_NEW_TAB(uuid));
- } else if (kind === ResourceKind.PROJECT) {
- dispatch(openInNewTabActions.OPEN_PROJECT_IN_NEW_TAB(uuid));
+ url = `/collections/${uuid}`;
+ }
+ if (kind === ResourceKind.PROJECT) {
+ url = `/projects/${uuid}`;
+ }
+
+ return url;
+};
+
+export const openInNewTabAction = (resource: any) => () => {
+ const url = getUrl(resource);
+
+ if (url) {
+ window.open(`${window.location.origin}${url}`, '_blank');
+ }
+};
+
+export const copyToClipboardAction = (resource: any) => () => {
+ const url = getUrl(resource);
+
+ if (url) {
+ copy(getClipboardUrl(url, false));
}
};
\ No newline at end of file
collectionsContentAddress,
subprocessMiddleware,
];
+
const enhancer = composeEnhancers(applyMiddleware(redirectToMiddleware, ...middlewares));
return createStore(rootReducer, enhancer);
}
{value === 4 && dialogContent(curlHeader, curlExample, classes)}
</DialogContent>
<DialogActions>
- <Button variant='text' color='primary' onClick={closeDialog}>
+ <Button data-cy="close-advanced-dialog" variant='text' color='primary' onClick={closeDialog}>
Close
</Button>
</DialogActions>
import { ContextMenuActionSet } from "../context-menu-action-set";
import { ToggleFavoriteAction } from "../actions/favorite-action";
import { toggleFavorite } from "~/store/favorites/favorites-actions";
-import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, AdvancedIcon } from "~/components/icon/icon";
+import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, AdvancedIcon, OpenIcon, Link } from "~/components/icon/icon";
import { openCollectionUpdateDialog } from "~/store/collections/collection-update-actions";
import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
import { openMoveCollectionDialog } from '~/store/collections/collection-move-actions';
import { openSharingDialog } from '~/store/sharing-dialog/sharing-dialog-actions';
import { openAdvancedTabDialog } from "~/store/advanced-tab/advanced-tab";
import { toggleDetailsPanel } from '~/store/details-panel/details-panel-action';
+import { copyToClipboardAction, openInNewTabAction } from "~/store/open-in-new-tab/open-in-new-tab.actions";
export const readOnlyCollectionActionSet: ContextMenuActionSet = [[
{
component: ToggleFavoriteAction,
+ name: 'ToggleFavoriteAction',
execute: (dispatch, resource) => {
dispatch<any>(toggleFavorite(resource)).then(() => {
dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
});
}
},
+ {
+ icon: OpenIcon,
+ name: "Open in new tab",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openInNewTabAction(resource));
+ }
+ },
+ {
+ icon: Link,
+ name: "Copy to clipboard",
+ execute: (dispatch, resource) => {
+ dispatch<any>(copyToClipboardAction(resource));
+ }
+ },
{
icon: CopyIcon,
name: "Make a copy",
},
{
component: ToggleTrashAction,
+ name: 'ToggleTrashAction',
execute: (dispatch, resource) => {
dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!));
}
import { ContextMenuActionSet } from "../context-menu-action-set";
import { ToggleFavoriteAction } from "../actions/favorite-action";
import { toggleFavorite } from "~/store/favorites/favorites-actions";
-import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, AdvancedIcon } from "~/components/icon/icon";
+import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, AdvancedIcon, OpenIcon, Link } from "~/components/icon/icon";
import { openCollectionUpdateDialog } from "~/store/collections/collection-update-actions";
import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
import { openMoveCollectionDialog } from '~/store/collections/collection-move-actions';
import { TogglePublicFavoriteAction } from "~/views-components/context-menu/actions/public-favorite-action";
import { publicFavoritePanelActions } from "~/store/public-favorites-panel/public-favorites-action";
import { togglePublicFavorite } from "~/store/public-favorites/public-favorites-actions";
+import { copyToClipboardAction, openInNewTabAction } from "~/store/open-in-new-tab/open-in-new-tab.actions";
export const collectionAdminActionSet: ContextMenuActionSet = [[
{
dispatch<any>(openCollectionUpdateDialog(resource));
}
},
+ {
+ icon: OpenIcon,
+ name: "Open in new tab",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openInNewTabAction(resource));
+ }
+ },
+ {
+ icon: Link,
+ name: "Copy to clipboard",
+ execute: (dispatch, resource) => {
+ dispatch<any>(copyToClipboardAction(resource));
+ }
+ },
{
icon: ShareIcon,
name: "Share",
},
{
component: ToggleFavoriteAction,
+ name: 'ToggleFavoriteAction',
execute: (dispatch, resource) => {
dispatch<any>(toggleFavorite(resource)).then(() => {
dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
},
{
component: TogglePublicFavoriteAction,
+ name: 'TogglePublicFavoriteAction',
execute: (dispatch, resource) => {
dispatch<any>(togglePublicFavorite(resource)).then(() => {
dispatch<any>(publicFavoritePanelActions.REQUEST_ITEMS());
},
{
component: ToggleTrashAction,
+ name: 'ToggleTrashAction',
execute: (dispatch, resource) => {
dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!));
}
--- /dev/null
+// 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 { ToggleTrashAction } from "~/views-components/context-menu/actions/trash-action";
+import { toggleFavorite } from "~/store/favorites/favorites-actions";
+import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, AdvancedIcon, OpenIcon } from '~/components/icon/icon';
+import { openCollectionUpdateDialog } from "~/store/collections/collection-update-actions";
+import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
+import { openMoveCollectionDialog } from '~/store/collections/collection-move-actions';
+import { openCollectionCopyDialog } from '~/store/collections/collection-copy-actions';
+import { toggleCollectionTrashed } from "~/store/trash/trash-actions";
+import { openSharingDialog } from "~/store/sharing-dialog/sharing-dialog-actions";
+import { openAdvancedTabDialog } from '~/store/advanced-tab/advanced-tab';
+import { toggleDetailsPanel } from '~/store/details-panel/details-panel-action';
+import { openInNewTabAction } from "~/store/open-in-new-tab/open-in-new-tab.actions";
+
+export const collectionResourceActionSet: ContextMenuActionSet = [[
+ {
+ icon: RenameIcon,
+ name: "Edit collection",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openCollectionUpdateDialog(resource));
+ }
+ },
+ {
+ icon: ShareIcon,
+ name: "Share",
+ execute: (dispatch, { uuid }) => {
+ dispatch<any>(openSharingDialog(uuid));
+ }
+ },
+ {
+ component: ToggleFavoriteAction,
+ execute: (dispatch, resource) => {
+ dispatch<any>(toggleFavorite(resource)).then(() => {
+ dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
+ });
+ }
+ },
+ {
+ icon: OpenIcon,
+ name: "Open in new tab",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openInNewTabAction(resource));
+ }
+ },
+ {
+ icon: MoveToIcon,
+ name: "Move to",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openMoveCollectionDialog(resource));
+ }
+ },
+ {
+ icon: CopyIcon,
+ name: "Copy to project",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openCollectionCopyDialog(resource));
+ }
+ },
+ {
+ icon: DetailsIcon,
+ name: "View details",
+ execute: dispatch => {
+ dispatch<any>(toggleDetailsPanel());
+ }
+ },
+ {
+ icon: AdvancedIcon,
+ name: "Advanced",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openAdvancedTabDialog(resource.uuid));
+ }
+ },
+ {
+ component: ToggleTrashAction,
+ execute: (dispatch, resource) => {
+ dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!));
+ }
+ },
+ // {
+ // icon: RemoveIcon,
+ // name: "Remove",
+ // execute: (dispatch, resource) => {
+ // // add code
+ // }
+ // }
+]];
// SPDX-License-Identifier: AGPL-3.0
import { ContextMenuActionSet } from "../context-menu-action-set";
-import { NewProjectIcon, RenameIcon, MoveToIcon, DetailsIcon, AdvancedIcon } from '~/components/icon/icon';
+import { NewProjectIcon, RenameIcon, MoveToIcon, DetailsIcon, AdvancedIcon, OpenIcon, Link } from '~/components/icon/icon';
import { ToggleFavoriteAction } from "../actions/favorite-action";
import { toggleFavorite } from "~/store/favorites/favorites-actions";
import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
import { openSharingDialog } from "~/store/sharing-dialog/sharing-dialog-actions";
import { openAdvancedTabDialog } from "~/store/advanced-tab/advanced-tab";
import { toggleDetailsPanel } from '~/store/details-panel/details-panel-action';
+import { copyToClipboardAction, openInNewTabAction } from "~/store/open-in-new-tab/open-in-new-tab.actions";
export const readOnlyProjectActionSet: ContextMenuActionSet = [[
{
component: ToggleFavoriteAction,
+ name: 'ToggleFavoriteAction',
execute: (dispatch, resource) => {
dispatch<any>(toggleFavorite(resource)).then(() => {
dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
});
}
},
+ {
+ icon: OpenIcon,
+ name: "Open in new tab",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openInNewTabAction(resource));
+ }
+ },
+ {
+ icon: Link,
+ name: "Copy to clipboard",
+ execute: (dispatch, resource) => {
+ dispatch<any>(copyToClipboardAction(resource));
+ }
+ },
{
icon: DetailsIcon,
name: "View details",
},
{
component: ToggleTrashAction,
+ name: 'ToggleTrashAction',
execute: (dispatch, resource) => {
dispatch<any>(toggleProjectTrashed(resource.uuid, resource.ownerUuid, resource.isTrashed!!));
}
// SPDX-License-Identifier: AGPL-3.0
import { ContextMenuActionSet } from "../context-menu-action-set";
-import { NewProjectIcon, RenameIcon, MoveToIcon, DetailsIcon, AdvancedIcon } from '~/components/icon/icon';
+import { NewProjectIcon, RenameIcon, MoveToIcon, DetailsIcon, AdvancedIcon, OpenIcon, Link } from '~/components/icon/icon';
import { ToggleFavoriteAction } from "../actions/favorite-action";
import { toggleFavorite } from "~/store/favorites/favorites-actions";
import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
import { TogglePublicFavoriteAction } from "~/views-components/context-menu/actions/public-favorite-action";
import { togglePublicFavorite } from "~/store/public-favorites/public-favorites-actions";
import { publicFavoritePanelActions } from "~/store/public-favorites-panel/public-favorites-action";
+import { copyToClipboardAction, openInNewTabAction } from "~/store/open-in-new-tab/open-in-new-tab.actions";
export const projectAdminActionSet: ContextMenuActionSet = [[
{
dispatch<any>(openProjectCreateDialog(resource.uuid));
}
},
+ {
+ icon: OpenIcon,
+ name: "Open in new tab",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openInNewTabAction(resource));
+ }
+ },
+ {
+ icon: Link,
+ name: "Copy to clipboard",
+ execute: (dispatch, resource) => {
+ dispatch<any>(copyToClipboardAction(resource));
+ }
+ },
{
icon: RenameIcon,
name: "Edit project",
},
{
component: ToggleFavoriteAction,
+ name: 'ToggleFavoriteAction',
execute: (dispatch, resource) => {
dispatch<any>(toggleFavorite(resource)).then(() => {
dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
},
{
component: TogglePublicFavoriteAction,
+ name: 'TogglePublicFavoriteAction',
execute: (dispatch, resource) => {
dispatch<any>(togglePublicFavorite(resource)).then(() => {
dispatch<any>(publicFavoritePanelActions.REQUEST_ITEMS());
},
{
component: ToggleTrashAction,
+ name: 'ToggleTrashAction',
execute: (dispatch, resource) => {
dispatch<any>(toggleProjectTrashed(resource.uuid, resource.ownerUuid, resource.isTrashed!!));
}
//
// SPDX-License-Identifier: AGPL-3.0
-export const sanitizeToken = (href: string, tokenAsQueryParam: boolean = true): string => {
+import { REDIRECT_TO_APPLY_TO_PATH } from "~/common/redirect-to";
+
+export const sanitizeToken = (href: string, tokenAsQueryParam = true): string => {
const [prefix, suffix] = href.split('/t=');
const [token1, token2, token3, ...rest] = suffix.split('/');
const token = `${token1}/${token2}/${token3}`;
return `${[prefix, ...rest].join('/')}${tokenAsQueryParam ? `${sep}api_token=${token}` : ''}`;
};
-export const getClipboardUrl = (href: string): string => {
+export const getClipboardUrl = (href: string, shouldSanitizeToken = true): string => {
const { origin } = window.location;
- const url = sanitizeToken(href, false);
+ const url = shouldSanitizeToken ? sanitizeToken(href, false) : href;
- return `${origin}?redirectTo=${url}`;
+ return `${origin}${!shouldSanitizeToken ? `?${REDIRECT_TO_APPLY_TO_PATH}=true&` : `?`}redirectTo=${url}`;
};
import { ContextMenuActionSet, ContextMenuAction } from "./context-menu-action-set";
import { Dispatch } from "redux";
import { memoize } from 'lodash';
+import { sortByProperty } from "~/common/array-utils";
type DataProps = Pick<ContextMenuProps, "anchorEl" | "items" | "open"> & { resource?: ContextMenuResource };
const mapStateToProps = (state: RootState): DataProps => {
const { open, position, resource } = state.contextMenu;
const menuActionSets = new Map<string, ContextMenuActionSet>();
export const addMenuActionSet = (name: string, itemSet: ContextMenuActionSet) => {
- menuActionSets.set(name, itemSet);
+ const sorted = itemSet.map(items => items.sort(sortByProperty('name')));
+ menuActionSets.set(name, sorted);
};
const emptyActionSet: ContextMenuActionSet = [];