Skip to content

Commit 64f3af1

Browse files
committed
feat: add job launcher in launchers
1 parent fd22fd0 commit 64f3af1

31 files changed

Lines changed: 1322 additions & 347 deletions

client/scripts/update_api_spec.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { parseDocument } from "yaml";
2424

2525
const GH_BASE_URL = "https://raw.githubusercontent.com";
2626
const DATA_SERVICES_REPO = "SwissDataScienceCenter/renku-data-services";
27-
const DATA_SERVICES_RELEASE = "main";
27+
const DATA_SERVICES_RELEASE = "eikek/session-launcher-type";
2828

2929
async function main() {
3030
argv.forEach((arg) => {
@@ -155,12 +155,12 @@ async function updateApiFiles({ specFile, destFile }) {
155155
const DEST_FILE = destFile;
156156

157157
console.log(
158-
`Updating "${DEST_FILE}" with spec file from release ${DATA_SERVICES_RELEASE}...`,
158+
`Updating "${DEST_FILE}" with spec file from release ${DATA_SERVICES_RELEASE}...`
159159
);
160160

161161
const fileUrl = new URL(
162162
join(DATA_SERVICES_REPO, DATA_SERVICES_RELEASE, API_SPEC_FILE),
163-
GH_BASE_URL,
163+
GH_BASE_URL
164164
);
165165
const res = await fetch(fileUrl);
166166
if (res.status >= 400) {
@@ -179,7 +179,7 @@ async function updateApiFiles({ specFile, destFile }) {
179179
await new Promise((resolve, reject) => {
180180
const cp = exec(["npx", "prettier", "-w", DEST_FILE].join(" "));
181181
cp.on("error", (error) =>
182-
reject(new Error("failed to run prettier", { cause: error })),
182+
reject(new Error("failed to run prettier", { cause: error }))
183183
);
184184
cp.on("exit", (code) => {
185185
code == 0 ? resolve() : reject(new Error("failed to run prettier"));

client/src/features/admin/SessionEnvironmentsSection.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import {
3131

3232
import { CommandCopy } from "~/components/commandCopy/CommandCopy";
3333
import RtkOrDataServicesError from "~/components/errors/RtkOrDataServicesError";
34-
import { ErrorLabel } from "~/components/formlabels/FormLabels";
3534
import ChevronFlippedIcon from "~/components/icons/ChevronFlippedIcon";
3635
import { Loader } from "~/components/Loader";
3736
import { TimeCaption } from "~/components/TimeCaption";
@@ -40,6 +39,7 @@ import type {
4039
EnvironmentList as SessionEnvironmentList,
4140
} from "../sessionsV2/api/sessionLaunchersV2.api";
4241
import { useGetEnvironmentsQuery } from "../sessionsV2/api/sessionLaunchersV2.api";
42+
import { EnvironmentCode } from "../sessionsV2/components/EnvironmentCode";
4343
import { safeStringify } from "../sessionsV2/session.utils";
4444
import AddSessionEnvironmentButton from "./AddSessionEnvironmentButton";
4545
import DeleteSessionEnvironmentButton from "./DeleteSessionEnvironmentButton";
@@ -142,7 +142,7 @@ function SessionEnvironmentDisplay({
142142
"fw-bold",
143143
"gap-3",
144144
"p-3",
145-
"w-100",
145+
"w-100"
146146
)}
147147
onClick={toggle}
148148
type="button"
@@ -217,8 +217,3 @@ function SessionEnvironmentDisplay({
217217
</Col>
218218
);
219219
}
220-
221-
function EnvironmentCode({ value }: { value: string | null }) {
222-
if (value === null) return <ErrorLabel text={"Invalid JSON array value"} />;
223-
return <code>{value}</code>;
224-
}

client/src/features/sessionsV2/AddSessionLauncherButton.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { useCallback, useState } from "react";
2121
import { PlusLg } from "react-bootstrap-icons";
2222
import { Button } from "reactstrap";
2323

24-
import NewSessionLauncherModal from "./components/SessionModals/NewSessionLauncherModal";
24+
import NewLauncherModal from "./components/SessionModals/NewLauncherModal";
2525

2626
export default function AddSessionLauncherButton({
2727
"data-cy": dataCy,
@@ -38,7 +38,7 @@ export default function AddSessionLauncherButton({
3838
return (
3939
<>
4040
{styleBtn === "iconTextBtn" ? (
41-
<Button data-cy={dataCy} onClick={() => toggle()}>
41+
<Button data-cy={dataCy} onClick={toggle}>
4242
<PlusLg className={cx("me-2", "bi")} />
4343
Add session
4444
</Button>
@@ -52,7 +52,7 @@ export default function AddSessionLauncherButton({
5252
<PlusLg className="bi" />
5353
</Button>
5454
)}
55-
<NewSessionLauncherModal isOpen={isOpen} toggle={toggle} />
55+
<NewLauncherModal isOpen={isOpen} toggle={toggle} />
5656
</>
5757
);
5858
}

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

Lines changed: 74 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@
1919
import { skipToken } from "@reduxjs/toolkit/query";
2020
import cx from "classnames";
2121
import { useContext, useMemo } from "react";
22-
import { CircleFill, Link45deg, Pencil, Trash } from "react-bootstrap-icons";
22+
import {
23+
CircleFill,
24+
Gear,
25+
Link45deg,
26+
Pencil,
27+
PlayCircle,
28+
Trash,
29+
} from "react-bootstrap-icons";
2330
import { Card, CardBody, Col, DropdownItem, Row } from "reactstrap";
2431

2532
import SessionEnvironmentGitLabWarningBadge from "~/features/legacy/SessionEnvironmentGitLabWarnBadge";
@@ -40,13 +47,16 @@ import {
4047
BuildStatusBadge,
4148
BuildStatusDescription,
4249
} from "../components/BuildStatusComponents";
50+
import JobLauncherButtons from "../components/JobLauncherButtons";
51+
import JobLauncherDropdownActions from "../components/JobLauncherDropdownActions";
4352
import {
4453
EnvironmentIcon,
4554
LauncherEnvironmentIcon,
4655
} from "../components/SessionForm/LauncherEnvironmentIcon";
4756
import { SessionLauncherButtons } from "../components/SessionLauncherButtons";
4857
import SessionImageBadge from "../components/SessionStatus/SessionImageBadge";
4958
import { SessionBadge } from "../components/SessionStatus/SessionStatus";
59+
import { isJobLauncher } from "../session.utils";
5060
import { SessionV2 } from "../sessionsV2.types";
5161
import SessionCard from "./SessionCard";
5262

@@ -86,38 +96,46 @@ export default function SessionLauncherCard({
8696
const { data: builds, isLoading } = useGetBuildsQuery(
8797
imageBuildersEnabled && isCodeEnvironment
8898
? { environmentId: environment.id }
89-
: skipToken,
99+
: skipToken
90100
);
91101

92102
const lastBuild = builds?.at(0);
93103
const lastSuccessfulBuild = builds?.find(
94-
(build) => build.status === "succeeded" && build.id !== lastBuild?.id,
104+
(build) => build.status === "succeeded" && build.id !== lastBuild?.id
95105
);
96106
const hasSession = !!sessions?.length;
107+
const isJob = launcher != null && isJobLauncher(launcher);
108+
const LauncherTypeIcon = isJob ? Gear : PlayCircle;
109+
const launcherTypeLabel = isJob ? "Job Launcher" : "Session Launcher";
97110

98111
sessionLaunchersV2Api.endpoints.getEnvironmentsByEnvironmentIdBuilds.useQuerySubscription(
99112
isCodeEnvironment && lastBuild?.status === "in_progress"
100113
? { environmentId: environment.id }
101114
: skipToken,
102115
{
103116
pollingInterval: 1_000,
104-
},
117+
}
105118
);
106119

107-
const otherLauncherActions = launcher &&
108-
toggleUpdate &&
109-
toggleDelete &&
110-
toggleShareLink &&
111-
toggleUpdateEnvironment && (
112-
<SessionLauncherDropdownActions
113-
project={project}
114-
launcher={launcher}
115-
toggleDelete={toggleDelete}
116-
toggleUpdate={toggleUpdate}
117-
toggleUpdateEnvironment={toggleUpdateEnvironment}
118-
toggleShareLink={toggleShareLink}
119-
/>
120-
);
120+
const otherLauncherActions =
121+
launcher &&
122+
(isJob ? (
123+
<JobLauncherDropdownActions launcher={launcher} />
124+
) : (
125+
toggleUpdate &&
126+
toggleDelete &&
127+
toggleShareLink &&
128+
toggleUpdateEnvironment && (
129+
<SessionLauncherDropdownActions
130+
project={project}
131+
launcher={launcher}
132+
toggleDelete={toggleDelete}
133+
toggleUpdate={toggleUpdate}
134+
toggleUpdateEnvironment={toggleUpdateEnvironment}
135+
toggleShareLink={toggleShareLink}
136+
/>
137+
)
138+
));
121139

122140
const ENVIRONMENT_KIND_CLASSES = [
123141
"align-items-center",
@@ -132,7 +150,7 @@ export default function SessionLauncherCard({
132150
useGetSessionsImagesQuery(
133151
environment?.container_image != null
134152
? { imageUrl: environment.container_image }
135-
: skipToken,
153+
: skipToken
136154
);
137155

138156
const { data: resourcePools, isLoading: isLoadingResourcePools } =
@@ -144,7 +162,7 @@ export default function SessionLauncherCard({
144162
return undefined;
145163
}
146164
return resourcePools.find(({ classes }) =>
147-
classes.some(({ id }) => id === launcher.resource_class_id),
165+
classes.some(({ id }) => id === launcher.resource_class_id)
148166
);
149167
}, [launcher?.resource_class_id, resourcePools]);
150168

@@ -154,7 +172,7 @@ export default function SessionLauncherCard({
154172
styles.SessionLauncherCard,
155173
"cursor-pointer",
156174
"shadow-none",
157-
"rounded-0",
175+
"rounded-0"
158176
)}
159177
data-cy="session-launcher-item"
160178
onClick={toggleSessionView}
@@ -170,8 +188,18 @@ export default function SessionLauncherCard({
170188
xl={4}
171189
className={cx("d-inline-block", "link-primary", "text-body")}
172190
>
173-
<span className={cx("small", "text-muted", "me-3")}>
174-
Session Launcher
191+
<span
192+
className={cx(
193+
"small",
194+
"text-muted",
195+
"me-3",
196+
"d-inline-flex",
197+
"align-items-center",
198+
"gap-1"
199+
)}
200+
>
201+
<LauncherTypeIcon className={cx("bi")} size={14} />
202+
{launcherTypeLabel}
175203
</span>
176204
</Col>
177205
<Col xs={12} xl="auto">
@@ -266,8 +294,8 @@ export default function SessionLauncherCard({
266294
lastBuild?.status === "succeeded"
267295
? lastBuild?.result?.completed_at
268296
: lastSuccessfulBuild?.status === "succeeded"
269-
? lastSuccessfulBuild?.result?.completed_at
270-
: undefined
297+
? lastSuccessfulBuild?.result?.completed_at
298+
: undefined
271299
}
272300
/>
273301
</Col>
@@ -292,22 +320,29 @@ export default function SessionLauncherCard({
292320
"d-flex",
293321
"flex-column",
294322
"align-items-end",
295-
"gap-2",
323+
"gap-2"
296324
)}
297325
>
298-
<SessionLauncherButtons
299-
hasSession={hasSession}
300-
lastBuild={lastBuild}
301-
launcher={launcher}
302-
namespace={project.namespace}
303-
otherActions={otherLauncherActions}
304-
slug={project.slug}
305-
useOldImage={
306-
isCodeEnvironment &&
307-
lastBuild?.status !== "succeeded" &&
308-
!!lastSuccessfulBuild
309-
}
310-
/>
326+
{isJob ? (
327+
<JobLauncherButtons
328+
launcher={launcher}
329+
otherActions={otherLauncherActions}
330+
/>
331+
) : (
332+
<SessionLauncherButtons
333+
hasSession={hasSession}
334+
lastBuild={lastBuild}
335+
launcher={launcher}
336+
namespace={project.namespace}
337+
otherActions={otherLauncherActions}
338+
slug={project.slug}
339+
useOldImage={
340+
isCodeEnvironment &&
341+
lastBuild?.status !== "succeeded" &&
342+
!!lastSuccessfulBuild
343+
}
344+
/>
345+
)}
311346
{isCodeEnvironment &&
312347
lastBuild?.status !== "succeeded" &&
313348
lastSuccessfulBuild && (

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export function SessionLauncherDisplay({
6060
const launcherHash = useMemo(() => `launcher-${launcher.id}`, [launcher.id]);
6161
const isSessionViewOpen = useMemo(
6262
() => hash === launcherHash,
63-
[hash, launcherHash],
63+
[hash, launcherHash]
6464
);
6565
const toggleSessionView = useCallback(() => {
6666
setHash((prev) => {
@@ -77,10 +77,10 @@ export function SessionLauncherDisplay({
7777
? sessions.filter(
7878
(session) =>
7979
session.launcher_id === launcher.id &&
80-
session.project_id === project.id,
80+
session.project_id === project.id
8181
)
8282
: [],
83-
[launcher.id, project.id, sessions],
83+
[launcher.id, project.id, sessions]
8484
);
8585

8686
return (
@@ -94,7 +94,9 @@ export function SessionLauncherDisplay({
9494
toggleUpdate={toggleUpdate}
9595
toggleUpdateEnvironment={toggleUpdateEnvironment}
9696
toggleDelete={toggleDelete}
97-
toggleShareLink={toggleShareLink}
97+
toggleShareLink={
98+
launcher.launcher_type === "interactive" ? toggleShareLink : undefined
99+
}
98100
toggleSessionView={toggleSessionView}
99101
/>
100102
<SessionView

client/src/features/sessionsV2/SessionsV2.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import { SessionView } from "./SessionView/SessionView";
4949

5050
export function getShowSessionUrlByProject(
5151
project: Project,
52-
sessionName: string,
52+
sessionName: string
5353
) {
5454
return generatePath(ABSOLUTE_ROUTES.v2.projects.show.sessions.show, {
5555
namespace: project.namespace,
@@ -87,10 +87,10 @@ export default function SessionsV2({ project }: SessionsV2Props) {
8787
? sessions.filter(
8888
(session) =>
8989
launchers.every(({ id }) => session.launcher_id !== id) &&
90-
session.project_id === projectId,
90+
session.project_id === projectId
9191
)
9292
: [],
93-
[launchers, sessions, projectId],
93+
[launchers, sessions, projectId]
9494
);
9595

9696
const loading = isLoading && (
@@ -140,13 +140,13 @@ export default function SessionsV2({ project }: SessionsV2Props) {
140140
className={cx(
141141
"align-items-center",
142142
"d-flex",
143-
"justify-content-between",
143+
"justify-content-between"
144144
)}
145145
>
146146
<div className={cx("align-items-center", "d-flex")}>
147147
<h2 className={cx("mb-0", "me-2")}>
148148
<PlayCircle className={cx("me-1", "bi")} />
149-
Sessions
149+
Launchers
150150
</h2>
151151
<Badge>{totalSessions}</Badge>
152152
</div>
@@ -246,11 +246,11 @@ function OrphanSession({ session, project }: OrphanSessionProps) {
246246
const [hash, setHash] = useLocationHash();
247247
const sessionHash = useMemo(
248248
() => `orphan-session-${session.name}`,
249-
[session.name],
249+
[session.name]
250250
);
251251
const isSessionViewOpen = useMemo(
252252
() => hash === sessionHash,
253-
[hash, sessionHash],
253+
[hash, sessionHash]
254254
);
255255
const toggleSessionView = useCallback(() => {
256256
setHash((prev) => {

0 commit comments

Comments
 (0)