Skip to content

Commit 5d61fad

Browse files
authored
feat: modal for creating session launch links (#3665)
* minor: add RStudio warning
1 parent 1c7b72c commit 5d61fad

10 files changed

Lines changed: 855 additions & 367 deletions

File tree

client/src/features/sessionsV2/SessionList/SessionLauncherDisplay.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import type { SessionLauncher } from "../api/sessionLaunchersV2.api";
2424
import { useGetSessionsQuery as useGetSessionsQueryV2 } from "../api/sessionsV2.api";
2525
import UpdateSessionLauncherEnvironmentModal from "../components/SessionModals/UpdateSessionLauncherModal";
2626
import DeleteSessionV2Modal from "../DeleteSessionLauncherModal";
27-
import SessionStartLinkModal from "../SessionView/SessionStartLinkModal";
27+
import SessionLaunchLinkModal from "../SessionView/SessionLaunchLinkModal";
2828
import { SessionView } from "../SessionView/SessionView";
2929
import SessionLauncherCard from "./SessionLauncherCard";
3030
import EnvironmentLogsV2 from "../../../components/LogsV2";
@@ -135,12 +135,11 @@ export function SessionLauncherDisplay({
135135
toggle={toggleDelete}
136136
sessionsLength={filteredSessions?.length}
137137
/>
138-
<SessionStartLinkModal
138+
<SessionLaunchLinkModal
139139
isOpen={isShareLinkOpen}
140-
launcherId={launcher.id}
140+
launcher={launcher}
141+
project={project}
141142
toggle={toggleShareLink}
142-
namespace={project.namespace}
143-
slug={project.slug}
144143
/>
145144
</>
146145
)}

client/src/features/sessionsV2/SessionShowPage/ShowSessionPage.tsx

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,16 @@ import { displaySlice, resetFavicon, setFavicon } from "../../display";
5454
import { useGetNamespacesByNamespaceProjectsAndSlugQuery } from "../../projectsV2/api/projectV2.enhanced-api";
5555
import { SessionRowResourceRequests } from "../../session/components/SessionsList";
5656
import { StartSessionProgressBarV2 } from "../../session/components/StartSessionProgressBar";
57+
import type { Project } from "../../projectsV2/api/projectV2.api";
5758
import PauseOrDeleteSessionModal from "../PauseOrDeleteSessionModal";
58-
import { useGetProjectsByProjectIdSessionLaunchersQuery as useGetProjectSessionLaunchersQuery } from "../api/sessionLaunchersV2.api";
59+
import {
60+
useGetProjectsByProjectIdSessionLaunchersQuery as useGetProjectSessionLaunchersQuery,
61+
type SessionLauncher,
62+
} from "../api/sessionLaunchersV2.api";
5963
import { useGetSessionsQuery } from "../api/sessionsV2.api";
6064
import { getSessionFavicon } from "../session.utils";
6165
import { SessionV2 } from "../sessionsV2.types";
62-
import SessionStartLinkModal from "../SessionView/SessionStartLinkModal";
66+
import SessionLaunchLinkModal from "../SessionView/SessionLaunchLinkModal";
6367
import SessionIframe from "./SessionIframe";
6468
import SessionPaused from "./SessionPaused";
6569
import SessionUnavailable from "./SessionUnavailable";
@@ -376,30 +380,17 @@ function SessionDetails({
376380
slug?: string;
377381
}) {
378382
const [isOpen, setIsOpen] = useState(false);
379-
const { projectId, launcherId } = useMemo(() => {
380-
if (session == null) {
381-
return { projectId: undefined, launcherId: undefined };
382-
}
383-
return {
384-
projectId: session.project_id,
385-
launcherId: session.launcher_id,
386-
};
387-
}, [session]);
388-
389383
const {
390-
data: launchers,
391-
isLoading: isLoadingLaunchers,
392-
error: launchersError,
393-
} = useGetProjectSessionLaunchersQuery(projectId ? { projectId } : skipToken);
394-
const { data: project, isLoading: isLoadingProject } =
395-
useGetNamespacesByNamespaceProjectsAndSlugQuery(
396-
namespace && slug ? { namespace, slug } : skipToken
397-
);
398-
399-
const launcher = useMemo(
400-
() => launchers?.find(({ id }) => id === launcherId),
401-
[launcherId, launchers]
402-
);
384+
isLoadingLaunchers,
385+
isLoadingProject,
386+
launcher,
387+
launchersError,
388+
project,
389+
} = useSessionProjectAndLauncher({
390+
namespace,
391+
session,
392+
slug,
393+
});
403394
const toggle = useCallback(() => {
404395
setIsOpen((open) => !open);
405396
}, []);
@@ -522,7 +513,11 @@ function ShareSessionLinkButton({
522513
namespace?: string;
523514
slug?: string;
524515
}) {
525-
const launcherId = session?.launcher_id;
516+
const { launcher, project } = useSessionProjectAndLauncher({
517+
namespace,
518+
session,
519+
slug,
520+
});
526521
const ref = useRef<HTMLButtonElement>(null);
527522
const buttonId = "share-session-button";
528523
const tooltip = "Share session launch link";
@@ -532,7 +527,7 @@ function ShareSessionLinkButton({
532527
setIsShareLinkOpen((open) => !open);
533528
}, []);
534529

535-
if (launcherId == null || namespace == null || slug == null) return null;
530+
if (launcher == null || project == null) return null;
536531

537532
return (
538533
<div>
@@ -556,13 +551,60 @@ function ShareSessionLinkButton({
556551
<UncontrolledTooltip placement="bottom" target={ref}>
557552
{tooltip}
558553
</UncontrolledTooltip>
559-
<SessionStartLinkModal
554+
<SessionLaunchLinkModal
560555
isOpen={isShareLinkOpen}
561-
launcherId={launcherId}
556+
launcher={launcher}
557+
project={project}
562558
toggle={toggleShareLink}
563-
slug={slug}
564-
namespace={namespace}
565559
/>
566560
</div>
567561
);
568562
}
563+
564+
function useSessionProjectAndLauncher({
565+
namespace,
566+
session,
567+
slug,
568+
}: {
569+
namespace: string | undefined;
570+
session: SessionV2 | undefined;
571+
slug: string | undefined;
572+
}): {
573+
isLoadingLaunchers: boolean;
574+
isLoadingProject: boolean;
575+
launcher: SessionLauncher | undefined;
576+
launchersError: unknown;
577+
project: Project | undefined;
578+
} {
579+
const { projectId, launcherId } = useMemo(() => {
580+
if (session == null) {
581+
return { projectId: undefined, launcherId: undefined };
582+
}
583+
return {
584+
projectId: session.project_id,
585+
launcherId: session.launcher_id,
586+
};
587+
}, [session]);
588+
589+
const {
590+
data: launchers,
591+
isLoading: isLoadingLaunchers,
592+
error: launchersError,
593+
} = useGetProjectSessionLaunchersQuery(projectId ? { projectId } : skipToken);
594+
const { data: project, isLoading: isLoadingProject } =
595+
useGetNamespacesByNamespaceProjectsAndSlugQuery(
596+
namespace && slug ? { namespace, slug } : skipToken
597+
);
598+
599+
const launcher = useMemo(
600+
() => launchers?.find(({ id }) => id === launcherId),
601+
[launcherId, launchers]
602+
);
603+
return {
604+
isLoadingLaunchers,
605+
isLoadingProject,
606+
launcher,
607+
launchersError,
608+
project,
609+
};
610+
}

client/src/features/sessionsV2/SessionView/EnvVariablesModal.tsx

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ function AddEnvVariableButton({
109109
);
110110
}
111111

112+
function RStudioInfo() {
113+
return (
114+
<span className="text-secondary">
115+
Note: Environment Variables are not visible in RStudio-based environments.
116+
</span>
117+
);
118+
}
119+
112120
interface EnvVariablesFormContentProps {
113121
control: Control<EnvVariablesForm, unknown>;
114122
errors: FieldErrors<EnvVariablesForm>;
@@ -329,30 +337,36 @@ export default function EnvVariablesModal({
329337
)}
330338
</ModalBody>
331339
<ModalFooter>
332-
<Button
333-
data-cy="close-cancel-button"
334-
color="outline-primary"
335-
onClick={toggle}
336-
>
337-
<XLg className={cx("bi", "me-1")} />
338-
{result.isSuccess ? "Close" : "Cancel"}
339-
</Button>
340-
{!result.isSuccess && (
340+
<div className="flex-shrink-1" style={{ width: "20rem" }}>
341+
<RStudioInfo />
342+
</div>
343+
<div className={cx("flex-grow-1", "flex-fill", "text-end")}>
341344
<Button
342-
color="primary"
343-
data-cy="edit-session-button"
344-
disabled={result.isLoading || !isDirty}
345-
onClick={handleSubmit(onSubmit)}
346-
type="submit"
345+
className="me-2"
346+
data-cy="close-cancel-button"
347+
color="outline-primary"
348+
onClick={toggle}
347349
>
348-
{result.isLoading ? (
349-
<Loader className="me-1" inline size={16} />
350-
) : (
351-
<CheckLg className={cx("bi", "me-1")} />
352-
)}
353-
Update session launcher
350+
<XLg className={cx("bi", "me-1")} />
351+
{result.isSuccess ? "Close" : "Cancel"}
354352
</Button>
355-
)}
353+
{!result.isSuccess && (
354+
<Button
355+
color="primary"
356+
data-cy="edit-session-button"
357+
disabled={result.isLoading || !isDirty}
358+
onClick={handleSubmit(onSubmit)}
359+
type="submit"
360+
>
361+
{result.isLoading ? (
362+
<Loader className="me-1" inline size={16} />
363+
) : (
364+
<CheckLg className={cx("bi", "me-1")} />
365+
)}
366+
Update session launcher
367+
</Button>
368+
)}
369+
</div>
356370
</ModalFooter>
357371
</Modal>
358372
);

0 commit comments

Comments
 (0)