Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/scripts/update_api_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { parseDocument } from "yaml";

const GH_BASE_URL = "https://raw.githubusercontent.com";
const DATA_SERVICES_REPO = "SwissDataScienceCenter/renku-data-services";
const DATA_SERVICES_RELEASE = "main";
const DATA_SERVICES_RELEASE = "leafty/feat-resource-class-platforms";

async function main() {
argv.forEach((arg) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,12 +315,15 @@ export type EnvironmentWithImageGet = Environment & {
environment_kind: EnvironmentKind;
};
export type Repository = string;
export type BuildPlatform = "linux/amd64" | "linux/arm64";
export type BuildPlatforms = BuildPlatform[];
export type BuilderVariant = string;
export type FrontendVariant = string;
export type RepositoryRevision = string;
export type BuildContextDir = string;
export type BuildParameters = {
repository: Repository;
platforms?: BuildPlatforms;
builder_variant: BuilderVariant;
frontend_variant: FrontendVariant;
repository_revision?: RepositoryRevision;
Expand Down Expand Up @@ -385,6 +388,7 @@ export type RepositoryRevisionPatch = string;
export type BuildContextDirPatch = string;
export type BuildParametersPatch = {
repository?: Repository;
platforms?: BuildPlatforms;
builder_variant?: BuilderVariant;
frontend_variant?: FrontendVariant;
repository_revision?: RepositoryRevisionPatch;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,18 @@
"maxLength": 99,
"example": "My Renku Session :)"
},
"BuildPlatforms": {
"description": "The target runtime platforms of a session environment.",
"type": "array",
"items": {
"$ref": "#/components/schemas/BuildPlatform"
}
},
"BuildPlatform": {
"description": "A runtime platform, e.g. \"linux/amd64\".",
"type": "string",
"enum": ["linux/amd64", "linux/arm64"]
},
"BuilderVariant": {
"description": "Type of virtual environment manager when building custom environments.",
"type": "string",
Expand Down Expand Up @@ -1106,6 +1118,9 @@
"repository": {
"$ref": "#/components/schemas/Repository"
},
"platforms": {
"$ref": "#/components/schemas/BuildPlatforms"
},
"builder_variant": {
"$ref": "#/components/schemas/BuilderVariant"
},
Expand Down Expand Up @@ -1144,6 +1159,9 @@
"repository": {
"$ref": "#/components/schemas/Repository"
},
"platforms": {
"$ref": "#/components/schemas/BuildPlatforms"
},
"builder_variant": {
"$ref": "#/components/schemas/BuilderVariant"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*!
* Copyright 2025 - Swiss Data Science Center (SDSC)
* A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and
* Eidgenössische Technische Hochschule Zürich (ETHZ).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import cx from "classnames";
import { useCallback, useMemo, useState } from "react";
import {
Controller,
useController,
type Control,
type FieldValues,
type UseControllerProps,
} from "react-hook-form";
import { Collapse, Label } from "reactstrap";

import ChevronFlippedIcon from "~/components/icons/ChevronFlippedIcon";
import { BUILDER_PLATFORMS } from "../../session.constants";
import type { SessionLauncherForm } from "../../sessionsV2.types";
import BuilderSelectorCommon from "./BuilderSelectorCommon";

interface BuilderAdvancedSettingsProps {
control: Control<SessionLauncherForm>;
}

export default function BuilderAdvancedSettings({
control,
}: BuilderAdvancedSettingsProps) {
const {
formState: { defaultValues },
} = useController({ control, name: "platform" });
defaultValues?.platform;
const isDefaultPlatform =
defaultValues?.platform == null ||
defaultValues.platform === BUILDER_PLATFORMS[0].value;
const [isOpen, setIsOpen] = useState(!isDefaultPlatform);
const toggleIsOpen = useCallback(
() => setIsOpen((isAdvancedSettingOpen) => !isAdvancedSettingOpen),
[]
);
return (
<div className={cx("d-flex", "flex-column", "gap-1")}>
<button
className={cx(
"d-flex",
"align-items-center",
"w-100",
"bg-transparent",
"border-0",
"p-0",
"h4"
)}
type="button"
onClick={toggleIsOpen}
>
Advanced settings
<ChevronFlippedIcon className="ms-1" flipped={isOpen} />
</button>
<Collapse isOpen={isOpen}>
<div className={cx("d-flex", "flex-column", "gap-3")}>
<BuilderPlatformSelector name="platform" control={control} />
</div>
</Collapse>
</div>
);
}

interface BuilderPlatformSelectorProps<T extends FieldValues>
extends UseControllerProps<T> {}

function BuilderPlatformSelector<T extends FieldValues>({
...controllerProps
}: BuilderPlatformSelectorProps<T>) {
const defaultValue = useMemo(
() =>
controllerProps.defaultValue
? controllerProps.defaultValue
: BUILDER_PLATFORMS[0],
[controllerProps.defaultValue]
);

return (
<div>
<Label for="builder-environment-platform-select-input">Platform</Label>
<Controller
{...controllerProps}
render={({
field: { onBlur, onChange, value, disabled },
fieldState: { error },
}) => (
<>
<div
className={cx(error && "is-invalid")}
data-cy="environment-platform-select"
>
<BuilderSelectorCommon
defaultValue={defaultValue}
disabled={disabled}
id="builder-environment-platform-select"
inputId="builder-environment-platform-select-input"
name={controllerProps.name}
onBlur={onBlur}
onChange={onChange}
options={BUILDER_PLATFORMS}
value={value ?? ""}
/>
</div>
<div className="invalid-feedback">
{error?.message ? (
<>{error.message}</>
) : (
<>Please select a valid platform.</>
)}
</div>
</>
)}
rules={
controllerProps.rules ?? {
required: "Please select a platform.",
}
}
/>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { DEFAULT_APP_PARAMS } from "../../../../utils/context/appParams.constant
import { useProject } from "../../../ProjectPageV2/ProjectPageContainer/ProjectPageContainer";
import { useGetRepositoriesProbesQuery } from "../../../repositories/repositories.api";
import type { SessionLauncherForm } from "../../sessionsV2.types";
import BuilderAdvancedSettings from "./BuilderAdvancedSettings";
import BuilderFrontendSelector from "./BuilderFrontendSelector";
import BuilderTypeSelector from "./BuilderTypeSelector";
import CodeRepositoryAdvancedSettings from "./CodeRepositoryAdvancedSettings";
Expand Down Expand Up @@ -104,6 +105,7 @@ export default function BuilderEnvironmentFields({
</div>
<BuilderTypeSelector name="builder_variant" control={control} />
<BuilderFrontendSelector name="frontend_variant" control={control} />
<BuilderAdvancedSettings control={control} />
</div>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export default function NewSessionLauncherModal({
default_url: DEFAULT_URL,
port: DEFAULT_PORT,
repository: "",
platform: "",
},
});
const {
Expand Down
15 changes: 15 additions & 0 deletions client/src/features/sessionsV2/session.constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ export const BUILDER_FRONTENDS = [
},
] as readonly BuilderSelectorOption[];

export const BUILDER_PLATFORMS = [
{
value: "linux/amd64" as const,
label: "linux/amd64",
description:
"The default runtime platform. Select this option unless you know your session will run on a different platform.",
},
{
value: "linux/arm64" as const,
label: "linux/arm64",
description:
"Select this option if your session will run on ARM64 compute resources.",
},
] as readonly BuilderSelectorOption<"linux/amd64" | "linux/arm64">[];

export const IMAGE_BUILD_DOCS =
"https://renku.notion.site/How-to-create-a-custom-environment-from-a-code-repository-1960df2efafc801b88f6da59a0aa8234";

Expand Down
19 changes: 18 additions & 1 deletion client/src/features/sessionsV2/session.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ import type {
SessionLauncherEnvironmentPatchParams,
} from "./api/sessionLaunchersV2.api";
import {
BUILDER_PLATFORMS,
DEFAULT_URL,
ENV_VARIABLES_RESERVED_PREFIX,
} from "./session.constants";
import { SessionLauncherForm } from "./sessionsV2.types";
import type { SessionLauncherForm } from "./sessionsV2.types";

export function getSessionFavicon(
sessionState?: SessionStatusState,
Expand Down Expand Up @@ -103,6 +104,7 @@ export function getFormattedEnvironmentValues(data: SessionLauncherForm): {
gid,
mount_directory,
name,
platform: platform_,
port,
repository_revision: repository_revision_,
repository,
Expand All @@ -118,13 +120,18 @@ export function getFormattedEnvironmentValues(data: SessionLauncherForm): {
if (environmentSelect === "custom + build") {
const context_dir = context_dir_?.trim();
const repository_revision = repository_revision_?.trim();
const platform =
BUILDER_PLATFORMS.map(({ value }) => value).find(
(value) => value === platform_
) ?? BUILDER_PLATFORMS[0].value;
return {
success: true,
data: {
environment_image_source: "build",
builder_variant,
frontend_variant,
repository,
platforms: [platform],
...(context_dir ? { context_dir } : {}),
...(repository_revision ? { repository_revision } : {}),
},
Expand Down Expand Up @@ -203,9 +210,14 @@ export function getFormattedEnvironmentValuesForEdit(
builder_variant,
context_dir,
frontend_variant,
platform: platform_,
repository_revision,
repository,
} = data;
const platform =
BUILDER_PLATFORMS.map(({ value }) => value).find(
(value) => value === platform_
) ?? BUILDER_PLATFORMS[0].value;

return {
success: true,
Expand All @@ -218,6 +230,7 @@ export function getFormattedEnvironmentValuesForEdit(
repository,
repository_revision: repository_revision ?? "",
context_dir: context_dir ?? "",
platforms: [platform],
},
},
};
Expand Down Expand Up @@ -277,6 +290,10 @@ export function getLauncherDefaultValues(
launcher.environment.environment_image_source === "build"
? launcher.environment.build_parameters.context_dir ?? ""
: "",
platform:
launcher.environment.environment_image_source === "build"
? launcher.environment.build_parameters.platforms?.at(0) ?? ""
: "",
};
}

Expand Down
11 changes: 7 additions & 4 deletions client/src/features/sessionsV2/sessionsV2.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import type { ReactNode } from "react";

import type { CloudStorageDetailsOptions } from "../project/components/cloudStorage/projectCloudStorage.types";
import type { ResourceClassWithId } from "./api/computeResources.generated-api";
import type { ResourceClassWithId } from "./api/computeResources.api";
import type {
BuildParametersPost,
DefaultUrl,
Expand Down Expand Up @@ -103,7 +103,7 @@ export interface SessionLauncherForm
// For "global" environments
environmentId: EnvironmentId;

// For "custom" + "image" environments
// For "custom + image" environments
default_url: DefaultUrl;
uid: EnvironmentUid;
gid: EnvironmentGid;
Expand All @@ -112,6 +112,9 @@ export interface SessionLauncherForm
args: string;
command: string;
strip_path_prefix: boolean;

// For "custom + build" environments
platform: string;
}

export interface SessionResources {
Expand Down Expand Up @@ -182,9 +185,9 @@ export interface DockerImage {
error?: unknown;
}

export interface BuilderSelectorOption {
export interface BuilderSelectorOption<T extends string = string> {
label: string;
value: string;
value: T;
description?: ReactNode;
}

Expand Down
Loading