mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(gpu): rework docker GPU for UI performance [EE-4918] (#8518)
This commit is contained in:
parent
769c8372fb
commit
fd916bc8a2
52 changed files with 692 additions and 285 deletions
|
@ -10,6 +10,7 @@ import { OptionProps } from 'react-select/dist/declarations/src/components/Optio
|
|||
import { Select } from '@@/form-components/ReactSelect';
|
||||
import { Switch } from '@@/form-components/SwitchField/Switch';
|
||||
import { Tooltip } from '@@/Tip/Tooltip';
|
||||
import { TextTip } from '@@/Tip/TextTip';
|
||||
|
||||
interface Values {
|
||||
enabled: boolean;
|
||||
|
@ -35,6 +36,7 @@ export interface Props {
|
|||
gpus: GPU[];
|
||||
usedGpus: string[];
|
||||
usedAllGpus: boolean;
|
||||
enableGpuManagement?: boolean;
|
||||
}
|
||||
|
||||
const NvidiaCapabilitiesOptions = [
|
||||
|
@ -103,6 +105,7 @@ export function Gpu({
|
|||
gpus = [],
|
||||
usedGpus = [],
|
||||
usedAllGpus,
|
||||
enableGpuManagement,
|
||||
}: Props) {
|
||||
const options = useMemo(() => {
|
||||
const options = (gpus || []).map((gpu) => ({
|
||||
|
@ -181,30 +184,38 @@ export function Gpu({
|
|||
|
||||
return (
|
||||
<div>
|
||||
{!enableGpuManagement && (
|
||||
<TextTip color="blue">
|
||||
GPU in the UI is not currently enabled for this environment.
|
||||
</TextTip>
|
||||
)}
|
||||
<div className="form-group">
|
||||
<div className="col-sm-3 col-lg-2 control-label text-left">
|
||||
Enable GPU
|
||||
<Switch
|
||||
id="enabled"
|
||||
name="enabled"
|
||||
checked={values.enabled}
|
||||
checked={values.enabled && !!enableGpuManagement}
|
||||
onChange={toggleEnableGpu}
|
||||
className="ml-2"
|
||||
disabled={enableGpuManagement === false}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-sm-9 col-lg-10 text-left">
|
||||
<Select<GpuOption, true>
|
||||
isMulti
|
||||
closeMenuOnSelect
|
||||
value={gpuValue}
|
||||
isClearable={false}
|
||||
backspaceRemovesValue={false}
|
||||
isDisabled={!values.enabled}
|
||||
onChange={onChangeSelectedGpus}
|
||||
options={options}
|
||||
components={{ MultiValueRemove }}
|
||||
/>
|
||||
</div>
|
||||
{enableGpuManagement && values.enabled && (
|
||||
<div className="col-sm-9 col-lg-10 text-left">
|
||||
<Select<GpuOption, true>
|
||||
isMulti
|
||||
closeMenuOnSelect
|
||||
value={gpuValue}
|
||||
isClearable={false}
|
||||
backspaceRemovesValue={false}
|
||||
isDisabled={!values.enabled}
|
||||
onChange={onChangeSelectedGpus}
|
||||
options={options}
|
||||
components={{ MultiValueRemove }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{values.enabled && (
|
||||
|
|
|
@ -15,7 +15,7 @@ import { gpus } from './gpus';
|
|||
|
||||
export function useColumns(
|
||||
isHostColumnVisible: boolean,
|
||||
isGPUsColumnVisible: boolean
|
||||
isGPUsColumnVisible?: boolean
|
||||
) {
|
||||
return useMemo(
|
||||
() =>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
import { useInfo } from '@/docker/services/system.service';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import { ResourceControlViewModel } from '@/react/portainer/access-control/models/ResourceControlViewModel';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import { useInfo } from '@/docker/services/system.service';
|
||||
import { useEnvironment } from '@/react/portainer/environments/queries';
|
||||
|
||||
import { DockerContainer, ContainerStatus } from './types';
|
||||
import { DockerContainerResponse } from './types/response';
|
||||
|
@ -95,10 +96,13 @@ function createStatus(statusText = ''): ContainerStatus {
|
|||
}
|
||||
|
||||
export function useShowGPUsColumn(environmentID: EnvironmentId) {
|
||||
const envInfoQuery = useInfo(
|
||||
const isDockerStandaloneQuery = useInfo(
|
||||
environmentID,
|
||||
(info) => !!info.Swarm?.NodeID && !!info.Swarm?.ControlAvailable
|
||||
(info) => !(!!info.Swarm?.NodeID && !!info.Swarm?.ControlAvailable) // is not a swarm environment, therefore docker standalone
|
||||
);
|
||||
|
||||
return envInfoQuery.data !== true && !envInfoQuery.isLoading;
|
||||
const enableGPUManagementQuery = useEnvironment(
|
||||
environmentID,
|
||||
(env) => env?.EnableGPUManagement
|
||||
);
|
||||
return isDockerStandaloneQuery.data && enableGPUManagementQuery.data;
|
||||
}
|
||||
|
|
73
app/react/docker/host/SetupView/GpusList.tsx
Normal file
73
app/react/docker/host/SetupView/GpusList.tsx
Normal file
|
@ -0,0 +1,73 @@
|
|||
import { array, object, string } from 'yup';
|
||||
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
import { withControlledInput } from '@/react-tools/withControlledInput';
|
||||
|
||||
import { InputList } from '@@/form-components/InputList';
|
||||
import { ItemProps } from '@@/form-components/InputList/InputList';
|
||||
import { InputGroup } from '@@/form-components/InputGroup';
|
||||
|
||||
export interface Gpu {
|
||||
value: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
value: Gpu[];
|
||||
onChange(value: Gpu[]): void;
|
||||
}
|
||||
|
||||
function Item({ item, onChange }: ItemProps<Gpu>) {
|
||||
return (
|
||||
<div className="flex flex-grow gap-2">
|
||||
<InputGroup size="small" className="flex-grow">
|
||||
<InputGroup.Addon>GPU Name</InputGroup.Addon>
|
||||
<InputGroup.Input
|
||||
placeholder="my-gpu"
|
||||
value={item.name}
|
||||
onChange={(e) => {
|
||||
onChange({ ...item, name: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
<InputGroup size="small" className="flex-grow">
|
||||
<InputGroup.Addon>Index or UUID</InputGroup.Addon>
|
||||
<InputGroup.Input
|
||||
placeholder="0 or GPU-6e2c7185-c3d3-ae22-da43-bc5267b89061"
|
||||
value={item.value}
|
||||
onChange={(e) => {
|
||||
onChange({ ...item, value: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function GpusList({ value, onChange }: Props) {
|
||||
return (
|
||||
<InputList<Gpu>
|
||||
label="GPUs"
|
||||
tooltip="You may optionally set up the GPUs that will be selectable against containers, although 'All GPUs' will always be available."
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
itemBuilder={() => ({ value: '', name: '' })}
|
||||
addLabel="Add GPU"
|
||||
item={Item}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function gpusListValidation() {
|
||||
const gpuShape = object().shape({
|
||||
name: string().required(),
|
||||
value: string().required(),
|
||||
});
|
||||
return array().of(gpuShape).default([]);
|
||||
}
|
||||
|
||||
export const GpusListAngular = r2a(withControlledInput(GpusList), [
|
||||
'value',
|
||||
'onChange',
|
||||
]);
|
Loading…
Add table
Add a link
Reference in a new issue