From 61295a30b00bcbe15d38886aa6391c2ddc6057e0 Mon Sep 17 00:00:00 2001 From: meganrm Date: Thu, 5 Oct 2023 11:46:43 -0700 Subject: [PATCH 1/5] change check for if a file is shareable --- .../ShareTrajectoryButton/index.tsx | 11 +++----- src/components/ShareTrajectoryModal/index.tsx | 22 +++++++-------- src/state/trajectory/types.ts | 1 + src/util/userUrlHandling.ts | 27 ++++++++++++------- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/components/ShareTrajectoryButton/index.tsx b/src/components/ShareTrajectoryButton/index.tsx index e26038f1..021675ef 100644 --- a/src/components/ShareTrajectoryButton/index.tsx +++ b/src/components/ShareTrajectoryButton/index.tsx @@ -2,15 +2,12 @@ import React from "react"; import { Button, Tooltip } from "antd"; import { TOOLTIP_COLOR } from "../../constants"; -import { - NetworkedSimFile, - LocalSimFile, - isLocalFileInterface, -} from "../../state/trajectory/types"; +import { NetworkedSimFile, LocalSimFile } from "../../state/trajectory/types"; import { Share } from "../Icons"; import ShareTrajectoryModal from "../ShareTrajectoryModal"; import styles from "./style.css"; +import { isOnlineTrajectory } from "../../util/userUrlHandling"; interface ShareTrajectoryButtonProps { simulariumFile: LocalSimFile | NetworkedSimFile; @@ -21,7 +18,7 @@ const ShareTrajectoryButton = ({ }: ShareTrajectoryButtonProps): JSX.Element => { const [isSharing, setIsSharing] = React.useState(false); - const isLocalFile = isLocalFileInterface(simulariumFile); + const trajectoryIsSharable = isOnlineTrajectory(location.href); const handleShare = () => { setIsSharing(!isSharing); @@ -42,7 +39,7 @@ const ShareTrajectoryButton = ({ {isSharing ? (
diff --git a/src/components/ShareTrajectoryModal/index.tsx b/src/components/ShareTrajectoryModal/index.tsx index da38ad2e..e10c64d1 100644 --- a/src/components/ShareTrajectoryModal/index.tsx +++ b/src/components/ShareTrajectoryModal/index.tsx @@ -17,14 +17,14 @@ import styles from "./style.css"; import theme from "../theme/light-theme.css"; interface ShareTrajectoryModalProps { - isLocalFile: boolean; + trajectoryIsSharable: boolean; closeModal: () => void; timeUnits: TimeUnits; displayTimes: DisplayTimes; } const ShareTrajectoryModal = ({ - isLocalFile, + trajectoryIsSharable, closeModal, timeUnits, displayTimes, @@ -102,7 +102,7 @@ const ShareTrajectoryModal = ({ }; const modalOptions = { - localFile: { + errorMessage: { content: ( <>

{Warn} The current file is stored on your device.

@@ -134,7 +134,7 @@ const ShareTrajectoryModal = ({ ), }, - networkedFile: { + isSharable: { content: ( <>
@@ -177,20 +177,20 @@ const ShareTrajectoryModal = ({ - {isLocalFile - ? modalOptions.localFile.content - : modalOptions.networkedFile.content} + {trajectoryIsSharable + ? modalOptions.isSharable.content + : modalOptions.errorMessage.content} ); diff --git a/src/state/trajectory/types.ts b/src/state/trajectory/types.ts index d05b5850..f0238d05 100644 --- a/src/state/trajectory/types.ts +++ b/src/state/trajectory/types.ts @@ -60,6 +60,7 @@ export interface NetworkedSimFile { } export const isLocalFileInterface = (file: any): file is LocalSimFile => !!file.lastModified; + export const isNetworkSimFileInterface = ( file: any ): file is NetworkedSimFile => !!file.title; diff --git a/src/util/userUrlHandling.ts b/src/util/userUrlHandling.ts index ea827b83..4506ce06 100644 --- a/src/util/userUrlHandling.ts +++ b/src/util/userUrlHandling.ts @@ -1,8 +1,13 @@ import { isString } from "lodash"; -import { USER_TRAJ_REDIRECTS } from "../constants"; +import { + URL_PARAM_KEY_FILE_NAME, + URL_PARAM_KEY_USER_URL, + USER_TRAJ_REDIRECTS, +} from "../constants"; -const googleDriveUrlRegEx = /(?:drive.google\.com\/file\/d\/)(.*)(?=\/)|(?:drive.google\.com\/file\/d\/)(.*)/g; +const googleDriveUrlRegEx = + /(?:drive.google\.com\/file\/d\/)(.*)(?=\/)|(?:drive.google\.com\/file\/d\/)(.*)/g; const googleDriveUrlExcludingIdRegEx = /(drive.google\.com\/file\/d\/)(?=.*)/g; export const urlCheck = (urlToCheck: any): string => { @@ -14,7 +19,8 @@ export const urlCheck = (urlToCheck: any): string => { * I had to modify the original to allow s3 buckets which have multiple `.letters-letters.` in them * and I made the http(s) required */ - const regEx = /(https?:\/\/)([\w\-]){0,200}(\.[a-zA-Z][^\-])([\/\w]*)*\/?\??([^\n\r]*)?([^\n\r]*)/g; + const regEx = + /(https?:\/\/)([\w\-]){0,200}(\.[a-zA-Z][^\-])([\/\w]*)*\/?\??([^\n\r]*)?([^\n\r]*)/g; if (regEx.test(urlToCheck)) { return urlToCheck; } @@ -68,18 +74,14 @@ export const getFileIdFromUrl = ( export const getRedirectUrl = (url: string, fileName: string | undefined) => { if (url && fileName && USER_TRAJ_REDIRECTS.includes(url)) { // ex) simularium.allencell.org/viewer?trajFileName=endocytosis.simularium - return `${location.origin}${ - location.pathname - }?trajFileName=${fileName}`; + return `${location.origin}${location.pathname}?trajFileName=${fileName}`; } else { return ""; } }; export const getGoogleApiUrl = (id: string) => { - return `https://www.googleapis.com/drive/v2/files/${id}?alt=media&key=${ - process.env.GOOGLE_API_KEY - }`; + return `https://www.googleapis.com/drive/v2/files/${id}?alt=media&key=${process.env.GOOGLE_API_KEY}`; }; export const getUserTrajectoryUrl = (url: string, fileId?: string) => { @@ -89,3 +91,10 @@ export const getUserTrajectoryUrl = (url: string, fileId?: string) => { return url.replace("dropbox.com", "dl.dropboxusercontent.com"); } }; + +export const isOnlineTrajectory = (url: string) => { + return ( + url.includes(URL_PARAM_KEY_USER_URL) || + url.includes(URL_PARAM_KEY_FILE_NAME) + ); +}; From 0b89c30e303c57b0be20f1b079ac19b5d297e3ba Mon Sep 17 00:00:00 2001 From: meganrm Date: Thu, 5 Oct 2023 11:52:19 -0700 Subject: [PATCH 2/5] use constant for trajFileName --- src/components/ViewerTitle/index.tsx | 6 +++++- src/util/userUrlHandling.ts | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/ViewerTitle/index.tsx b/src/components/ViewerTitle/index.tsx index 9df3e7df..e2f370f6 100644 --- a/src/components/ViewerTitle/index.tsx +++ b/src/components/ViewerTitle/index.tsx @@ -7,6 +7,7 @@ import { VIEWER_PATHNAME } from "../../routes"; import TRAJECTORIES from "../../constants/networked-trajectories"; import styles from "./style.css"; +import { URL_PARAM_KEY_FILE_NAME } from "../../constants"; interface ViewerTitleProps { simulariumFileName: string; @@ -27,7 +28,10 @@ const ViewerTitle: React.FunctionComponent = ( // networked-trajectories.ts to get its version info // TODO: Eventually we should put all the contents of networked-trajectories.ts in the // Simularium files themselves - const trajectoryId = location.search.replace("?trajFileName=", ""); + const trajectoryId = location.search.replace( + `?${URL_PARAM_KEY_FILE_NAME}=`, + "" + ); const currentTrajectory = TRAJECTORIES.find( (trajectory) => trajectory.id === trajectoryId ); diff --git a/src/util/userUrlHandling.ts b/src/util/userUrlHandling.ts index 4506ce06..26a85e8f 100644 --- a/src/util/userUrlHandling.ts +++ b/src/util/userUrlHandling.ts @@ -74,7 +74,7 @@ export const getFileIdFromUrl = ( export const getRedirectUrl = (url: string, fileName: string | undefined) => { if (url && fileName && USER_TRAJ_REDIRECTS.includes(url)) { // ex) simularium.allencell.org/viewer?trajFileName=endocytosis.simularium - return `${location.origin}${location.pathname}?trajFileName=${fileName}`; + return `${location.origin}${location.pathname}?${URL_PARAM_KEY_FILE_NAME}=${fileName}`; } else { return ""; } From e1fa8070dbb6c29be716c406942cfa4250693647 Mon Sep 17 00:00:00 2001 From: meganrm Date: Thu, 5 Oct 2023 12:03:26 -0700 Subject: [PATCH 3/5] use selector instead of type guard --- src/components/DownloadTrajectoryMenu/index.tsx | 13 ++++++------- src/containers/AppHeader/index.tsx | 5 +++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/components/DownloadTrajectoryMenu/index.tsx b/src/components/DownloadTrajectoryMenu/index.tsx index 9908711a..1ff696a0 100644 --- a/src/components/DownloadTrajectoryMenu/index.tsx +++ b/src/components/DownloadTrajectoryMenu/index.tsx @@ -3,23 +3,21 @@ import { Button, Tooltip } from "antd"; import { ISimulariumFile } from "@aics/simularium-viewer/type-declarations"; import { DATA_BUCKET_URL, TOOLTIP_COLOR } from "../../constants"; -import { - NetworkedSimFile, - LocalSimFile, - isNetworkSimFileInterface, -} from "../../state/trajectory/types"; +import { NetworkedSimFile, LocalSimFile } from "../../state/trajectory/types"; import { Download } from "../Icons"; import styles from "./style.css"; interface DownloadTrajectoryMenuProps { isBuffering: boolean; + isNetworkedFile: boolean; simulariumFile: LocalSimFile | NetworkedSimFile; } const DownloadTrajectoryMenu = ({ isBuffering, simulariumFile, + isNetworkedFile, }: DownloadTrajectoryMenuProps): JSX.Element => { const fileIsLoaded = () => !!simulariumFile.name; @@ -27,10 +25,11 @@ const DownloadTrajectoryMenu = ({ if (!fileIsLoaded()) { return ""; } - if (isNetworkSimFileInterface(simulariumFile)) { + if (isNetworkedFile) { return `${DATA_BUCKET_URL}/trajectory/${simulariumFile.name}`; } else { - const data: ISimulariumFile = simulariumFile.data; + const localFile = simulariumFile as LocalSimFile; // isNetworkedFile checks for this + const data: ISimulariumFile = localFile.data; const blob = data.getAsBlob(); return URL.createObjectURL(blob); } diff --git a/src/containers/AppHeader/index.tsx b/src/containers/AppHeader/index.tsx index 85f7a220..57aef185 100644 --- a/src/containers/AppHeader/index.tsx +++ b/src/containers/AppHeader/index.tsx @@ -31,6 +31,7 @@ import DownloadTrajectoryMenu from "../../components/DownloadTrajectoryMenu"; interface AppHeaderProps { simulariumFile: LocalSimFile | NetworkedSimFile; isBuffering: boolean; + isNetworkedFile: boolean; clearSimulariumFile: ActionCreator; changeToLocalSimulariumFile: ActionCreator; changeToNetworkedFile: ActionCreator; @@ -48,6 +49,7 @@ class AppHeader extends React.Component { setViewerStatus, clearSimulariumFile, setError, + isNetworkedFile, } = this.props; let lastModified = 0; let displayName = ""; @@ -89,6 +91,7 @@ class AppHeader extends React.Component {
@@ -101,6 +104,8 @@ function mapStateToProps(state: State) { simulariumFile: trajectoryStateBranch.selectors.getSimulariumFile(state), isBuffering: viewerStateBranch.selectors.getIsBuffering(state), + isNetworkedFile: + trajectoryStateBranch.selectors.getIsNetworkedFile(state), }; } From 17028347eca6cfc3944caa0cdbbc03723e8f431d Mon Sep 17 00:00:00 2001 From: meganrm Date: Thu, 5 Oct 2023 12:29:02 -0700 Subject: [PATCH 4/5] add unit test --- src/util/test/index.test.ts | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/util/test/index.test.ts b/src/util/test/index.test.ts index 0352c491..41e9fc44 100644 --- a/src/util/test/index.test.ts +++ b/src/util/test/index.test.ts @@ -1,6 +1,10 @@ import * as React from "react"; -import { USER_TRAJ_REDIRECTS } from "../../constants"; +import { + URL_PARAM_KEY_FILE_NAME, + URL_PARAM_KEY_USER_URL, + USER_TRAJ_REDIRECTS, +} from "../../constants"; import { bindAll, convertToSentenceCase, @@ -16,8 +20,10 @@ import { getRedirectUrl, getUserTrajectoryUrl, isGoogleDriveUrl, + isOnlineTrajectory, urlCheck, } from "../userUrlHandling"; +import { FILE } from "dns"; process.env.GOOGLE_API_KEY = "key"; describe("General utilities", () => { @@ -373,4 +379,21 @@ describe("User Url handling", () => { expect(result).toEqual("dl.dropboxusercontent.com/path"); }); }); + describe("isOnlineTrajectory", () => { + it("it returns true if the trajectory is hosted online", () => { + const cloudTrajectoryUrl = `simularium?${URL_PARAM_KEY_USER_URL}=url`; + const result = isOnlineTrajectory(cloudTrajectoryUrl); + expect(result).toBeTruthy; + }); + it("true if the trajectory is one of our networked models", () => { + const networkedUrl = `simularium?${URL_PARAM_KEY_FILE_NAME}=url`; + const result = isOnlineTrajectory(networkedUrl); + expect(result).toBeTruthy; + }); + it("it returns false if no relevant url params are present", () => { + const url = `simularium?other_url_param=value`; + const result = isOnlineTrajectory(url); + expect(result).toBeFalsy; + }); + }); }); From 4d0ee6734b22d702415b9621c502e68953eb1a00 Mon Sep 17 00:00:00 2001 From: meganrm Date: Thu, 5 Oct 2023 12:33:40 -0700 Subject: [PATCH 5/5] remove accidental auto import --- src/util/test/index.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/test/index.test.ts b/src/util/test/index.test.ts index 41e9fc44..cdb7040b 100644 --- a/src/util/test/index.test.ts +++ b/src/util/test/index.test.ts @@ -23,7 +23,6 @@ import { isOnlineTrajectory, urlCheck, } from "../userUrlHandling"; -import { FILE } from "dns"; process.env.GOOGLE_API_KEY = "key"; describe("General utilities", () => {