Skip to content

Commit

Permalink
feat: devbox support gpu (#5281)
Browse files Browse the repository at this point in the history
* feat: basic logic

* feat: basic logic gpu runtime

* feat: pricebox and quota box

* fix: bug

* chore: ubuntu-cuda svg

* fix: price bug

* fix: build bug

* fix: gpu bug

* fix: build bug

* chore: pytorch svg

* fix: delete will not be effective

* chore: cursor->vscode

* feat: detail support gpu

* chore: name change

* fix: gpu inventory bug

* fix: delete devbox

* fix: bug

* fix: next build bug

* fix: next build bug

* chore:delete coonsole.log

* perf: code shorten

* chore: deploy update

* fix: add runtimeClassName

* fix: basic fix

* fix: gpu bug

* fix: type bug

* chore: prettier modify

* chore: prettier every file

* fix: get->watch

* fix: merge cause code bug

* fix: yaml problem
  • Loading branch information
mlhiter authored Feb 21, 2025
1 parent bf52ed5 commit f667853
Show file tree
Hide file tree
Showing 37 changed files with 653 additions and 238 deletions.
1 change: 1 addition & 0 deletions frontend/providers/devbox/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ DEVBOX_AFFINITY_ENABLE=
SQUASH_ENABLE=
NODE_TLS_REJECT_UNAUTHORIZED=
ROOT_RUNTIME_NAMESPACE=
GPU_ENABLE=
DATABASE_URL=
RETAG_SVC_URL=
PRIVACY_URL=
4 changes: 2 additions & 2 deletions frontend/providers/devbox/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
dist
.vscode
**/dist
**/.vscode
**/.DS_Store
node_modules
.next
3 changes: 3 additions & 0 deletions frontend/providers/devbox/api/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export const listOfficialTemplateRepository = () =>
kind: TemplateRepositoryKind;
iconId: string;
description: string | null;
templateRepositoryTags: {
tag: Tag;
}[];
}[];
}>(`/api/templateRepository/listOfficial`);
export const listTemplateRepository = (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { useMemo } from 'react';
import { useTranslations } from 'next-intl';
import { useFormContext } from 'react-hook-form';
import { useQuery } from '@tanstack/react-query';
import { Box, Center, Flex } from '@chakra-ui/react';
import { MySelect, MyTooltip } from '@sealos/ui';

import Label from '../Label';
import { usePriceStore } from '@/stores/price';
import { DevboxEditTypeV2 } from '@/types/devbox';
import { GpuAmountMarkList } from '@/constants/devbox';
import { listOfficialTemplateRepository } from '@/api/template';

const labelWidth = 100;

export default function GpuSelector({
countGpuInventory
}: {
countGpuInventory: (type: string) => number;
}) {
const t = useTranslations();
const { sourcePrice } = usePriceStore();
const { watch, setValue, getValues } = useFormContext<DevboxEditTypeV2>();
const templateRepositoryQuery = useQuery(
['list-official-template-repository'],
listOfficialTemplateRepository
);

const templateData = useMemo(
() => templateRepositoryQuery.data?.templateRepositoryList || [],
[templateRepositoryQuery.data]
);
const templateRepositoryUid = getValues('templateRepositoryUid');
const isGpuTemplate = useMemo(() => {
const template = templateData.find((item) => item.uid === templateRepositoryUid);
return template?.templateRepositoryTags.some((item) => item.tag.name === 'gpu');
}, [templateData, templateRepositoryUid]);

const selectedGpu = () => {
const selected = sourcePrice?.gpu?.find((item) => item.type === getValues('gpu.type'));
if (!selected) return;
return {
...selected,
inventory: countGpuInventory(selected.type)
};
};

// add NoGPU select item
const gpuSelectList = useMemo(
() =>
sourcePrice?.gpu
? [
{
label: t('No GPU'),
value: ''
},
...sourcePrice.gpu.map((item) => ({
icon: 'nvidia',
label: (
<Flex>
<Box color={'myGray.900'}>{item.alias}</Box>
<Box mx={3} color={'grayModern.900'}>
|
</Box>
<Box color={'grayModern.900'}>
{t('vm')} : {Math.round(item.vm)}G
</Box>
<Box mx={3} color={'grayModern.900'}>
|
</Box>
<Flex pr={3}>
<Box color={'grayModern.900'}>{t('Inventory')}&ensp;:&ensp;</Box>
<Box color={'#FB7C3C'}>{countGpuInventory(item.type)}</Box>
</Flex>
</Flex>
),
value: item.type
}))
]
: [],
[countGpuInventory, t, sourcePrice?.gpu]
);

if (!isGpuTemplate || !sourcePrice?.gpu) {
return null;
}

return (
<Box mb={7}>
<Flex alignItems={'center'}>
<Label w={100}>GPU</Label>
<MySelect
width={'300px'}
placeholder={t('No GPU') || ''}
value={getValues('gpu.type')}
list={gpuSelectList}
onchange={(type: any) => {
const selected = sourcePrice?.gpu?.find((item) => item.type === type);
const inventory = countGpuInventory(type);
if (type === '' || (selected && inventory > 0)) {
setValue('gpu.type', type);
}
}}
/>
</Flex>
{!!watch('gpu.type') && (
<Box mt={4} pl={`${labelWidth}px`}>
<Box mb={1}>{t('Amount')}</Box>
<Flex alignItems={'center'}>
{GpuAmountMarkList.map((item) => {
const inventory = selectedGpu()?.inventory || 0;

const hasInventory = item.value <= inventory;

return (
<MyTooltip key={item.value} label={hasInventory ? '' : t('Under Stock')}>
<Center
mr={2}
w={'32px'}
h={'32px'}
borderRadius={'md'}
border={'1px solid'}
bg={'white'}
{...(getValues('gpu.amount') === item.value
? {
borderColor: 'brightBlue.500',
boxShadow: '0px 0px 0px 2.4px rgba(33, 155, 244, 0.15)'
}
: {
borderColor: 'grayModern.200',
bgColor: 'grayModern.100'
})}
{...(hasInventory
? {
cursor: 'pointer',
onClick: () => {
setValue('gpu.amount', item.value);
}
}
: {
cursor: 'default',
opacity: 0.5
})}
>
{item.label}
</Center>
</MyTooltip>
);
})}
<Box ml={3} color={'MyGray.500'}>
/ {t('Card')}
</Box>
</Flex>
</Box>
)}
</Box>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default function TemplateRepositoryItem({
});
return;
}
setValue('gpu.type', '');
if (startedTemplate && startedTemplate.uid !== item.uid) {
setStartedTemplate(undefined);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import MyIcon from '@/components/Icon';
import { Box, BoxProps } from '@chakra-ui/react';
import { useTranslations } from 'next-intl';
import ConfigurationHeader from '../ConfigurationHeader';

import CpuSelector from './CpuSelector';
import DevboxNameInput from './DevboxNameInput';
import GpuSelector from './GpuSelector';
import MemorySelector from './MemorySelector';
import TemplateRepositorySelector from './TemplateRepositorySelector';
import DevboxNameInput from './DevboxNameInput';
import TemplateSelector from './TemplateSelector';
import ConfigurationHeader from '../ConfigurationHeader';
import TemplateRepositorySelector from './TemplateRepositorySelector';

export default function BasicConfiguration({ isEdit, ...props }: BoxProps & { isEdit: boolean }) {
export default function BasicConfiguration({
isEdit,
countGpuInventory,
...props
}: BoxProps & { isEdit: boolean; countGpuInventory: (type: string) => number }) {
const t = useTranslations();
return (
<Box {...props}>
Expand All @@ -23,13 +29,12 @@ export default function BasicConfiguration({ isEdit, ...props }: BoxProps & { is
<TemplateRepositorySelector isEdit={isEdit} />
{/* Runtime Version */}
<TemplateSelector isEdit={isEdit} />

<Box className="guide-custom-resources" pb={'2px'}>
{/* CPU */}
<CpuSelector />
{/* Memory */}
<MemorySelector />
</Box>
{/* GPU */}
<GpuSelector countGpuInventory={countGpuInventory} />
{/* CPU */}
<CpuSelector />
{/* Memory */}
<MemorySelector />
</Box>
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use client';
'use client';

import { Box, Flex, Grid, useTheme } from '@chakra-ui/react';
import { Tabs } from '@sealos/ui';
Expand All @@ -19,7 +20,15 @@ import { obj2Query } from '@/utils/tools';
import BasicConfiguration from './BasicConfiguration';
import NetworkConfiguration from './NetworkConfiguration';

const Form = ({ pxVal, isEdit }: { pxVal: number; isEdit: boolean }) => {
const Form = ({
pxVal,
isEdit,
countGpuInventory
}: {
pxVal: number;
isEdit: boolean;
countGpuInventory: (type: string) => number;
}) => {
const theme = useTheme();
const router = useRouter();
const t = useTranslations();
Expand All @@ -36,6 +45,7 @@ const Form = ({ pxVal, isEdit }: { pxVal: number; isEdit: boolean }) => {
icon: 'network'
}
];

const [activeNav, setActiveNav] = useState(navList[0].id);
const { devboxList } = useDevboxStore();

Expand All @@ -59,7 +69,6 @@ const Form = ({ pxVal, isEdit }: { pxVal: number; isEdit: boolean }) => {
}
}
}, 200);
document.getElementById('form-container')?.addEventListener('scroll', scrollFn);
return () => {
document.getElementById('form-container')?.removeEventListener('scroll', scrollFn);
};
Expand Down Expand Up @@ -168,7 +177,12 @@ const Form = ({ pxVal, isEdit }: { pxVal: number; isEdit: boolean }) => {
overflowY={'scroll'}
>
{/* base info */}
<BasicConfiguration isEdit={isEdit} id={'baseInfo'} {...boxStyles} />
<BasicConfiguration
isEdit={isEdit}
id={'baseInfo'}
{...boxStyles}
countGpuInventory={countGpuInventory}
/>
{/* network */}
<NetworkConfiguration isEdit={isEdit} id={'network'} {...boxStyles} />
</Box>
Expand Down
Loading

0 comments on commit f667853

Please sign in to comment.