style: subdrawer width
This commit is contained in:
@@ -4,7 +4,3 @@ import { atom } from 'jotai';
|
|||||||
export const currentClusterAtom = atom<
|
export const currentClusterAtom = atom<
|
||||||
(Partial<ClusterListItem> & { label?: string; value?: number }) | null
|
(Partial<ClusterListItem> & { label?: string; value?: number }) | null
|
||||||
>(null);
|
>(null);
|
||||||
|
|
||||||
export const addSSHKeyPageAtom = atom<{ create: boolean }>({
|
|
||||||
create: false
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const InstanceStatusValueMap = {
|
|||||||
Preparing: 'Preparing',
|
Preparing: 'Preparing',
|
||||||
NotReady: 'NotReady',
|
NotReady: 'NotReady',
|
||||||
Ready: 'Ready',
|
Ready: 'Ready',
|
||||||
Staring: 'Staring'
|
Starting: 'Starting'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InstanceStatusLabelMap: Record<string, string> = {
|
export const InstanceStatusLabelMap: Record<string, string> = {
|
||||||
@@ -27,7 +27,7 @@ export const InstanceStatusLabelMap: Record<string, string> = {
|
|||||||
[InstanceStatusValueMap.Preparing]: 'Preparing',
|
[InstanceStatusValueMap.Preparing]: 'Preparing',
|
||||||
[InstanceStatusValueMap.NotReady]: 'NotReady',
|
[InstanceStatusValueMap.NotReady]: 'NotReady',
|
||||||
[InstanceStatusValueMap.Ready]: 'Ready',
|
[InstanceStatusValueMap.Ready]: 'Ready',
|
||||||
[InstanceStatusValueMap.Staring]: 'Staring'
|
[InstanceStatusValueMap.Starting]: 'Starting'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const status: Record<string, StatusType> = {
|
export const status: Record<string, StatusType> = {
|
||||||
@@ -40,7 +40,7 @@ export const status: Record<string, StatusType> = {
|
|||||||
[InstanceStatusValueMap.Preparing]: StatusMaps.transitioning,
|
[InstanceStatusValueMap.Preparing]: StatusMaps.transitioning,
|
||||||
[InstanceStatusValueMap.NotReady]: StatusMaps.error,
|
[InstanceStatusValueMap.NotReady]: StatusMaps.error,
|
||||||
[InstanceStatusValueMap.Ready]: StatusMaps.success,
|
[InstanceStatusValueMap.Ready]: StatusMaps.success,
|
||||||
[InstanceStatusValueMap.Staring]: StatusMaps.transitioning
|
[InstanceStatusValueMap.Starting]: StatusMaps.transitioning
|
||||||
};
|
};
|
||||||
|
|
||||||
// Lifecycle actions (logs/events/start/stop) require K8s proxy endpoints that
|
// Lifecycle actions (logs/events/start/stop) require K8s proxy endpoints that
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { addSSHKeyPageAtom } from '@/atoms/gpuservice';
|
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
@@ -14,9 +13,8 @@ import {
|
|||||||
useScrollActiveChange,
|
useScrollActiveChange,
|
||||||
useWrapperContext
|
useWrapperContext
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl, useNavigate } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Empty, Form } from 'antd';
|
import { Button, Flex, Form } from 'antd';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import {
|
import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
@@ -26,6 +24,8 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { FormData as PublicKeyFormData } from '../../public-keys/config/types';
|
||||||
|
import useCreateSshkey from '../../public-keys/services/use-create-sshkey';
|
||||||
import useQuerySshkeys from '../../public-keys/services/use-query-sshkeys';
|
import useQuerySshkeys from '../../public-keys/services/use-query-sshkeys';
|
||||||
import { DefaultImagePullPolicy } from '../../templates/config';
|
import { DefaultImagePullPolicy } from '../../templates/config';
|
||||||
import TemplateBasicForm, {
|
import TemplateBasicForm, {
|
||||||
@@ -36,6 +36,7 @@ import { FormData, InstanceTypeItem, ListItem } from '../config/types';
|
|||||||
import instanceStyles from '../styles/instances.module.less';
|
import instanceStyles from '../styles/instances.module.less';
|
||||||
import Basic from './basic';
|
import Basic from './basic';
|
||||||
import InstanceTypeFormItem from './instance-type';
|
import InstanceTypeFormItem from './instance-type';
|
||||||
|
import PublicKeyOverlay from './public-key-overlay';
|
||||||
import StorageVolume from './storage-volume';
|
import StorageVolume from './storage-volume';
|
||||||
|
|
||||||
const SSH_PORT = 22;
|
const SSH_PORT = 22;
|
||||||
@@ -124,8 +125,6 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
onFinish
|
onFinish
|
||||||
} = props;
|
} = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const navigate = useNavigate();
|
|
||||||
const setAddSSHKeyPage = useSetAtom(addSSHKeyPageAtom);
|
|
||||||
const { getRuleMessage } = useAppUtils();
|
const { getRuleMessage } = useAppUtils();
|
||||||
const [form] = Form.useForm<InstanceFormValues>();
|
const [form] = Form.useForm<InstanceFormValues>();
|
||||||
const scrollTabsRef = useRef<any>(null);
|
const scrollTabsRef = useRef<any>(null);
|
||||||
@@ -133,6 +132,8 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
realAction === PageAction.CREATE ? PageAction.CREATE : action;
|
realAction === PageAction.CREATE ? PageAction.CREATE : action;
|
||||||
const sshEnabled = Form.useWatch('enable_ssh', form);
|
const sshEnabled = Form.useWatch('enable_ssh', form);
|
||||||
const { sshkeyOptions, fetchData: fetchSSHData } = useQuerySshkeys();
|
const { sshkeyOptions, fetchData: fetchSSHData } = useQuerySshkeys();
|
||||||
|
const { fetchData: createSshkey } = useCreateSshkey();
|
||||||
|
const [sshOverlayOpen, setSshOverlayOpen] = useState(false);
|
||||||
const { getScrollElementScrollableHeight } = useWrapperContext();
|
const { getScrollElementScrollableHeight } = useWrapperContext();
|
||||||
const {
|
const {
|
||||||
activeKey,
|
activeKey,
|
||||||
@@ -352,9 +353,23 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const handleAddSSHKey = () => {
|
const handleAddSSHKey = () => {
|
||||||
setAddSSHKeyPage({ create: true });
|
setSshOverlayOpen(true);
|
||||||
// to go ssh key page
|
};
|
||||||
navigate('/gpu-service/public-keys');
|
|
||||||
|
const handleCreateSSHKey = async (values: PublicKeyFormData) => {
|
||||||
|
try {
|
||||||
|
await fetchSSHData({ page: -1 });
|
||||||
|
const current: Array<{ name: string } | string> =
|
||||||
|
form.getFieldValue(['spec', 'sshPublicKeys']) || [];
|
||||||
|
form.setFieldValue(
|
||||||
|
['spec', 'sshPublicKeys'],
|
||||||
|
[...current, { name: values.name }]
|
||||||
|
);
|
||||||
|
|
||||||
|
setSshOverlayOpen(false);
|
||||||
|
} catch (error) {
|
||||||
|
// it's handled in interceptor
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnEnableSSHChange = (e: any) => {
|
const handleOnEnableSSHChange = (e: any) => {
|
||||||
@@ -463,19 +478,31 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Form.Item<FormData>
|
<Flex align="center" justify="space-between">
|
||||||
name="enable_ssh"
|
<Form.Item<FormData>
|
||||||
valuePropName="checked"
|
name="enable_ssh"
|
||||||
style={{ marginBottom: 8 }}
|
valuePropName="checked"
|
||||||
>
|
style={{ marginBottom: 8 }}
|
||||||
<CheckboxField
|
>
|
||||||
onChange={handleOnEnableSSHChange}
|
<CheckboxField
|
||||||
disabled={disabled}
|
onChange={handleOnEnableSSHChange}
|
||||||
label={intl.formatMessage({
|
disabled={disabled}
|
||||||
id: 'gpuservice.instance.ssh.enable'
|
label={intl.formatMessage({
|
||||||
|
id: 'gpuservice.instance.ssh.enable'
|
||||||
|
})}
|
||||||
|
></CheckboxField>
|
||||||
|
</Form.Item>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={handleAddSSHKey}
|
||||||
|
>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: 'gpuservice.instance.ssh.addKey'
|
||||||
})}
|
})}
|
||||||
></CheckboxField>
|
</Button>
|
||||||
</Form.Item>
|
</Flex>
|
||||||
{
|
{
|
||||||
<div className={instanceStyles.sshkeySelection}>
|
<div className={instanceStyles.sshkeySelection}>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
@@ -515,38 +542,16 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
options={sshkeyOptions}
|
options={sshkeyOptions}
|
||||||
notFoundContent={
|
|
||||||
<Empty
|
|
||||||
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
|
||||||
description={intl.formatMessage({
|
|
||||||
id: 'noresult.gpuservice.sshkey.title'
|
|
||||||
})}
|
|
||||||
styles={{
|
|
||||||
image: {
|
|
||||||
height: 32
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
margin: 0
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
type="link"
|
|
||||||
icon={<PlusOutlined />}
|
|
||||||
onClick={handleAddSSHKey}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({
|
|
||||||
id: 'gpuservice.instance.ssh.addKey'
|
|
||||||
})}
|
|
||||||
</Button>
|
|
||||||
</Empty>
|
|
||||||
}
|
|
||||||
></MultipleSelect>
|
></MultipleSelect>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</Form>
|
</Form>
|
||||||
|
<PublicKeyOverlay
|
||||||
|
open={sshOverlayOpen}
|
||||||
|
onCancel={() => setSshOverlayOpen(false)}
|
||||||
|
onSubmit={handleCreateSSHKey}
|
||||||
|
/>
|
||||||
</ScrollSpyTabs>
|
</ScrollSpyTabs>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ const InstanceTypeFormItem: React.FC<InstanceTypeFormItemProps> = ({
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<NumberSelection
|
<NumberSelection
|
||||||
min={0}
|
min={1}
|
||||||
onChange={handleOnGPUCountChange}
|
onChange={handleOnGPUCountChange}
|
||||||
max={maxGpuCount}
|
max={maxGpuCount}
|
||||||
step={1}
|
step={1}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { PageAction } from '@/config';
|
||||||
|
import FormOverlayView from '@/pages/_components/form-overlay-view';
|
||||||
|
import { ModalFooter } from '@gpustack/core-ui';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { useRef, useState } from 'react';
|
||||||
|
import { FormData as PublicKeyFormData } from '../../public-keys/config/types';
|
||||||
|
import GPUServicePublicKeyForm from '../../public-keys/forms';
|
||||||
|
import useCreateSshkey from '../../public-keys/services/use-create-sshkey';
|
||||||
|
import useOverlayLayout from '../hooks/use-overlay-layout';
|
||||||
|
|
||||||
|
interface PublicKeyOverlayProps {
|
||||||
|
open: boolean;
|
||||||
|
onCancel: () => void;
|
||||||
|
onSubmit: (values: PublicKeyFormData) => Promise<void> | void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PublicKeyOverlay: React.FC<PublicKeyOverlayProps> = ({
|
||||||
|
open,
|
||||||
|
onCancel,
|
||||||
|
onSubmit
|
||||||
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const formRef = useRef<any>(null);
|
||||||
|
const { fetchData: createSshkey } = useCreateSshkey();
|
||||||
|
const { drawerWidth, getOverlayContainer } = useOverlayLayout(open);
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
formRef.current?.submit();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
formRef.current?.resetFields();
|
||||||
|
onCancel();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFinish = async (values: PublicKeyFormData) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
await createSshkey({ data: values });
|
||||||
|
await onSubmit(values);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormOverlayView
|
||||||
|
title={intl.formatMessage({ id: 'gpuservice.publicKey.add' })}
|
||||||
|
open={open}
|
||||||
|
width={drawerWidth}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
getContainer={getOverlayContainer}
|
||||||
|
footer={
|
||||||
|
<ModalFooter
|
||||||
|
onOk={handleSubmit}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
loading={loading}
|
||||||
|
style={{
|
||||||
|
padding: '16px 24px 24px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<GPUServicePublicKeyForm
|
||||||
|
ref={formRef}
|
||||||
|
action={PageAction.CREATE}
|
||||||
|
open={open}
|
||||||
|
onFinish={handleFinish}
|
||||||
|
/>
|
||||||
|
</FormOverlayView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PublicKeyOverlay;
|
||||||
@@ -4,9 +4,10 @@ import { FormContext } from '@/pages/gpu-service/storage/config/form-context';
|
|||||||
import useQueryStorageClass from '@/pages/gpu-service/storage/services/use-query-storage-class';
|
import useQueryStorageClass from '@/pages/gpu-service/storage/services/use-query-storage-class';
|
||||||
import { ModalFooter } from '@gpustack/core-ui';
|
import { ModalFooter } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { FormData as StorageFormData } from '../../storage/config/types';
|
import { FormData as StorageFormData } from '../../storage/config/types';
|
||||||
import GPUServiceStorageForm from '../../storage/forms';
|
import GPUServiceStorageForm from '../../storage/forms';
|
||||||
|
import useOverlayLayout from '../hooks/use-overlay-layout';
|
||||||
|
|
||||||
interface StorageOverlayProps {
|
interface StorageOverlayProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -24,6 +25,7 @@ const StorageOverlay: React.FC<StorageOverlayProps> = ({
|
|||||||
useQueryStorageClass();
|
useQueryStorageClass();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const formRef = useRef<any>(null);
|
const formRef = useRef<any>(null);
|
||||||
|
const { drawerWidth, getOverlayContainer } = useOverlayLayout(open);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
@@ -49,19 +51,11 @@ const StorageOverlay: React.FC<StorageOverlayProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getOverlayContainer = useCallback(() => {
|
|
||||||
const containers = document.querySelectorAll<HTMLElement>(
|
|
||||||
'.ant-layout-content'
|
|
||||||
);
|
|
||||||
|
|
||||||
return containers[containers.length - 1] ?? null;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormOverlayView
|
<FormOverlayView
|
||||||
title={intl.formatMessage({ id: 'gpuservice.storage.add' })}
|
title={intl.formatMessage({ id: 'gpuservice.storage.add' })}
|
||||||
open={open}
|
open={open}
|
||||||
width={600}
|
width={drawerWidth}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
getContainer={getOverlayContainer}
|
getContainer={getOverlayContainer}
|
||||||
footer={
|
footer={
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
Input as CInput,
|
Input as CInput,
|
||||||
InputNumber as CInputNumber,
|
InputNumber as CInputNumber,
|
||||||
@@ -135,6 +136,7 @@ const StorageVolume = ({
|
|||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
onClick={() => setOverlayOpen(true)}
|
onClick={() => setOverlayOpen(true)}
|
||||||
>
|
>
|
||||||
{intl.formatMessage({ id: 'gpuservice.storage.add' })}
|
{intl.formatMessage({ id: 'gpuservice.storage.add' })}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
DropdownButtons,
|
DropdownButtons,
|
||||||
StatusTag
|
StatusTag
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useAccess, useIntl } from '@umijs/max';
|
||||||
import { Button, Flex } from 'antd';
|
import { Button, Flex } from 'antd';
|
||||||
import type { ColumnsType } from 'antd/lib/table';
|
import type { ColumnsType } from 'antd/lib/table';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@@ -80,6 +80,7 @@ const useInstancesColumns = ({
|
|||||||
sortOrder
|
sortOrder
|
||||||
}: ColumnsHookProps): ColumnsType<ListItem> => {
|
}: ColumnsHookProps): ColumnsType<ListItem> => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const access = useAccess();
|
||||||
|
|
||||||
const renderInstanceType = (record: ListItem) => {
|
const renderInstanceType = (record: ListItem) => {
|
||||||
const description = JSON.parse(record?.description || '{}').spec || {};
|
const description = JSON.parse(record?.description || '{}').spec || {};
|
||||||
@@ -122,7 +123,7 @@ const useInstancesColumns = ({
|
|||||||
},
|
},
|
||||||
render: (text: string, record: ListItem) => (
|
render: (text: string, record: ListItem) => (
|
||||||
<AutoTooltip ghost style={{ maxWidth: 360 }}>
|
<AutoTooltip ghost style={{ maxWidth: 360 }}>
|
||||||
<span className="text-primary">{text || record.displayName}</span>
|
<span className="text-primary">{record.displayName || text}</span>
|
||||||
</AutoTooltip>
|
</AutoTooltip>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -247,6 +248,7 @@ const useInstancesColumns = ({
|
|||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'clusters.title' }),
|
title: intl.formatMessage({ id: 'clusters.title' }),
|
||||||
dataIndex: 'clusterId',
|
dataIndex: 'clusterId',
|
||||||
|
hidden: !access.canSeeAdmin,
|
||||||
render: (id: number) => (
|
render: (id: number) => (
|
||||||
<AutoTooltip ghost maxWidth={240}>
|
<AutoTooltip ghost maxWidth={240}>
|
||||||
{_.find(clusterList, { value: id })?.label || id || '-'}
|
{_.find(clusterList, { value: id })?.label || id || '-'}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import instanceStyles from '../styles/instances.module.less';
|
||||||
|
|
||||||
|
const FALLBACK_WIDTH = `calc((100vw - 220px) / 3 + 16px)`;
|
||||||
|
|
||||||
|
const useOverlayLayout = (open: boolean) => {
|
||||||
|
const [drawerWidth, setDrawerWidth] = useState<number | string>(
|
||||||
|
FALLBACK_WIDTH
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return;
|
||||||
|
const formWrapper = document.querySelector<HTMLElement>(
|
||||||
|
`.${instanceStyles.formWrapper}`
|
||||||
|
);
|
||||||
|
if (formWrapper) {
|
||||||
|
setDrawerWidth(formWrapper.clientWidth);
|
||||||
|
}
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
|
const getOverlayContainer = useCallback(() => {
|
||||||
|
const containers = document.querySelectorAll<HTMLElement>(
|
||||||
|
'.ant-layout-content'
|
||||||
|
);
|
||||||
|
return containers[containers.length - 1] ?? null;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { drawerWidth, getOverlayContainer };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useOverlayLayout;
|
||||||
@@ -67,6 +67,7 @@ const usePublicKeyColumns = ({
|
|||||||
title: intl.formatMessage({ id: 'common.table.operation' }),
|
title: intl.formatMessage({ id: 'common.table.operation' }),
|
||||||
key: 'operation',
|
key: 'operation',
|
||||||
dataIndex: 'operation',
|
dataIndex: 'operation',
|
||||||
|
width: 200,
|
||||||
render: (_text, record) => (
|
render: (_text, record) => (
|
||||||
<DropdownButtons
|
<DropdownButtons
|
||||||
items={rowActionList}
|
items={rowActionList}
|
||||||
|
|||||||
Reference in New Issue
Block a user