Skip to content
Draft
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
4 changes: 4 additions & 0 deletions front/src/components/onboarding/onboardingState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ export interface OnboardingState {
setup_seen: boolean;
chat_feature_tour_seen: boolean;
response_attachment_tip_seen: boolean;
sandbox_settings_seen: boolean;
}

const DEFAULT_ONBOARDING_STATE: OnboardingState = {
setup_seen: false,
chat_feature_tour_seen: false,
response_attachment_tip_seen: false,
sandbox_settings_seen: false,
};

const COMPLETED_ONBOARDING_STATE: OnboardingState = {
setup_seen: true,
chat_feature_tour_seen: true,
response_attachment_tip_seen: true,
sandbox_settings_seen: true,
};

function parseJson(raw: string | null): unknown {
Expand Down Expand Up @@ -78,6 +81,7 @@ export function getOnboardingState(): OnboardingState {
chat_feature_tour_seen: parsed.chat_feature_tour_seen === true,
response_attachment_tip_seen:
parsed.response_attachment_tip_seen === true,
sandbox_settings_seen: parsed.sandbox_settings_seen === true,
};
}

Expand Down
93 changes: 93 additions & 0 deletions front/src/components/settings-page/sandbox-onboarding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { useState } from "react";
import { ChevronDown, HelpCircle, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { cn } from "@/lib/utils";
import {
getOnboardingState,
updateOnboardingState,
} from "@/components/onboarding/onboardingState";

const SandboxOnboarding: React.FC = () => {
const [dismissed, setDismissed] = useState(
() => getOnboardingState().sandbox_settings_seen,
);
const [expanded, setExpanded] = useState(false);

const handleDismiss = () => {
updateOnboardingState({ sandbox_settings_seen: true });
setDismissed(true);
};

if (dismissed) return null;

return (
<Alert variant="info" className="relative">
<HelpCircle />
<AlertTitle>Что такое Sandbox?</AlertTitle>
<Button
variant="ghost"
size="icon"
onClick={handleDismiss}
aria-label="Скрыть подсказку"
className="absolute right-2 top-2 h-7 w-7 text-current hover:bg-black/5 dark:hover:bg-white/10"
>
<X className="size-4" />
</Button>
<AlertDescription>
<p>
Sandbox — это изолированная среда, в которой агент запускает код,
работает с файлами и использует большинство инструментов. Без
настроенного и активного провайдера агент не сможет выполнять эти
действия. Создайте провайдера кнопкой «Добавить», а затем активируйте
его.
</p>
<button
type="button"
onClick={() => setExpanded((prev) => !prev)}
className="mt-1 inline-flex items-center gap-1 font-medium hover:underline"
>
<ChevronDown
className={cn(
"size-4 transition-transform",
expanded && "rotate-180",
)}
/>
{expanded ? "Скрыть подробности" : "Подробнее о LOCAL_DOCKER"}
</button>
{expanded && (
<div className="mt-1 space-y-2">
<p>
<span className="font-medium">LOCAL_DOCKER</span> запускает
sandbox локально в Docker-контейнере на этом же сервере. Это
удобный вариант для локальной работы: не нужны сторонние сервисы,
достаточно установленного и запущенного Docker.
</p>
<p>
Опция <span className="font-mono font-medium">not_remove</span>{" "}
(«Не удалять контейнер») определяет, что происходит с контейнером
после остановки sandbox:
</p>
<ul className="list-disc space-y-1 pl-5">
<li>
<span className="font-medium">Выключена (по умолчанию):</span>{" "}
контейнер удаляется после остановки, и при следующем запуске
создаётся новый — чистое окружение каждый раз.
</li>
<li>
<span className="font-medium">Включена:</span> контейнер не
удаляется и переиспользуется при следующем запуске.
Установленные пакеты и файлы вне рабочей директории сохраняются,
а запуск происходит быстрее. Если поднять Jupyter в
переиспользуемом контейнере не удаётся, он пересоздаётся
автоматически.
</li>
</ul>
</div>
)}
</AlertDescription>
</Alert>
);
};

export default SandboxOnboarding;
2 changes: 2 additions & 0 deletions front/src/components/settings-page/sandbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
toPermissionsApiPayload,
} from "./forms/resource-permissions-utils";
import { compactSchemaValues } from "./forms/schema-fields-utils";
import SandboxOnboarding from "./sandbox-onboarding";

interface SandboxProviderResponse {
id: string;
Expand Down Expand Up @@ -682,6 +683,7 @@ export const SandboxSettings: React.FC = () => {

return (
<div className="space-y-6">
<SandboxOnboarding />
<div className="flex items-center justify-between">
<div>
<h3 className="font-medium">Sandbox провайдеры</h3>
Expand Down
Loading