@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
22import { useTranslation } from 'react-i18next' ;
33import { useNavigate , useParams } from 'react-router-dom' ;
44import { debounce } from 'lodash' ;
5+ import Wizard from "@cloudscape-design/components/wizard" ;
56
67import {
78 Box ,
@@ -40,6 +41,9 @@ import { ProjectSecrets } from '../../Secrets';
4041import { CLI_INFO } from './constants' ;
4142
4243import styles from './styles.module.scss' ;
44+ import { ExpandableSection , Tabs } from '@cloudscape-design/components' ;
45+ import { useGetRunsQuery } from 'services/run' ;
46+ import { copyToClipboard } from 'libs' ;
4347
4448export const ProjectSettings : React . FC = ( ) => {
4549 const { t } = useTranslation ( ) ;
@@ -167,6 +171,21 @@ export const ProjectSettings: React.FC = () => {
167171 } ) ;
168172 } ;
169173
174+ const [
175+ activeStepIndex ,
176+ setActiveStepIndex
177+ ] = React . useState ( 0 ) ;
178+
179+
180+ const { data : runsData } = useGetRunsQuery ( {
181+ limit : 1 ,
182+ } ) ;
183+ const [ expanded , setExpanded ] = React . useState ( false ) ;
184+
185+ useEffect ( ( ) => {
186+ setExpanded ( ! runsData || runsData . length === 0 ) ;
187+ } , [ runsData ] ) ;
188+
170189 if ( isLoadingPage )
171190 return (
172191 < Container >
@@ -179,53 +198,144 @@ export const ProjectSettings: React.FC = () => {
179198 { data && backendsData && gatewaysData && (
180199 < SpaceBetween size = "l" >
181200 { isProjectMember && (
182- < Container
183- header = {
184- < Header variant = "h2" info = { < InfoLink onFollow = { ( ) => openHelpPanel ( CLI_INFO ) } /> } >
185- { t ( 'projects.edit.cli' ) }
186- </ Header >
187- }
201+ < ExpandableSection
202+ variant = "container"
203+ headerText = "CLI"
204+ expanded = { expanded }
205+ onChange = { ( { detail } ) => setExpanded ( detail . expanded ) }
206+ headerActions = { < Button iconName = 'script' variant = { expanded ? "normal" : "primary" } onClick = { ( ) => setExpanded ( ( prev ) => ! prev ) } > </ Button > }
207+ // headerInfo={<InfoLink onFollow={() => openHelpPanel(CLI_INFO)} />}
188208 >
189- < SpaceBetween size = "s" >
190- < Box variant = "p" color = "text-body-secondary" >
191- Run the following commands to set up the CLI for this project
192- </ Box >
193-
194- < div className = { styles . codeWrapper } >
195- < Hotspot hotspotId = { HotspotIds . CONFIGURE_CLI_COMMAND } >
196- < Code className = { styles . code } > { configCliCommand } </ Code >
197-
198- < div className = { styles . copy } >
199- < Popover
200- dismissButton = { false }
201- position = "top"
202- size = "small"
203- triggerType = "custom"
204- content = { < StatusIndicator type = "success" > { t ( 'common.copied' ) } </ StatusIndicator > }
205- >
206- < Button
207- formAction = "none"
208- iconName = "copy"
209- variant = "normal"
210- onClick = { copyCliCommand }
211- />
212- </ Popover >
213- </ div >
214- </ Hotspot >
215- </ div >
216- </ SpaceBetween >
217- </ Container >
209+ < Wizard
210+ i18nStrings = { {
211+ stepNumberLabel : stepNumber =>
212+ `Step ${ stepNumber } ` ,
213+ collapsedStepsLabel : ( stepNumber , stepsCount ) =>
214+ `Step ${ stepNumber } of ${ stepsCount } ` ,
215+ skipToButtonLabel : ( step , stepNumber ) =>
216+ `Skip to ${ step . title } ` ,
217+ navigationAriaLabel : "Steps" ,
218+ // cancelButton: "Cancel",
219+ previousButton : "Previous" ,
220+ nextButton : "Next" ,
221+ optional : "required"
222+ } }
223+ onNavigate = { ( { detail } ) =>
224+ setActiveStepIndex ( detail . requestedStepIndex )
225+ }
226+ activeStepIndex = { activeStepIndex }
227+ onSubmit = { ( ) => setExpanded ( false ) }
228+ submitButtonText = "Dismiss"
229+ allowSkipTo = { true }
230+ steps = { [
231+ {
232+ title : "Install CLI" ,
233+ // info: <InfoLink onFollow={() => openHelpPanel(CLI_INFO)} />,
234+ description : "To use dstack, install the CLI on your local machine." ,
235+ content : (
236+ < Tabs
237+ variant = "stacked"
238+ tabs = { [
239+ {
240+ label : "uv" ,
241+ id : "uv" ,
242+ content : < >
243+ < div className = { styles . codeWrapper } >
244+ < Code className = { styles . code } > uv tool install dstack -U</ Code >
245+
246+ < div className = { styles . copy } >
247+ < Popover
248+ dismissButton = { false }
249+ position = "top"
250+ size = "small"
251+ triggerType = "custom"
252+ content = { < StatusIndicator type = "success" > { t ( 'common.copied' ) } </ StatusIndicator > }
253+ >
254+ < Button
255+ formAction = "none"
256+ iconName = "copy"
257+ variant = "normal"
258+ onClick = { ( ) => copyToClipboard ( 'uv tool install dstack -U' ) }
259+ />
260+ </ Popover >
261+ </ div >
262+ </ div >
263+ </ >
264+ } ,
265+ {
266+ label : "pip" ,
267+ id : "pip" ,
268+ content : < >
269+ < div className = { styles . codeWrapper } >
270+ < Code className = { styles . code } > pip install dstack -U</ Code >
271+
272+ < div className = { styles . copy } >
273+ < Popover
274+ dismissButton = { false }
275+ position = "top"
276+ size = "small"
277+ triggerType = "custom"
278+ content = { < StatusIndicator type = "success" > { t ( 'common.copied' ) } </ StatusIndicator > }
279+ >
280+ < Button
281+ formAction = "none"
282+ iconName = "copy"
283+ variant = "normal"
284+ onClick = { ( ) => copyToClipboard ( 'pip install dstack -U' ) }
285+ />
286+ </ Popover >
287+ </ div >
288+ </ div >
289+ </ >
290+ } ] }
291+ />
292+ ) ,
293+ isOptional : true ,
294+ } ,
295+ {
296+ title : "Add project" ,
297+ // info: <InfoLink onFollow={() => openHelpPanel(CLI_INFO)} />,
298+ description : "To use dstack with this project, run the following command." ,
299+ content : (
300+ < div className = { styles . codeWrapper } >
301+ < Hotspot hotspotId = { HotspotIds . CONFIGURE_CLI_COMMAND } >
302+ < Code className = { styles . code } > { configCliCommand } </ Code >
303+
304+ < div className = { styles . copy } >
305+ < Popover
306+ dismissButton = { false }
307+ position = "top"
308+ size = "small"
309+ triggerType = "custom"
310+ content = { < StatusIndicator type = "success" > { t ( 'common.copied' ) } </ StatusIndicator > }
311+ >
312+ < Button
313+ formAction = "none"
314+ iconName = "copy"
315+ variant = "normal"
316+ onClick = { copyCliCommand }
317+ />
318+ </ Popover >
319+ </ div >
320+ </ Hotspot >
321+ </ div >
322+ ) ,
323+ isOptional : true ,
324+ } ,
325+ ] }
326+ />
327+ </ ExpandableSection >
218328 ) }
219329
220330 < BackendsTable
221331 backends = { backendsData }
222332 { ...( isProjectManager ( data )
223333 ? {
224- onClickAddBackend : addBackend ,
225- editBackend : editBackend ,
226- deleteBackends : deleteBackend ,
227- isDisabledDelete : isDeletingBackend ,
228- }
334+ onClickAddBackend : addBackend ,
335+ editBackend : editBackend ,
336+ deleteBackends : deleteBackend ,
337+ isDisabledDelete : isDeletingBackend ,
338+ }
229339 : { } ) }
230340 />
231341
0 commit comments