Skip to content

Commit b5b8407

Browse files
committed
[UI] Project wizard #323
1 parent 7b536ab commit b5b8407

7 files changed

Lines changed: 113 additions & 19 deletions

File tree

frontend/src/App/Login/LoginByGithubCallback/index.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { UnauthorizedLayout } from 'layouts/UnauthorizedLayout';
88
import { useAppDispatch } from 'hooks';
99
import { ROUTES } from 'routes';
1010
import { useGithubCallbackMutation } from 'services/auth';
11+
import { useLazyGetProjectsQuery } from 'services/project';
1112

1213
import { AuthErrorMessage } from 'App/AuthErrorMessage';
1314
import { Loading } from 'App/Loading';
@@ -22,13 +23,24 @@ export const LoginByGithubCallback: React.FC = () => {
2223
const dispatch = useAppDispatch();
2324

2425
const [githubCallback] = useGithubCallbackMutation();
26+
const [getProjects] = useLazyGetProjectsQuery();
2527

2628
const checkCode = () => {
2729
if (code) {
2830
githubCallback({ code })
2931
.unwrap()
30-
.then(({ creds: { token } }) => {
32+
.then(async ({ creds: { token } }) => {
3133
dispatch(setAuthData({ token }));
34+
35+
if (process.env.UI_VERSION === 'sky') {
36+
const result = await getProjects().unwrap();
37+
38+
if (result?.length === 0) {
39+
navigate(ROUTES.PROJECT.ADD);
40+
return;
41+
}
42+
}
43+
3244
navigate('/');
3345
})
3446
.catch(() => {

frontend/src/App/slice.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const getInitialState = (): IAppState => {
6161
},
6262

6363
tutorialPanel: {
64+
createProjectCompleted: false,
6465
billingCompleted: false,
6566
configureCLICompleted: false,
6667
discordCompleted: false,

frontend/src/App/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface IAppState {
3232
};
3333

3434
tutorialPanel: {
35+
createProjectCompleted: boolean;
3536
billingCompleted: boolean;
3637
configureCLICompleted: boolean;
3738
discordCompleted: boolean;

frontend/src/layouts/AppLayout/TutorialPanel/constants.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export enum HotspotIds {
4444
ADD_TOP_UP_BALANCE = 'billing-top-up-balance',
4545
PAYMENT_CONTINUE_BUTTON = 'billing-payment-continue-button',
4646
CONFIGURE_CLI_COMMAND = 'configure-cli-command',
47+
CREATE_FIRST_PROJECT = 'create-first-project',
4748
}
4849

4950
export const BILLING_TUTORIAL: TutorialPanelProps.Tutorial = {
@@ -101,6 +102,31 @@ export const CONFIGURE_CLI_TUTORIAL: TutorialPanelProps.Tutorial = {
101102
],
102103
};
103104

105+
export const CREATE_FIRST_PROJECT: TutorialPanelProps.Tutorial = {
106+
completed: false,
107+
title: 'Create the first project',
108+
description: (
109+
<>
110+
<Box variant="p" color="text-body-secondary" padding={{ top: 'n' }}>
111+
Configure the first your project
112+
</Box>
113+
</>
114+
),
115+
completedScreenDescription: 'TBA',
116+
tasks: [
117+
{
118+
title: 'Create the first project',
119+
steps: [
120+
{
121+
title: 'Create the first project',
122+
content: 'Create the first project',
123+
hotspotId: HotspotIds.CREATE_FIRST_PROJECT,
124+
},
125+
],
126+
},
127+
],
128+
};
129+
104130
export const JOIN_DISCORD_TUTORIAL: TutorialPanelProps.Tutorial = {
105131
completed: false,
106132
title: 'Community',

frontend/src/layouts/AppLayout/TutorialPanel/hooks.ts

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useCallback, useEffect, useMemo, useRef } from 'react';
2-
import { useNavigate } from 'react-router-dom';
2+
import { useLocation, useNavigate } from 'react-router-dom';
33

44
import {
55
DISCORD_URL,
@@ -8,6 +8,8 @@ import {
88
} from 'consts';
99
import { useAppDispatch, useAppSelector } from 'hooks';
1010
import { goToUrl } from 'libs';
11+
import { ROUTES } from 'routes';
12+
import { useGetProjectsQuery } from 'services/project';
1113
import { useGetRunsQuery } from 'services/run';
1214
import { useGetUserBillingInfoQuery } from 'services/user';
1315

@@ -17,6 +19,7 @@ import { useSideNavigation } from '../hooks';
1719
import {
1820
BILLING_TUTORIAL,
1921
CONFIGURE_CLI_TUTORIAL,
22+
CREATE_FIRST_PROJECT,
2023
// CREDITS_TUTORIAL,
2124
JOIN_DISCORD_TUTORIAL,
2225
QUICKSTART_TUTORIAL,
@@ -26,40 +29,73 @@ import { ITutorialItem } from 'App/types';
2629

2730
export const useTutorials = () => {
2831
const navigate = useNavigate();
32+
const location = useLocation();
2933
const dispatch = useAppDispatch();
3034
const { billingUrl } = useSideNavigation();
3135
const useName = useAppSelector(selectUserName);
32-
const { billingCompleted, configureCLICompleted, discordCompleted, tallyCompleted, quickStartCompleted, hideStartUp } =
33-
useAppSelector(selectTutorialPanel);
36+
const {
37+
billingCompleted,
38+
createProjectCompleted,
39+
configureCLICompleted,
40+
discordCompleted,
41+
tallyCompleted,
42+
quickStartCompleted,
43+
hideStartUp,
44+
} = useAppSelector(selectTutorialPanel);
3445

3546
const { data: userBillingData } = useGetUserBillingInfoQuery({ username: useName ?? '' }, { skip: !useName });
47+
const { data: projectData } = useGetProjectsQuery();
3648
const { data: runsData } = useGetRunsQuery({
3749
limit: 1,
3850
});
3951

4052
const completeIsChecked = useRef<boolean>(false);
4153

4254
useEffect(() => {
43-
if (userBillingData && runsData && !completeIsChecked.current) {
55+
if (
56+
userBillingData &&
57+
projectData &&
58+
runsData &&
59+
!completeIsChecked.current &&
60+
location.pathname !== ROUTES.PROJECT.ADD
61+
) {
4462
const billingCompleted = userBillingData.balance > 0;
4563
const configureCLICompleted = runsData.length > 0;
64+
const createProjectCompleted = projectData.length > 0;
4665

4766
let tempHideStartUp = hideStartUp;
4867

4968
if (hideStartUp === null) {
50-
tempHideStartUp = billingCompleted && configureCLICompleted;
69+
tempHideStartUp = billingCompleted && configureCLICompleted && createProjectCompleted;
5170
}
5271

5372
// Set hideStartUp without updating localstorage
54-
dispatch(updateTutorialPanelState({ billingCompleted, configureCLICompleted, hideStartUp: tempHideStartUp }));
73+
dispatch(
74+
updateTutorialPanelState({
75+
billingCompleted,
76+
configureCLICompleted,
77+
createProjectCompleted,
78+
hideStartUp: tempHideStartUp,
79+
}),
80+
);
5581

5682
if (!tempHideStartUp && process.env.UI_VERSION === 'sky') {
5783
dispatch(openTutorialPanel());
5884
}
5985

6086
completeIsChecked.current = true;
6187
}
62-
}, [userBillingData, runsData]);
88+
}, [userBillingData, runsData, projectData, location.pathname]);
89+
90+
useEffect(() => {
91+
if (projectData && projectData.length > 0 && !createProjectCompleted) {
92+
dispatch(
93+
updateTutorialPanelState({
94+
createProjectCompleted: true,
95+
}),
96+
);
97+
}
98+
}, [projectData]);
6399

64100
const startBillingTutorial = useCallback(() => {
65101
navigate(billingUrl);
@@ -69,6 +105,14 @@ export const useTutorials = () => {
69105
dispatch(updateTutorialPanelState({ billingCompleted: true }));
70106
}, []);
71107

108+
const startFirstProjectTutorial = useCallback(() => {
109+
navigate(ROUTES.PROJECT.ADD);
110+
}, []);
111+
112+
const finishFirstProjectTutorial = useCallback(() => {
113+
dispatch(updateTutorialPanelState({ createProjectCompleted: true }));
114+
}, []);
115+
72116
const startConfigCliTutorial = useCallback(() => {}, [billingUrl]);
73117

74118
const finishConfigCliTutorial = useCallback(() => {
@@ -103,44 +147,54 @@ export const useTutorials = () => {
103147
// },
104148

105149
{
106-
...CONFIGURE_CLI_TUTORIAL,
150+
...CREATE_FIRST_PROJECT,
107151
id: 2,
152+
completed: createProjectCompleted,
153+
startCallback: startFirstProjectTutorial,
154+
finishCallback: finishFirstProjectTutorial,
155+
},
156+
157+
{
158+
...CONFIGURE_CLI_TUTORIAL,
159+
id: 3,
108160
completed: configureCLICompleted,
109161
startCallback: startConfigCliTutorial,
110162
finishCallback: finishConfigCliTutorial,
111163
},
112164

113165
{
114166
...BILLING_TUTORIAL,
115-
id: 3,
167+
id: 4,
116168
completed: billingCompleted,
117169
startCallback: startBillingTutorial,
118170
finishCallback: finishBillingTutorial,
119171
},
120172

121173
{
122174
...QUICKSTART_TUTORIAL,
123-
id: 4,
175+
id: 5,
124176
startWithoutActivation: true,
125177
completed: quickStartCompleted,
126178
startCallback: startQuickStartTutorial,
127179
},
128180

129181
{
130182
...JOIN_DISCORD_TUTORIAL,
131-
id: 5,
183+
id: 6,
132184
startWithoutActivation: true,
133185
completed: discordCompleted,
134186
startCallback: startDiscordTutorial,
135187
},
136188
];
137189
}, [
138190
billingUrl,
191+
createProjectCompleted,
139192
quickStartCompleted,
140193
discordCompleted,
141194
tallyCompleted,
142195
billingCompleted,
143196
configureCLICompleted,
197+
finishFirstProjectTutorial,
144198
finishBillingTutorial,
145199
finishConfigCliTutorial,
146200
]);

frontend/src/pages/Project/CreateWizard/index.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export const CreateProjectWizard: React.FC = () => {
168168
const resolver = useYupValidationResolver(projectValidationSchema);
169169
const formMethods = useForm<IProjectWizardForm>({
170170
resolver,
171-
defaultValues: { enable_fleet: true, fleet_min_instances: 0 },
171+
defaultValues: { project_type: 'gpu_marketplace', enable_fleet: true, fleet_min_instances: 0 },
172172
});
173173
const { handleSubmit, control, watch, trigger, formState, getValues, setValue, setError } = formMethods;
174174
const formValues = watch();
@@ -209,10 +209,9 @@ export const CreateProjectWizard: React.FC = () => {
209209
return false;
210210
});
211211

212-
console.log({ serverValidationResult });
213-
214212
return yupValidationResult && serverValidationResult;
215213
} catch (e) {
214+
console.log(e);
216215
return false;
217216
}
218217
};
@@ -468,10 +467,10 @@ export const CreateProjectWizard: React.FC = () => {
468467
},
469468
{
470469
label: t('projects.edit.backends'),
471-
value: (formValues['project_type'] === 'gpu_marketplace'
472-
? (formValues['backends'] ?? [])
473-
: backendOptions.map((b: { value: string }) => b.value)
474-
).join(', '),
470+
value:
471+
formValues['project_type'] === 'gpu_marketplace'
472+
? (formValues['backends'] ?? []).join(', ')
473+
: 'The backends can be configured with your own cloud credentials in the project settings after the project is created.',
475474
},
476475
]}
477476
/>

frontend/src/services/project.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ export const projectApi = createApi({
180180

181181
export const {
182182
useGetProjectsQuery,
183+
useLazyGetProjectsQuery,
183184
useGetProjectQuery,
184185
useCreateProjectMutation,
185186
useCreateWizardProjectMutation,

0 commit comments

Comments
 (0)