fix: admin can not delete own

This commit is contained in:
jialin
2025-10-23 17:09:30 +08:00
parent a815e71bfe
commit bf57290197
12 changed files with 57 additions and 18 deletions
+4
View File
@@ -270,6 +270,10 @@
gap: 16px; gap: 16px;
} }
.gap-4 {
gap: 4px;
}
.color-white-tertiary { .color-white-tertiary {
color: var(--color-white-tertiary); color: var(--color-white-tertiary);
} }
+3
View File
@@ -41,6 +41,9 @@ export default function useTableRowSelection() {
selectedRowKeys, selectedRowKeys,
selectedRows, selectedRows,
enableSelection: true, enableSelection: true,
getCheckboxProps: (record: Record<string, any>) => ({
disabled: record.disabled
}),
clearSelections, clearSelections,
onChange: onSelectChange, onChange: onSelectChange,
removeSelectedKeys, removeSelectedKeys,
+2 -1
View File
@@ -95,5 +95,6 @@ export default {
'resource.register.windows.support': 'win 10, win 11', 'resource.register.windows.support': 'win 10, win 11',
'resources.model.instance': 'Model Instance', 'resources.model.instance': 'Model Instance',
'resources.worker.download.privatekey': 'Download Private Key', 'resources.worker.download.privatekey': 'Download Private Key',
'resources.modelfiles.form.exsting': 'Existing' 'resources.modelfiles.form.exsting': 'Downloaded',
'resources.modelfiles.form.added': 'Added'
}; };
+4 -2
View File
@@ -96,7 +96,8 @@ export default {
'resources.model.instance': 'Model Instance', 'resources.model.instance': 'Model Instance',
'resources.worker.download.privatekey': 'Download Private Key', 'resources.worker.download.privatekey': 'Download Private Key',
'resources.worker': 'Worker', 'resources.worker': 'Worker',
'resources.modelfiles.form.exsting': 'Existing' 'resources.modelfiles.form.exsting': 'Downloaded',
'resources.modelfiles.form.added': 'Added'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -115,5 +116,6 @@ export default {
// 13. 'resources.model.instance': 'Model Instance', // 13. 'resources.model.instance': 'Model Instance',
// 14. 'resources.worker.download.privatekey': 'Download Private Key', // 14. 'resources.worker.download.privatekey': 'Download Private Key',
// 15. 'resources.worker': 'Worker', // 15. 'resources.worker': 'Worker',
// 16. 'resources.modelfiles.form.exsting': 'Existing' // 16. 'resources.modelfiles.form.exsting': 'Downloaded',
// 17. 'resources.modelfiles.form.added': 'Added'
// ========== End of To-Do List ========== // ========== End of To-Do List ==========
+4 -1
View File
@@ -94,9 +94,12 @@ export default {
'resources.model.instance': 'Модель экземпляра', 'resources.model.instance': 'Модель экземпляра',
'resources.worker.download.privatekey': 'Скачать приватный ключ', 'resources.worker.download.privatekey': 'Скачать приватный ключ',
'resources.worker': 'Worker', 'resources.worker': 'Worker',
'resources.modelfiles.form.exsting': 'Существующий' 'resources.modelfiles.form.exsting': 'Downloaded',
'resources.modelfiles.form.added': 'Added'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. 'resources.worker': 'Worker', // 1. 'resources.worker': 'Worker',
// 2. 'resources.modelfiles.form.exsting': 'Downloaded',
// 3. 'resources.modelfiles.form.added': 'Added'
// ========== End of To-Do List ========== // ========== End of To-Do List ==========
+2 -1
View File
@@ -93,5 +93,6 @@ export default {
'resource.register.windows.support': 'win 10, win 11', 'resource.register.windows.support': 'win 10, win 11',
'resources.model.instance': '模型实例', 'resources.model.instance': '模型实例',
'resources.worker.download.privatekey': '下载私钥', 'resources.worker.download.privatekey': '下载私钥',
'resources.modelfiles.form.exsting': '已存在' 'resources.modelfiles.form.exsting': '已下载',
'resources.modelfiles.form.added': '已添加'
}; };
@@ -2,7 +2,7 @@ import { PageAction } from '@/config';
import { PageActionType } from '@/config/types'; import { PageActionType } from '@/config/types';
import useAppUtils from '@/hooks/use-app-utils'; import useAppUtils from '@/hooks/use-app-utils';
import SelectPanel from '@/pages/_components/select-panel'; import SelectPanel from '@/pages/_components/select-panel';
import { queryModelsList } from '@/pages/llmodels/apis'; import { queryMyModels } from '@/pages/llmodels/apis';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Divider, Form, Radio } from 'antd'; import { Divider, Form, Radio } from 'antd';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
@@ -38,7 +38,7 @@ const AllowModelsForm: React.FC<{
const getModelList = async () => { const getModelList = async () => {
try { try {
const res = await queryModelsList(queryParams); const res = await queryMyModels(queryParams);
const options = res.items.map((item) => item.name); const options = res.items.map((item) => item.name);
if (action === PageAction.EDIT && currentData) { if (action === PageAction.EDIT && currentData) {
const list = new Set([ const list = new Set([
@@ -186,11 +186,11 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
item.title.toLowerCase().includes(inputValue.toLowerCase()) item.title.toLowerCase().includes(inputValue.toLowerCase())
} }
render={(item) => ( render={(item) => (
<span className="flex-center gap-8"> <span className="flex-center gap-4">
<span>{item.title}</span> <span>{item.title}</span>
<span className="text-tertiary"> <span className="text-tertiary">
{item.is_admin {item.is_admin
? `(${intl.formatMessage({ id: 'models.table.admin' })})` ? `[${intl.formatMessage({ id: 'models.table.admin' })}]`
: ''} : ''}
</span> </span>
</span> </span>
+8 -3
View File
@@ -52,6 +52,7 @@ const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
const { getRuleMessage } = useAppUtils(); const { getRuleMessage } = useAppUtils();
const intl = useIntl(); const intl = useIntl();
const [form] = Form.useForm(); const [form] = Form.useForm();
const localPath = Form.useWatch('local_path', form);
useEffect(() => { useEffect(() => {
const init = async () => { const init = async () => {
@@ -95,18 +96,22 @@ const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
const isExisting = currentWorker?.children?.some((child) => { const isExisting = currentWorker?.children?.some((child) => {
const isSameFile = const isSameFile =
child.fileName === (fileName || '') || child.fileName === (fileName || localPath || '') ||
minimatch(child.fileName || '', fileName || ''); minimatch(child.fileName || '', fileName || '');
return child.repoId === selectedModel?.name && isSameFile; return child.repoId === (selectedModel?.name || '') && isSameFile;
}); });
const localeId = localPath
? 'resources.modelfiles.form.added'
: 'resources.modelfiles.form.exsting';
return ( return (
<span> <span>
{data.label} {data.label}
{isExisting && ( {isExisting && (
<span className="text-tertiary m-l-4"> <span className="text-tertiary m-l-4">
({intl.formatMessage({ id: 'resources.modelfiles.form.exsting' })}) [{intl.formatMessage({ id: localeId })}]
</span> </span>
)} )}
</span> </span>
@@ -133,6 +133,7 @@ const ModelFiles = () => {
).pop() ).pop()
); );
// select the worker current model file is downloaded to.
const targetWorker = _.find(workersList, { value: record.worker_id }) const targetWorker = _.find(workersList, { value: record.worker_id })
?.labels?.['worker-name']; ?.labels?.['worker-name'];
+14 -3
View File
@@ -3,7 +3,8 @@ import AutoTooltip from '@/components/auto-tooltip';
import DropdownButtons from '@/components/drop-down-buttons'; import DropdownButtons from '@/components/drop-down-buttons';
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import icons from '@/components/icon-font/icons'; import icons from '@/components/icon-font/icons';
import { useIntl } from '@umijs/max'; import { useIntl, useModel } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Tag } from 'antd'; import { Tag } from 'antd';
import type { SortOrder } from 'antd/es/table/interface'; import type { SortOrder } from 'antd/es/table/interface';
import { ColumnsType } from 'antd/lib/table'; import { ColumnsType } from 'antd/lib/table';
@@ -35,6 +36,16 @@ const useUsersColumns = ({
sortOrder sortOrder
}: ColumnsHookProps): ColumnsType<ListItem> => { }: ColumnsHookProps): ColumnsType<ListItem> => {
const intl = useIntl(); const intl = useIntl();
const { initialState } = useModel('@@initialState') || {};
const setActions = useMemoizedFn((record: ListItem) => {
return actionList.filter((action) => {
if (initialState?.currentUser?.id === record.id) {
return action.key !== 'delete';
}
return true;
});
});
return useMemo(() => { return useMemo(() => {
return [ return [
@@ -168,13 +179,13 @@ const useUsersColumns = ({
span: 3, span: 3,
render: (text, record) => ( render: (text, record) => (
<DropdownButtons <DropdownButtons
items={actionList} items={setActions(record)}
onSelect={(val) => handleSelect(val, record)} onSelect={(val) => handleSelect(val, record)}
/> />
) )
} }
]; ];
}, [sortOrder, intl, handleSelect]); }, [sortOrder, intl, handleSelect, setActions]);
}; };
export default useUsersColumns; export default useUsersColumns;
+11 -3
View File
@@ -5,10 +5,10 @@ import { PageAction } from '@/config';
import type { PageActionType } from '@/config/types'; import type { PageActionType } from '@/config/types';
import useTableFetch from '@/hooks/use-table-fetch'; import useTableFetch from '@/hooks/use-table-fetch';
import { PageContainer } from '@ant-design/pro-components'; import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max'; import { useIntl, useModel } from '@umijs/max';
import { useMemoizedFn } from 'ahooks'; import { useMemoizedFn } from 'ahooks';
import { Button, ConfigProvider, message, Table } from 'antd'; import { Button, ConfigProvider, message, Table } from 'antd';
import { useState } from 'react'; import { useMemo, useState } from 'react';
import NoResult from '../_components/no-result'; import NoResult from '../_components/no-result';
import { createUser, deleteUser, queryUsersList, updateUser } from './apis'; import { createUser, deleteUser, queryUsersList, updateUser } from './apis';
import AddModal from './components/add-modal'; import AddModal from './components/add-modal';
@@ -35,6 +35,7 @@ const Users: React.FC = () => {
contentForDelete: 'users.table.user' contentForDelete: 'users.table.user'
}); });
const { initialState } = useModel('@@initialState') || {};
const intl = useIntl(); const intl = useIntl();
const [openAddModalStatus, setOpenAddModalStatus] = useState<{ const [openAddModalStatus, setOpenAddModalStatus] = useState<{
action: PageActionType; action: PageActionType;
@@ -155,6 +156,13 @@ const Users: React.FC = () => {
sortOrder sortOrder
}); });
const dataList = useMemo(() => {
return dataSource.dataList.map((item) => ({
...item,
disabled: initialState?.currentUser?.id === item.id
}));
}, [dataSource.dataList, initialState?.currentUser?.id]);
return ( return (
<> <>
<PageContainer <PageContainer
@@ -182,7 +190,7 @@ const Users: React.FC = () => {
<ConfigProvider renderEmpty={renderEmpty}> <ConfigProvider renderEmpty={renderEmpty}>
<Table <Table
columns={columns} columns={columns}
dataSource={dataSource.dataList} dataSource={dataList}
rowSelection={rowSelection} rowSelection={rowSelection}
loading={dataSource.loading} loading={dataSource.loading}
rowKey="id" rowKey="id"