From 015f9f8dadc86459523584a2d47fd0c80ac07c5f Mon Sep 17 00:00:00 2001 From: peterschmidt85 Date: Mon, 13 Oct 2025 10:39:26 -0700 Subject: [PATCH 1/3] [UI] A prototype of the "Connect" section to show on the running dev environment page (WIP) --- .../pages/Runs/Details/RunDetails/index.tsx | 256 +++++++++++++++++- .../Details/RunDetails/styles.module.scss | 13 + 2 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 frontend/src/pages/Runs/Details/RunDetails/styles.module.scss diff --git a/frontend/src/pages/Runs/Details/RunDetails/index.tsx b/frontend/src/pages/Runs/Details/RunDetails/index.tsx index f5613a288..9bb96a951 100644 --- a/frontend/src/pages/Runs/Details/RunDetails/index.tsx +++ b/frontend/src/pages/Runs/Details/RunDetails/index.tsx @@ -4,13 +4,31 @@ import { useParams } from 'react-router-dom'; import { get as _get } from 'lodash'; import { format } from 'date-fns'; -import { Box, ColumnLayout, Container, Header, Loader, NavigateLink, StatusIndicator } from 'components'; +import { + Alert, + Box, + Button, + Code, + ColumnLayout, + Container, + ExpandableSection, + Header, + Loader, + NavigateLink, + Popover, + SpaceBetween, + StatusIndicator, + Tabs, + Wizard, +} from 'components'; import { DATE_TIME_FORMAT } from 'consts'; +import { copyToClipboard } from 'libs'; import { getRunError, getRunPriority, getRunStatusMessage, getStatusIconColor, getStatusIconType } from 'libs/run'; import { useGetRunQuery } from 'services/run'; import { finishedRunStatuses } from 'pages/Runs/constants'; +import { runIsStopped } from 'pages/Runs/utils'; import { ROUTES } from '../../../../routes'; import { @@ -24,6 +42,8 @@ import { } from '../../List/helpers'; import { JobList } from '../Jobs/List'; +import styles from './styles.module.scss'; + export const RunDetails = () => { const { t } = useTranslation(); const params = useParams(); @@ -37,6 +57,28 @@ export const RunDetails = () => { const serviceUrl = runData ? getRunListItemServiceUrl(runData) : null; + const getAttachCommand = (runData: IRun) => { + const attachCommand = `dstack attach ${runData.run_spec.run_name}`; + + const copyAttachCommand = () => { + copyToClipboard(attachCommand); + }; + + return [attachCommand, copyAttachCommand] as const; + }; + + const getSSHCommand = (runData: IRun) => { + const sshCommand = `ssh ${runData.run_spec.run_name}`; + + const copySSHCommand = () => { + copyToClipboard(sshCommand); + }; + + return [sshCommand, copySSHCommand] as const; + }; + + const [activeStepIndex, setActiveStepIndex] = React.useState(0); + if (isLoadingRun) return ( @@ -46,6 +88,9 @@ export const RunDetails = () => { if (!runData) return null; + const [attachCommand, copyAttachCommand] = getAttachCommand(runData); + const [sshCommand, copySSHCommand] = getSSHCommand(runData); + const status = finishedRunStatuses.includes(runData.status) ? (runData.latest_job_submission?.status ?? runData.status) : runData.status; @@ -53,6 +98,8 @@ export const RunDetails = () => { ? runData.latest_job_submission?.termination_reason : null; + const openInIDEUrl = `${runData.run_spec.configuration.ide}://vscode-remote/ssh-remote+${runData.run_spec.run_name}/${runData.run_spec.working_dir || 'workflow'}`; + return ( <> {t('common.general')}}> @@ -168,6 +215,213 @@ export const RunDetails = () => { )} + {runData.run_spec.configuration.type === 'dev-environment' && !runIsStopped(runData.status) && ( + +
Connect
+ + {runData.status === 'running' && ( + `Step ${stepNumber}`, + collapsedStepsLabel: (stepNumber, stepsCount) => `Step ${stepNumber} of ${stepsCount}`, + skipToButtonLabel: (step) => `Skip to ${step.title}`, + navigationAriaLabel: 'Steps', + // cancelButton: "Cancel", + previousButton: 'Previous', + nextButton: 'Next', + optional: 'required', + }} + onNavigate={({ detail }) => setActiveStepIndex(detail.requestedStepIndex)} + activeStepIndex={activeStepIndex} + onSubmit={() => { + window.open(openInIDEUrl, '_blank'); + }} + submitButtonText="Open in VS Code" + allowSkipTo={true} + steps={[ + { + title: 'Attach', + // info: openHelpPanel(CLI_INFO)} />, + content: ( + + To access this run, first you need to attach to it. +
+ {attachCommand} + +
+ + {t('common.copied')} + + } + > +
+
+ + + + + To use dstack, install the CLI on your local machine. + +
+ + uv tool install dstack -U + + +
+ + {t('common.copied')} + + } + > +
+
+ + ), + }, + { + label: 'pip', + id: 'pip', + content: ( + <> +
+ + pip install dstack -U + + +
+ + {t('common.copied')} + + } + > +
+
+ + ), + }, + ]} + /> +
+
+
+ ), + isOptional: true, + }, + { + title: 'Open', + // info: openHelpPanel(CLI_INFO)} />, + description: 'After the CLI is attached, you can open the dev environment in VS Code.', + content: ( + + + + + +
+ {sshCommand} + +
+ + {t('common.copied')} + + } + > +
+
+
+
+
+ ), + isOptional: true, + }, + ]} + /> + )} + + {runData.status === 'running' && ( + + + Waiting for the run to start. + + )} +
+ )} + {runData.jobs.length > 1 && ( Date: Tue, 14 Oct 2025 21:19:55 +0300 Subject: [PATCH 2/3] [UI] A prototype of the "Connect" section to show on the running dev environment page (WIP) --- .../pages/Runs/Details/RunDetails/index.tsx | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/frontend/src/pages/Runs/Details/RunDetails/index.tsx b/frontend/src/pages/Runs/Details/RunDetails/index.tsx index 9bb96a951..a842d27ac 100644 --- a/frontend/src/pages/Runs/Details/RunDetails/index.tsx +++ b/frontend/src/pages/Runs/Details/RunDetails/index.tsx @@ -25,12 +25,12 @@ import { import { DATE_TIME_FORMAT } from 'consts'; import { copyToClipboard } from 'libs'; import { getRunError, getRunPriority, getRunStatusMessage, getStatusIconColor, getStatusIconType } from 'libs/run'; +import { ROUTES } from 'routes'; import { useGetRunQuery } from 'services/run'; import { finishedRunStatuses } from 'pages/Runs/constants'; import { runIsStopped } from 'pages/Runs/utils'; -import { ROUTES } from '../../../../routes'; import { getRunListItemBackend, getRunListItemInstanceId, @@ -44,6 +44,9 @@ import { JobList } from '../Jobs/List'; import styles from './styles.module.scss'; +const UvInstallCommand = 'uv tool install dstack -U'; +const PipInstallCommand = 'pip install dstack -U'; + export const RunDetails = () => { const { t } = useTranslation(); const params = useParams(); @@ -94,6 +97,7 @@ export const RunDetails = () => { const status = finishedRunStatuses.includes(runData.status) ? (runData.latest_job_submission?.status ?? runData.status) : runData.status; + const terminationReason = finishedRunStatuses.includes(runData.status) ? runData.latest_job_submission?.termination_reason : null; @@ -233,15 +237,12 @@ export const RunDetails = () => { }} onNavigate={({ detail }) => setActiveStepIndex(detail.requestedStepIndex)} activeStepIndex={activeStepIndex} - onSubmit={() => { - window.open(openInIDEUrl, '_blank'); - }} + onSubmit={() => window.open(openInIDEUrl, '_blank')} submitButtonText="Open in VS Code" allowSkipTo={true} steps={[ { title: 'Attach', - // info: openHelpPanel(CLI_INFO)} />, content: ( To access this run, first you need to attach to it. @@ -272,8 +273,9 @@ export const RunDetails = () => { - + To use dstack, install the CLI on your local machine. + { <>
- uv tool install dstack -U + {UvInstallCommand}
@@ -304,9 +306,7 @@ export const RunDetails = () => { iconName="copy" variant="normal" onClick={() => - copyToClipboard( - 'uv tool install dstack -U', - ) + copyToClipboard(UvInstallCommand) } /> @@ -322,7 +322,7 @@ export const RunDetails = () => { <>
- pip install dstack -U + {PipInstallCommand}
@@ -342,9 +342,7 @@ export const RunDetails = () => { iconName="copy" variant="normal" onClick={() => - copyToClipboard( - 'pip install dstack -U', - ) + copyToClipboard(PipInstallCommand) } /> @@ -363,22 +361,20 @@ export const RunDetails = () => { }, { title: 'Open', - // info: openHelpPanel(CLI_INFO)} />, description: 'After the CLI is attached, you can open the dev environment in VS Code.', content: ( + - +
{sshCommand} @@ -415,7 +411,7 @@ export const RunDetails = () => { {runData.status === 'running' && ( - + Waiting for the run to start. )} From 56efbd7a7161cfbac4ee421e090e8aeac4d86e75 Mon Sep 17 00:00:00 2001 From: Oleg Vavilov Date: Tue, 14 Oct 2025 21:30:26 +0300 Subject: [PATCH 3/3] [UI] A prototype of the "Connect" section to show on the running dev environment page (WIP) --- .../index.tsx | 244 +++++++++++++++++ .../styles.module.scss | 0 .../pages/Runs/Details/RunDetails/index.tsx | 249 +----------------- 3 files changed, 247 insertions(+), 246 deletions(-) create mode 100644 frontend/src/pages/Runs/Details/RunDetails/ConnectToRunWithDevEnvConfiguration/index.tsx rename frontend/src/pages/Runs/Details/RunDetails/{ => ConnectToRunWithDevEnvConfiguration}/styles.module.scss (100%) diff --git a/frontend/src/pages/Runs/Details/RunDetails/ConnectToRunWithDevEnvConfiguration/index.tsx b/frontend/src/pages/Runs/Details/RunDetails/ConnectToRunWithDevEnvConfiguration/index.tsx new file mode 100644 index 000000000..36bfa2379 --- /dev/null +++ b/frontend/src/pages/Runs/Details/RunDetails/ConnectToRunWithDevEnvConfiguration/index.tsx @@ -0,0 +1,244 @@ +import React, { FC } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { + Alert, + Box, + Button, + Code, + Container, + ExpandableSection, + Header, + Popover, + SpaceBetween, + StatusIndicator, + Tabs, + Wizard, +} from 'components'; + +import { copyToClipboard } from 'libs'; + +import styles from './styles.module.scss'; + +const UvInstallCommand = 'uv tool install dstack -U'; +const PipInstallCommand = 'pip install dstack -U'; + +export const ConnectToRunWithDevEnvConfiguration: FC<{ run: IRun }> = ({ run }) => { + const { t } = useTranslation(); + + const getAttachCommand = (runData: IRun) => { + const attachCommand = `dstack attach ${runData.run_spec.run_name}`; + + const copyAttachCommand = () => { + copyToClipboard(attachCommand); + }; + + return [attachCommand, copyAttachCommand] as const; + }; + + const getSSHCommand = (runData: IRun) => { + const sshCommand = `ssh ${runData.run_spec.run_name}`; + + const copySSHCommand = () => { + copyToClipboard(sshCommand); + }; + + return [sshCommand, copySSHCommand] as const; + }; + + const [activeStepIndex, setActiveStepIndex] = React.useState(0); + const [attachCommand, copyAttachCommand] = getAttachCommand(run); + const [sshCommand, copySSHCommand] = getSSHCommand(run); + + const openInIDEUrl = `${run.run_spec.configuration.ide}://vscode-remote/ssh-remote+${run.run_spec.run_name}/${run.run_spec.working_dir || 'workflow'}`; + + return ( + +
Connect
+ + {run.status === 'running' && ( + `Step ${stepNumber}`, + collapsedStepsLabel: (stepNumber, stepsCount) => `Step ${stepNumber} of ${stepsCount}`, + skipToButtonLabel: (step) => `Skip to ${step.title}`, + navigationAriaLabel: 'Steps', + previousButton: 'Previous', + nextButton: 'Next', + optional: 'required', + }} + onNavigate={({ detail }) => setActiveStepIndex(detail.requestedStepIndex)} + activeStepIndex={activeStepIndex} + onSubmit={() => window.open(openInIDEUrl, '_blank')} + submitButtonText="Open in VS Code" + allowSkipTo + steps={[ + { + title: 'Attach', + content: ( + + To access this run, first you need to attach to it. +
+ {attachCommand} + +
+ {t('common.copied')}} + > +
+
+ + + + + To use dstack, install the CLI on your local machine. + + +
+ {UvInstallCommand} + +
+ + {t('common.copied')} + + } + > +
+
+ + ), + }, + { + label: 'pip', + id: 'pip', + content: ( + <> +
+ {PipInstallCommand} + +
+ + {t('common.copied')} + + } + > +
+
+ + ), + }, + ]} + /> +
+
+
+ ), + isOptional: true, + }, + { + title: 'Open', + description: 'After the CLI is attached, you can open the dev environment in VS Code.', + content: ( + + + + + + +
+ {sshCommand} + +
+ + {t('common.copied')} + + } + > +
+
+
+
+
+ ), + isOptional: true, + }, + ]} + /> + )} + + {run.status === 'running' && ( + + + Waiting for the run to start. + + )} +
+ ); +}; diff --git a/frontend/src/pages/Runs/Details/RunDetails/styles.module.scss b/frontend/src/pages/Runs/Details/RunDetails/ConnectToRunWithDevEnvConfiguration/styles.module.scss similarity index 100% rename from frontend/src/pages/Runs/Details/RunDetails/styles.module.scss rename to frontend/src/pages/Runs/Details/RunDetails/ConnectToRunWithDevEnvConfiguration/styles.module.scss diff --git a/frontend/src/pages/Runs/Details/RunDetails/index.tsx b/frontend/src/pages/Runs/Details/RunDetails/index.tsx index a842d27ac..aab63a3ed 100644 --- a/frontend/src/pages/Runs/Details/RunDetails/index.tsx +++ b/frontend/src/pages/Runs/Details/RunDetails/index.tsx @@ -4,26 +4,9 @@ import { useParams } from 'react-router-dom'; import { get as _get } from 'lodash'; import { format } from 'date-fns'; -import { - Alert, - Box, - Button, - Code, - ColumnLayout, - Container, - ExpandableSection, - Header, - Loader, - NavigateLink, - Popover, - SpaceBetween, - StatusIndicator, - Tabs, - Wizard, -} from 'components'; +import { Box, ColumnLayout, Container, Header, Loader, NavigateLink, StatusIndicator } from 'components'; import { DATE_TIME_FORMAT } from 'consts'; -import { copyToClipboard } from 'libs'; import { getRunError, getRunPriority, getRunStatusMessage, getStatusIconColor, getStatusIconType } from 'libs/run'; import { ROUTES } from 'routes'; import { useGetRunQuery } from 'services/run'; @@ -41,11 +24,7 @@ import { getRunListItemSpot, } from '../../List/helpers'; import { JobList } from '../Jobs/List'; - -import styles from './styles.module.scss'; - -const UvInstallCommand = 'uv tool install dstack -U'; -const PipInstallCommand = 'pip install dstack -U'; +import { ConnectToRunWithDevEnvConfiguration } from './ConnectToRunWithDevEnvConfiguration'; export const RunDetails = () => { const { t } = useTranslation(); @@ -60,28 +39,6 @@ export const RunDetails = () => { const serviceUrl = runData ? getRunListItemServiceUrl(runData) : null; - const getAttachCommand = (runData: IRun) => { - const attachCommand = `dstack attach ${runData.run_spec.run_name}`; - - const copyAttachCommand = () => { - copyToClipboard(attachCommand); - }; - - return [attachCommand, copyAttachCommand] as const; - }; - - const getSSHCommand = (runData: IRun) => { - const sshCommand = `ssh ${runData.run_spec.run_name}`; - - const copySSHCommand = () => { - copyToClipboard(sshCommand); - }; - - return [sshCommand, copySSHCommand] as const; - }; - - const [activeStepIndex, setActiveStepIndex] = React.useState(0); - if (isLoadingRun) return ( @@ -91,9 +48,6 @@ export const RunDetails = () => { if (!runData) return null; - const [attachCommand, copyAttachCommand] = getAttachCommand(runData); - const [sshCommand, copySSHCommand] = getSSHCommand(runData); - const status = finishedRunStatuses.includes(runData.status) ? (runData.latest_job_submission?.status ?? runData.status) : runData.status; @@ -102,8 +56,6 @@ export const RunDetails = () => { ? runData.latest_job_submission?.termination_reason : null; - const openInIDEUrl = `${runData.run_spec.configuration.ide}://vscode-remote/ssh-remote+${runData.run_spec.run_name}/${runData.run_spec.working_dir || 'workflow'}`; - return ( <> {t('common.general')}}> @@ -220,202 +172,7 @@ export const RunDetails = () => { {runData.run_spec.configuration.type === 'dev-environment' && !runIsStopped(runData.status) && ( - -
Connect
- - {runData.status === 'running' && ( - `Step ${stepNumber}`, - collapsedStepsLabel: (stepNumber, stepsCount) => `Step ${stepNumber} of ${stepsCount}`, - skipToButtonLabel: (step) => `Skip to ${step.title}`, - navigationAriaLabel: 'Steps', - // cancelButton: "Cancel", - previousButton: 'Previous', - nextButton: 'Next', - optional: 'required', - }} - onNavigate={({ detail }) => setActiveStepIndex(detail.requestedStepIndex)} - activeStepIndex={activeStepIndex} - onSubmit={() => window.open(openInIDEUrl, '_blank')} - submitButtonText="Open in VS Code" - allowSkipTo={true} - steps={[ - { - title: 'Attach', - content: ( - - To access this run, first you need to attach to it. -
- {attachCommand} - -
- - {t('common.copied')} - - } - > -
-
- - - - - To use dstack, install the CLI on your local machine. - - -
- - {UvInstallCommand} - - -
- - {t('common.copied')} - - } - > -
-
- - ), - }, - { - label: 'pip', - id: 'pip', - content: ( - <> -
- - {PipInstallCommand} - - -
- - {t('common.copied')} - - } - > -
-
- - ), - }, - ]} - /> -
-
-
- ), - isOptional: true, - }, - { - title: 'Open', - description: 'After the CLI is attached, you can open the dev environment in VS Code.', - content: ( - - - - - - -
- {sshCommand} - -
- - {t('common.copied')} - - } - > -
-
-
-
-
- ), - isOptional: true, - }, - ]} - /> - )} - - {runData.status === 'running' && ( - - - Waiting for the run to start. - - )} -
+ )} {runData.jobs.length > 1 && (