Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
import { skipToken } from "@reduxjs/toolkit/query";
import cx from "classnames";
import { useContext, useMemo } from "react";
import { CircleFill, Link45deg, Pencil, Trash } from "react-bootstrap-icons";
import { Link45deg, Pencil, Trash } from "react-bootstrap-icons";
import { Card, CardBody, Col, DropdownItem, Row } from "reactstrap";

import SessionEnvironmentGitLabWarningBadge from "~/features/legacy/SessionEnvironmentGitLabWarnBadge";
import { useGetRepositoryQuery } from "~/features/repositories/api/repositories.api";
import { Loader } from "../../../components/Loader";
import AppContext from "../../../utils/context/appContext";
import { DEFAULT_APP_PARAMS } from "../../../utils/context/appParams.constants";
Expand Down Expand Up @@ -135,6 +136,15 @@ export default function SessionLauncherCard({
: skipToken
);

const {
data: imageRepositorySource,
isLoading: isLoadingImageRepositorySource,
} = useGetRepositoryQuery(
environment?.environment_image_source === "build"
? { url: environment.build_parameters.repository }
: skipToken
);

const { data: resourcePools, isLoading: isLoadingResourcePools } =
computeResourcesApi.endpoints.getResourcePools.useQueryState({});
// Ref: https://github.com/facebook/react/issues/35577
Expand Down Expand Up @@ -221,6 +231,7 @@ export default function SessionLauncherCard({
{isCodeEnvironment &&
(isLoading ||
isLoadingContainerImage ||
isLoadingImageRepositorySource ||
isLoadingResourcePools) ? (
<SessionBadge
className={cx("border-warning", "bg-warning-subtle")}
Expand All @@ -238,23 +249,17 @@ export default function SessionLauncherCard({
<BuildStatusBadge
buildStatus={lastBuild?.status}
imageCheck={containerImage}
imageSourceCheck={imageRepositorySource}
resourcePool={resourcePool}
/>
) : !hasSession ? (
<SessionBadge
className={cx("border-dark-subtle", "bg-light")}
>
<CircleFill
className={cx("me-1", "bi", "text-light-emphasis")}
/>
<span
className="text-dark-emphasis"
data-cy="session-status"
>
Not Running
</span>
</SessionBadge>
) : null}
) : (
<SessionImageBadge
data={containerImage}
isLoading={isLoadingContainerImage}
resourcePool={resourcePool}
isLoadingResourcePools={isLoadingResourcePools}
/>
)}
</Col>
<Col xs={12} xl="auto" className="d-flex">
<BuildStatusDescription
Expand Down
154 changes: 86 additions & 68 deletions client/src/features/sessionsV2/SessionView/EnvironmentCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Link, useLocation } from "react-router";
import { Badge, Card, CardBody, Col, Row } from "reactstrap";

import { ErrorAlert, WarnAlert } from "~/components/Alert";
import { useGetRepositoryQuery } from "~/features/repositories/api/repositories.api";
import { ABSOLUTE_ROUTES } from "~/routing/routes.constants";
import RtkOrDataServicesError from "../../../components/errors/RtkOrDataServicesError";
import { ErrorLabel } from "../../../components/formlabels/FormLabels";
Expand Down Expand Up @@ -217,6 +218,14 @@ function CustomImageEnvironmentValues({
? { imageUrl: environment.container_image }
: skipToken
);
const {
data: imageRepositorySource,
isLoading: isLoadingImageRepositorySource,
} = useGetRepositoryQuery(
environment?.environment_image_source === "build"
? { url: environment.build_parameters.repository }
: skipToken
);
const { data: resourcePools, isLoading: isLoadingResourcePools } =
computeResourcesApi.endpoints.getResourcePools.useQueryState({});
const resourcePool = useMemo(() => {
Expand Down Expand Up @@ -248,82 +257,91 @@ function CustomImageEnvironmentValues({
isLoadingResourcePools={isLoadingResourcePools}
/>
)}
{!isLoading && data?.accessible === false && (
<div className="mt-2">
{!data.connection && !data.provider ? (
<ErrorAlert className="mb-0" dismissible={false}>
<p className="mb-2">
The container image reference is invalid or points to an
unsupported registry. Please verify the image and check if the
registry is in the currently supported{" "}
<Link
to={{
pathname: ABSOLUTE_ROUTES.v2.integrations,
search,
}}
>
<Plugin className={cx("bi", "me-1")} />
integrations
</Link>
. If you&apos;re certain the image is correct and points to a
registry we don&apos;t currently support,{" "}
<a
target="_blank"
rel="noreferrer noopener"
href={`mailto:${renkuContactEmail}`}
>
<Send className={cx("bi", "me-1")} />
contact us
</a>{" "}
about adding an integration.
</p>
</ErrorAlert>
) : data.connection?.status === "connected" ? (
<ErrorAlert className="mb-0" dismissible={false}>
<p className="mb-0">
Either the container image reference does not exist, or you do
not have access to it.
</p>
{data?.provider?.id && (
<>
<p className={cx("mb-2", "mt-2")}>
If you think you should have access, check your
integration configuration.
</p>
{!isLoading &&
data?.accessible === false &&
!isLoadingImageRepositorySource && (
<div className="mt-2">
{imageRepositorySource?.status === "invalid" ? (
<ErrorAlert className="mb-0" dismissible={false}>
<p className="mb-2">
You do not have access to the repository used to build the
image for this session environment.
</p>
</ErrorAlert>
) : !data.connection && !data.provider ? (
<ErrorAlert className="mb-0" dismissible={false}>
<p className="mb-2">
The container image reference is invalid or points to an
unsupported registry. Please verify the image and check if
the registry is in the currently supported{" "}
<Link
className={cx("btn", "btn-primary", "btn-sm")}
to={{
pathname: ABSOLUTE_ROUTES.v2.integrations,
search,
}}
>
<Plugin className={cx("bi", "me-1")} />
View integration
integrations
</Link>
</>
)}
</ErrorAlert>
) : (
<WarnAlert className="mb-0" dismissible={false}>
<p className="mb-2">
This container image reference is from a supported registry,
but you haven&apos;t activated the integration yet. Activate
the integration to check if you have access to this image.
</p>
<Link
className={cx("btn", "btn-primary", "btn-sm")}
to={{
pathname: ABSOLUTE_ROUTES.v2.integrations,
search,
}}
>
<Plugin className={cx("bi", "me-1")} />
Go to Integration
</Link>
</WarnAlert>
)}
</div>
)}
. If you&apos;re certain the image is correct and points to
a registry we don&apos;t currently support,{" "}
<a
target="_blank"
rel="noreferrer noopener"
href={`mailto:${renkuContactEmail}`}
>
<Send className={cx("bi", "me-1")} />
contact us
</a>{" "}
about adding an integration.
</p>
</ErrorAlert>
) : data.connection?.status === "connected" ? (
<ErrorAlert className="mb-0" dismissible={false}>
<p className="mb-0">
Either the container image reference does not exist, or you
do not have access to it.
</p>
{data?.provider?.id && (
<>
<p className={cx("mb-2", "mt-2")}>
If you think you should have access, check your
integration configuration.
</p>
<Link
className={cx("btn", "btn-primary", "btn-sm")}
to={{
pathname: ABSOLUTE_ROUTES.v2.integrations,
search,
}}
>
<Plugin className={cx("bi", "me-1")} />
View integration
</Link>
</>
)}
</ErrorAlert>
) : (
<WarnAlert className="mb-0" dismissible={false}>
<p className="mb-2">
This container image reference is from a supported registry,
but you haven&apos;t activated the integration yet. Activate
the integration to check if you have access to this image.
</p>
<Link
className={cx("btn", "btn-primary", "btn-sm")}
to={{
pathname: ABSOLUTE_ROUTES.v2.integrations,
search,
}}
>
<Plugin className={cx("bi", "me-1")} />
Go to Integration
</Link>
</WarnAlert>
)}
</div>
)}
</div>
<EnvironmentRowWithLabel
dataCy="session-view-session-environment-image"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
} from "reactstrap";

import BuildLogsModal from "~/features/logsDisplay/BuildLogsModal";
import type { RepositoryProviderData } from "~/features/repositories/api/repositories.api";
import { ButtonWithMenuV2 } from "../../../components/buttons/Button";
import RtkOrDataServicesError from "../../../components/errors/RtkOrDataServicesError";
import { ExternalLink } from "../../../components/LegacyExternalLinks";
Expand All @@ -65,12 +66,14 @@ import { isImageCompatibleWith } from "../session.utils";
interface BuildStatusBadgeProps {
buildStatus: Build["status"];
imageCheck?: ImageCheckResponse | null;
imageSourceCheck?: RepositoryProviderData | null;
resourcePool?: ResourcePoolWithId;
}

export function BuildStatusBadge({
buildStatus,
imageCheck,
imageSourceCheck,
resourcePool,
}: BuildStatusBadgeProps) {
const isCompatible = useMemo(() => {
Expand All @@ -80,6 +83,11 @@ export function BuildStatusBadge({
return isImageCompatibleWith(imageCheck, resourcePool.platform);
}, [imageCheck, resourcePool]);

const privateImageNotFound = useMemo(
() => imageSourceCheck?.status === "invalid",
[imageSourceCheck?.status]
);

const badgeIcon =
buildStatus === "in_progress" ? (
<Loader className="me-1" inline size={12} />
Expand All @@ -90,6 +98,8 @@ export function BuildStatusBadge({
const badgeText =
isCompatible === false
? "Image incompatible"
: privateImageNotFound
? "Image not accessible"
: buildStatus === "in_progress"
? "Build in progress"
: buildStatus === "cancelled"
Expand All @@ -99,7 +109,7 @@ export function BuildStatusBadge({
: "Build failed";

const badgeColorClasses =
isCompatible === false
isCompatible === false || privateImageNotFound
? ["border-danger", "bg-danger-subtle", "text-danger-emphasis"]
: buildStatus === "in_progress"
? ["border-warning", "bg-warning-subtle", "text-warning-emphasis"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
import { skipToken } from "@reduxjs/toolkit/query";
import cx from "classnames";
import { useContext, useMemo } from "react";
import { type Control } from "react-hook-form";
import { useWatch, type Control, type Path } from "react-hook-form";

import { useProject } from "~/routes/projects/root";
import { ErrorAlert, WarnAlert } from "../../../../components/Alert";
import { ErrorAlert, InfoAlert, WarnAlert } from "../../../../components/Alert";
import RtkOrDataServicesError from "../../../../components/errors/RtkOrDataServicesError";
import { Loader } from "../../../../components/Loader";
import AppContext from "../../../../utils/context/appContext";
Expand Down Expand Up @@ -55,12 +55,26 @@ export default function BuilderEnvironmentFields({
repositories.length > 0 ? repositories : skipToken
);

const selectedRepositoryUrl = useWatch({
control,
name: "repository" as Path<SessionLauncherForm>,
}) as string;

const selectedRepositoryIsPrivate = useMemo(
() =>
data?.find(
(repo) =>
repo.url === selectedRepositoryUrl &&
repo.data?.metadata?.visibility === "private"
),
[data, selectedRepositoryUrl]
);

const firstEligibleRepository = useMemo(
() =>
data?.findIndex(
(repo) =>
repo.data?.status === "valid" &&
repo.data.metadata?.visibility === "public"
repo.data?.status === "valid" && repo.data.metadata?.pull_permission
),
[data]
);
Expand Down Expand Up @@ -91,8 +105,8 @@ export default function BuilderEnvironmentFields({
</>
) : firstEligibleRepository == null || firstEligibleRepository < 0 ? (
<WarnAlert dismissible={false}>
No publicly accessible code repositories found in this project. RenkuLab
can only build session environments from public code repositories.
No accessible code repositories found in this project. Please ensure that
you have proper access to them.
</WarnAlert>
) : (
<div className={cx("d-flex", "flex-column", "gap-3")}>
Expand All @@ -102,6 +116,12 @@ export default function BuilderEnvironmentFields({
control={control}
repositoriesDetails={data}
/>
{selectedRepositoryIsPrivate && (
<InfoAlert dismissible={false} timeout={0}>
This is a private repository, launching the session will only be
available to users who have pull access to the repository.
</InfoAlert>
)}
<CodeRepositoryAdvancedSettings control={control} />
</div>
<BuilderTypeSelector name="builder_variant" control={control} />
Expand All @@ -114,9 +134,7 @@ export default function BuilderEnvironmentFields({
<div className={cx("d-flex", "flex-column", "gap-3")}>
{!isEdit && (
<p className={cx("mb-0")}>
Let RenkuLab create a customized environment from a code repository. A
container image will be created based on the requirements found in the
code repository.
Let RenkuLab create a customized environment from a code repository.
</p>
)}
{content}
Expand Down
Loading
Loading