Skip to content

Commit

Permalink
Initial display of app & resource info when launching instant launches
Browse files Browse the repository at this point in the history
  • Loading branch information
ianmcorvidae committed Oct 11, 2024
1 parent e883236 commit 2d4c853
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 36 deletions.
73 changes: 52 additions & 21 deletions src/components/instantlaunches/InstantLaunchButtonWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
import React, { useEffect, useCallback } from "react";

import { useMutation } from "react-query";
import { useMutation, useQuery } from "react-query";

import { useDefaultOutputDir } from "components/data/utils";
import withErrorAnnouncer from "components/error/withErrorAnnouncer";
Expand All @@ -25,7 +25,14 @@ import { useUserProfile } from "contexts/userProfile";
import { useBootstrapInfo } from "contexts/bootstrap";
import ids from "./ids";
import { InstantLaunchSubmissionDialog } from "./index";
import { instantlyLaunch } from "serviceFacades/instantlaunches";
import {
instantlyLaunch,
extractLaunchId,
} from "serviceFacades/instantlaunches";
import {
SAVED_LAUNCH_APP_INFO,
getAppInfo,
} from "serviceFacades/savedLaunches";
import { useTranslation } from "i18n";
import { ERROR_CODES } from "components/error/errorCode";

Expand All @@ -44,6 +51,8 @@ function InstantLaunchButtonWrapper(props) {

const [open, setOpen] = React.useState(false);
const [hasLaunched, setHasLaunched] = React.useState(false);
const [appInfo, setAppInfo] = React.useState(null);

const [signInDlgOpen, setSignInDlgOpen] = React.useState(false);
const [accessRequestDialogOpen, setAccessRequestDialogOpen] =
React.useState(false);
Expand All @@ -62,6 +71,19 @@ function InstantLaunchButtonWrapper(props) {
}
}, [ilUrl]);

const launchId = extractLaunchId(instantLaunch);

const { isFetching: savedLaunchLoading } = useQuery({
queryKey: [SAVED_LAUNCH_APP_INFO, { launchId }],
queryFn: () => getAppInfo({ launchId }),
enabled: open,
onSuccess: setAppInfo,
onError: (err) => {
setOpen(false);
showErrorAnnouncer(err.message, err);
},
});

const { mutate: launch } = useMutation(instantlyLaunch, {
onSuccess: (listing) => {
if (listing.analyses.length > 0) {
Expand Down Expand Up @@ -106,45 +128,54 @@ function InstantLaunchButtonWrapper(props) {
const preferences = bootstrapInfo?.preferences;
const userId = userProfile?.id;

useEffect(() => {
if (open && !savedLaunchLoading) {
launch({
instantLaunch,
resource,
output_dir,
preferences,
appInfo,
});
}
}, [
open,
savedLaunchLoading,
instantLaunch,
launch,
resource,
output_dir,
preferences,
appInfo,
]);

const onClick = useCallback(() => {
if (userId) {
if (computeLimitExceeded) {
showErrorAnnouncer(t("computeLimitExceededMsg"));
} else {
setOpen(true);
launch({
instantLaunch,
resource,
output_dir,
preferences,
});
}
} else {
setSignInDlgOpen(true);
}
}, [
preferences,
computeLimitExceeded,
instantLaunch,
launch,
output_dir,
resource,
showErrorAnnouncer,
t,
userId,
]);
}, [computeLimitExceeded, showErrorAnnouncer, t, userId]);

useEffect(() => {
if (autolaunch && !hasLaunched) {
onClick();
setHasLaunched(true);
}
}, [autolaunch, onClick, hasLaunched, setHasLaunched]);
}, [autolaunch, onClick, hasLaunched]);

return (
<>
{!autolaunch && render && render(onClick)}
<InstantLaunchSubmissionDialog open={open} />
<InstantLaunchSubmissionDialog
open={open}
appInfo={appInfo}
resource={resource}
/>
<SignInDialog
open={signInDlgOpen}
handleClose={() => setSignInDlgOpen(false)}
Expand Down
12 changes: 11 additions & 1 deletion src/components/instantlaunches/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ const useStyles = makeStyles()((theme) => ({
* @param {Object} props - The component props.
* @param {boolean} props.open - Whether or not the dialog is open.
*/
export const InstantLaunchSubmissionDialog = ({ open }) => {
export const InstantLaunchSubmissionDialog = ({
open,
appInfo,
resource = null,
}) => {
const baseID = buildID(ids.BASE, ids.SUBMISSION, ids.DIALOG);
const { t } = useTranslation("instantlaunches");
const { classes } = useStyles();
Expand All @@ -57,6 +61,12 @@ export const InstantLaunchSubmissionDialog = ({ open }) => {
</DialogTitle>

<DialogContent>
{appInfo && (
<Typography variant="h6">
Launching app: {appInfo.name}
{resource ? " with data " + resource.path : ""}
</Typography>
)}
<div
className={classes.progress}
id={buildID(baseID, ids.PROGRESS)}
Expand Down
45 changes: 31 additions & 14 deletions src/serviceFacades/instantlaunches.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,24 @@ export const deleteInstantLaunchHandler = async (id) => {
);
};

/**
* Utility function to extract a saved launch ID from an instant launch in either format.
*
* @param {Object} instantLaunch - the instant launch object to pull the value out of
*/
export const extractLaunchId = (instantLaunch) => {
if (instantLaunch.hasOwnProperty("default")) {
// The data window logic.
// The saved launch ID is buried in the "default" map of the object passed in
// from the data window.
return instantLaunch.default["quick_launch_id"];
} else {
// The dashboard logic.
// The saved launch ID is a top-level property of the object passed in.
return instantLaunch.quick_launch_id;
}
};

/**
* Event handler for the button that performs the instant launch.
*
Expand All @@ -337,39 +355,38 @@ export const instantlyLaunch = ({
resource,
output_dir,
preferences,
appInfo = null,
}) => {
let savedLaunchId; // The saved launch ID, used to get app information.
let savedLaunchId = extractLaunchId(instantLaunch); // The saved launch ID, used to get app information.

let savedLaunchPromise; // The promise used to get saved launch information.
let appInfoPromise; // The promise used to get app info for the saved launch.

// The format of the instantLaunch object passed in by the data window is a bit different
// than the format passed in by the dashboard, so a bit of normalization needs to take
// place.
if (instantLaunch.hasOwnProperty("default")) {
// The data window logic.
// The saved launch ID is buried in the "default" map of the object passed in
// from the data window.
savedLaunchId = instantLaunch.default["quick_launch_id"];

// We'll need to get the saved launch info from the API since it contains the
// submission, which isn't provided from the data window.
savedLaunchPromise = getSavedLaunch(savedLaunchId);
} else {
// The dashboard logic.
// The saved launch ID is a top-level property of the object passed in.
savedLaunchId = instantLaunch.quick_launch_id;

// Wrap the instant launch object in a promise so we don't have to branch logic
// farther down.
savedLaunchPromise = new Promise((resolve, reject) => {
resolve(instantLaunch);
});
}

if (appInfo) {
appInfoPromise = new Promise((resolve, reject) => {
resolve(appInfo);
});
} else {
appInfoPromise = getAppInfo({ launchId: savedLaunchId });
}

// Contains the Promises that resolve to the data needed to perform a job submission.
const promiseList = [
savedLaunchPromise,
getAppInfo({ launchId: savedLaunchId }),
];
const promiseList = [savedLaunchPromise, appInfoPromise];

return Promise.all(promiseList)
.then((values) => {
Expand Down

0 comments on commit 2d4c853

Please sign in to comment.