feat(manager/users/share): Enhance device sharing functionality and update related APIs and UI components

This commit is contained in:
Tran Anh Tuan
2026-01-23 11:29:35 +07:00
parent 8b95a620c2
commit 6691122c8f
11 changed files with 782 additions and 380 deletions

View File

@@ -0,0 +1,303 @@
const LogActions = (intl: any) => {
return [
//Alarm
{
title: intl.formatMessage({
id: 'master.logs.things.alarm.confirm',
defaultMessage: 'Alarm confirm',
}),
value: '0-0',
selectable: false,
children: [
{
value: 'things.alarm_confirm',
title: intl.formatMessage({
id: 'master.logs.things.confirm',
defaultMessage: 'Confirm',
}),
},
{
value: 'things.alarm_unconfirm',
title: intl.formatMessage({
id: 'master.logs.things.unconfirm',
defaultMessage: 'Unconfirm',
}),
},
],
},
//Things
{
title: intl.formatMessage({
id: 'master.logs.things',
defaultMessage: 'Things',
}),
value: '0-1',
selectable: false,
children: [
{
value: 'things.create',
title: intl.formatMessage({
id: 'master.logs.things.create',
defaultMessage: 'Create new thing',
}),
},
{
value: 'things.update',
title: intl.formatMessage({
id: 'master.logs.things.update',
defaultMessage: 'Update thing',
}),
},
{
value: 'things.remove',
title: intl.formatMessage({
id: 'master.logs.things.remove',
defaultMessage: 'Remove thing',
}),
},
{
value: 'things.share',
title: intl.formatMessage({
id: 'master.logs.things.share',
defaultMessage: 'Share thing',
}),
},
{
value: 'things.unshare',
title: intl.formatMessage({
id: 'master.logs.things.unshare',
defaultMessage: 'Unshare thing',
}),
},
{
value: 'things.update_key',
title: intl.formatMessage({
id: 'master.logs.things.update_key',
defaultMessage: 'Update key thing',
}),
},
],
},
// Users
{
title: intl.formatMessage({
id: 'master.logs.users',
defaultMessage: 'Users',
}),
value: '0-2',
selectable: false,
children: [
{
value: 'users.create',
title: intl.formatMessage({
id: 'master.logs.users.create',
defaultMessage: 'Register user',
}),
},
{
value: 'users.update',
title: intl.formatMessage({
id: 'master.logs.users.update',
defaultMessage: 'Update user',
}),
},
{
value: 'users.remove',
title: intl.formatMessage({
id: 'master.logs.users.remove',
defaultMessage: 'Remove user',
}),
},
{
value: 'users.login',
title: intl.formatMessage({
id: 'master.logs.users.login',
defaultMessage: 'User login',
}),
},
],
},
// Groups
{
title: intl.formatMessage({
id: 'master.logs.groups',
defaultMessage: 'Groups',
}),
value: '0-3',
selectable: false,
children: [
{
value: 'group.create',
title: intl.formatMessage({
id: 'master.logs.groups.create',
defaultMessage: 'Create new group',
}),
},
{
value: 'group.update',
title: intl.formatMessage({
id: 'master.logs.groups.update',
defaultMessage: 'Update group',
}),
},
{
value: 'group.remove',
title: intl.formatMessage({
id: 'master.logs.groups.remove',
defaultMessage: 'Remove group',
}),
},
{
value: 'group.assign_thing',
title: intl.formatMessage({
id: 'master.logs.groups.assign_thing',
defaultMessage: 'Assign thing to group',
}),
},
{
value: 'group.assign_user',
title: intl.formatMessage({
id: 'master.logs.groups.assign_user',
defaultMessage: 'Assign user to group',
}),
},
{
value: 'group.unassign_thing',
title: intl.formatMessage({
id: 'master.logs.groups.unassign_thing',
defaultMessage: 'Remove thing from group',
}),
},
{
value: 'group.unassign_user',
title: intl.formatMessage({
id: 'master.logs.groups.unassign_user',
defaultMessage: 'Remove user from group',
}),
},
],
},
// Ships
{
title: intl.formatMessage({
id: 'master.logs.ships',
defaultMessage: 'Ships',
}),
value: '0-4',
selectable: false,
children: [
{
value: 'ships.create',
title: intl.formatMessage({
id: 'master.logs.ships.create',
defaultMessage: 'Create new ship',
}),
},
{
value: 'ships.update',
title: intl.formatMessage({
id: 'master.logs.ships.update',
defaultMessage: 'Update ship',
}),
},
{
value: 'ships.remove',
title: intl.formatMessage({
id: 'master.logs.ships.remove',
defaultMessage: 'Remove ship',
}),
},
{
value: 'ships.assign_thing',
title: intl.formatMessage({
id: 'master.logs.ships.assign_thing',
defaultMessage: 'Assign thing to ship',
}),
},
{
value: 'ships.assign_user',
title: intl.formatMessage({
id: 'master.logs.ships.assign_user',
defaultMessage: 'Assign user to ship',
}),
},
{
value: 'ships.unassign_thing',
title: intl.formatMessage({
id: 'master.logs.ships.unassign_thing',
defaultMessage: 'Remove thing from ship',
}),
},
{
value: 'ships.unassign_user',
title: intl.formatMessage({
id: 'master.logs.ships.unassign_user',
defaultMessage: 'Remove user from ship',
}),
},
],
},
// Trips
{
title: intl.formatMessage({
id: 'master.logs.trips',
defaultMessage: 'Trips',
}),
value: '0-5',
selectable: false,
children: [
{
value: 'trips.create',
title: intl.formatMessage({
id: 'master.logs.trips.create',
defaultMessage: 'Create new ship',
}),
},
{
value: 'trips.update',
title: intl.formatMessage({
id: 'master.logs.trips.update',
defaultMessage: 'Update ship',
}),
},
{
value: 'trips.remove',
title: intl.formatMessage({
id: 'master.logs.trips.remove',
defaultMessage: 'Remove ship',
}),
},
{
value: 'trips.approve',
title: intl.formatMessage({
id: 'master.logs.trips.approve',
defaultMessage: 'Approve trip',
}),
},
{
value: 'trips.request_approve',
title: intl.formatMessage({
id: 'master.logs.trips.request_approve',
defaultMessage: 'Request approval for trip',
}),
},
{
value: 'trips.unassign_thing',
title: intl.formatMessage({
id: 'master.logs.trips.unassign_thing',
defaultMessage: 'Remove thing from ship',
}),
},
{
value: 'trips.unassign_user',
title: intl.formatMessage({
id: 'master.logs.trips.unassign_user',
defaultMessage: 'Remove user from ship',
}),
},
],
},
];
};
export default LogActions;

View File

@@ -3,312 +3,16 @@ import { apiQueryLogs } from '@/services/master/LogController';
import { apiQueryUsers } from '@/services/master/UserController';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { theme } from 'antd';
import { DatePicker } from 'antd/lib';
import dayjs from 'dayjs';
import { useRef } from 'react';
import LogActions from './components/LogActions';
const SystemLogs = () => {
const intl = useIntl();
const tableRef = useRef<ActionType>();
const actions = [
//Alarm
{
title: intl.formatMessage({
id: 'master.logs.things.alarm.confirm',
defaultMessage: 'Alarm confirm',
}),
value: '0-0',
selectable: false,
children: [
{
value: 'things.alarm_confirm',
title: intl.formatMessage({
id: 'master.logs.things.confirm',
defaultMessage: 'Confirm',
}),
},
{
value: 'things.alarm_unconfirm',
title: intl.formatMessage({
id: 'master.logs.things.unconfirm',
defaultMessage: 'Unconfirm',
}),
},
],
},
//Things
{
title: intl.formatMessage({
id: 'master.logs.things',
defaultMessage: 'Things',
}),
value: '0-1',
selectable: false,
children: [
{
value: 'things.create',
title: intl.formatMessage({
id: 'master.logs.things.create',
defaultMessage: 'Create new thing',
}),
},
{
value: 'things.update',
title: intl.formatMessage({
id: 'master.logs.things.update',
defaultMessage: 'Update thing',
}),
},
{
value: 'things.remove',
title: intl.formatMessage({
id: 'master.logs.things.remove',
defaultMessage: 'Remove thing',
}),
},
{
value: 'things.share',
title: intl.formatMessage({
id: 'master.logs.things.share',
defaultMessage: 'Share thing',
}),
},
{
value: 'things.unshare',
title: intl.formatMessage({
id: 'master.logs.things.unshare',
defaultMessage: 'Unshare thing',
}),
},
{
value: 'things.update_key',
title: intl.formatMessage({
id: 'master.logs.things.update_key',
defaultMessage: 'Update key thing',
}),
},
],
},
// Users
{
title: intl.formatMessage({
id: 'master.logs.users',
defaultMessage: 'Users',
}),
value: '0-2',
selectable: false,
children: [
{
value: 'users.create',
title: intl.formatMessage({
id: 'master.logs.users.create',
defaultMessage: 'Register user',
}),
},
{
value: 'users.update',
title: intl.formatMessage({
id: 'master.logs.users.update',
defaultMessage: 'Update user',
}),
},
{
value: 'users.remove',
title: intl.formatMessage({
id: 'master.logs.users.remove',
defaultMessage: 'Remove user',
}),
},
{
value: 'users.login',
title: intl.formatMessage({
id: 'master.logs.users.login',
defaultMessage: 'User login',
}),
},
],
},
// Groups
{
title: intl.formatMessage({
id: 'master.logs.groups',
defaultMessage: 'Groups',
}),
value: '0-3',
selectable: false,
children: [
{
value: 'group.create',
title: intl.formatMessage({
id: 'master.logs.groups.create',
defaultMessage: 'Create new group',
}),
},
{
value: 'group.update',
title: intl.formatMessage({
id: 'master.logs.groups.update',
defaultMessage: 'Update group',
}),
},
{
value: 'group.remove',
title: intl.formatMessage({
id: 'master.logs.groups.remove',
defaultMessage: 'Remove group',
}),
},
{
value: 'group.assign_thing',
title: intl.formatMessage({
id: 'master.logs.groups.assign_thing',
defaultMessage: 'Assign thing to group',
}),
},
{
value: 'group.assign_user',
title: intl.formatMessage({
id: 'master.logs.groups.assign_user',
defaultMessage: 'Assign user to group',
}),
},
{
value: 'group.unassign_thing',
title: intl.formatMessage({
id: 'master.logs.groups.unassign_thing',
defaultMessage: 'Remove thing from group',
}),
},
{
value: 'group.unassign_user',
title: intl.formatMessage({
id: 'master.logs.groups.unassign_user',
defaultMessage: 'Remove user from group',
}),
},
],
},
// Ships
{
title: intl.formatMessage({
id: 'master.logs.ships',
defaultMessage: 'Ships',
}),
value: '0-4',
selectable: false,
children: [
{
value: 'ships.create',
title: intl.formatMessage({
id: 'master.logs.ships.create',
defaultMessage: 'Create new ship',
}),
},
{
value: 'ships.update',
title: intl.formatMessage({
id: 'master.logs.ships.update',
defaultMessage: 'Update ship',
}),
},
{
value: 'ships.remove',
title: intl.formatMessage({
id: 'master.logs.ships.remove',
defaultMessage: 'Remove ship',
}),
},
{
value: 'ships.assign_thing',
title: intl.formatMessage({
id: 'master.logs.ships.assign_thing',
defaultMessage: 'Assign thing to ship',
}),
},
{
value: 'ships.assign_user',
title: intl.formatMessage({
id: 'master.logs.ships.assign_user',
defaultMessage: 'Assign user to ship',
}),
},
{
value: 'ships.unassign_thing',
title: intl.formatMessage({
id: 'master.logs.ships.unassign_thing',
defaultMessage: 'Remove thing from ship',
}),
},
{
value: 'ships.unassign_user',
title: intl.formatMessage({
id: 'master.logs.ships.unassign_user',
defaultMessage: 'Remove user from ship',
}),
},
],
},
// Trips
{
title: intl.formatMessage({
id: 'master.logs.trips',
defaultMessage: 'Trips',
}),
value: '0-5',
selectable: false,
children: [
{
value: 'trips.create',
title: intl.formatMessage({
id: 'master.logs.trips.create',
defaultMessage: 'Create new ship',
}),
},
{
value: 'trips.update',
title: intl.formatMessage({
id: 'master.logs.trips.update',
defaultMessage: 'Update ship',
}),
},
{
value: 'trips.remove',
title: intl.formatMessage({
id: 'master.logs.trips.remove',
defaultMessage: 'Remove ship',
}),
},
{
value: 'trips.approve',
title: intl.formatMessage({
id: 'master.logs.trips.approve',
defaultMessage: 'Approve trip',
}),
},
{
value: 'trips.request_approve',
title: intl.formatMessage({
id: 'master.logs.trips.request_approve',
defaultMessage: 'Request approval for trip',
}),
},
{
value: 'trips.unassign_thing',
title: intl.formatMessage({
id: 'master.logs.trips.unassign_thing',
defaultMessage: 'Remove thing from ship',
}),
},
{
value: 'trips.unassign_user',
title: intl.formatMessage({
id: 'master.logs.trips.unassign_user',
defaultMessage: 'Remove user from ship',
}),
},
],
},
];
const { token } = theme.useToken();
const queryUserSource = async (): Promise<MasterModel.ProfileResponse[]> => {
try {
@@ -345,6 +49,10 @@ const SystemLogs = () => {
return (
<DatePicker.RangePicker
width="50%"
style={{
backgroundColor: token.colorBgContainer,
color: token.colorText,
}}
presets={[
{
label: intl.formatMessage({
@@ -404,9 +112,9 @@ const SystemLogs = () => {
treeCheckable: true,
multiple: true,
},
request: async () => actions,
request: async () => LogActions(intl),
render: (_, item) => {
const childs = actions.flatMap((a) => a.children || []);
const childs = LogActions(intl).flatMap((a) => a.children || []);
const action = childs.find((a) => a?.value === item.subtopic);
return action?.title ?? '...';
},

View File

@@ -1,7 +1,35 @@
import { ActionType, ProList } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { message } from 'antd';
import { useRef } from 'react';
import ThingsFilter from '@/components/shared/ThingFilterModal';
import { DEFAULT_PAGE_SIZE } from '@/constants';
import {
apiDeleteUserThingPolicy,
apiGetThingPolicyByUser,
apiShareThingToUser,
} from '@/services/master/ThingController';
import { DeleteOutlined, ShareAltOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
ProList,
ProListMetas,
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import {
Button,
Checkbox,
GetProp,
message,
Popconfirm,
Tag,
Typography,
} from 'antd';
import { useRef, useState } from 'react';
const { Paragraph } = Typography;
type PolicyShareDefault = {
read: boolean;
write: boolean;
delete: boolean;
};
type ShareThingProps = {
user: MasterModel.ProfileResponse | null;
@@ -9,56 +37,287 @@ type ShareThingProps = {
const ShareThing = ({ user }: ShareThingProps) => {
const listActionRef = useRef<ActionType>();
const intl = useIntl();
const [messageAPI, contextHolder] = message.useMessage();
const [messageApi, contextHolder] = message.useMessage();
const [selectedRowsState, setSelectedRows] = useState<
MasterModel.ThingPolicy[]
>([]);
const [thingPolicy, setThingPolicy] = useState<MasterModel.ThingPolicy[]>([]);
const [shareThingModalVisible, setShareThingModalVisible] =
useState<boolean>(false);
const [policyShare, setPolicyShare] = useState<PolicyShareDefault>({
read: true,
write: true,
delete: true,
});
const getPolicyInfo = (
policy: MasterModel.Policy,
): { color: string; text: string } => {
switch (policy) {
case 'read':
return {
color: 'blue',
text: intl.formatMessage({
id: 'master.users.things.relation.read',
defaultMessage: 'Read',
}),
};
case 'write':
return {
color: 'gold',
text: intl.formatMessage({
id: 'master.users.things.relation.write',
defaultMessage: 'Write',
}),
};
case 'delete':
return {
color: 'red',
text: intl.formatMessage({
id: 'master.users.things.relation.delete',
defaultMessage: 'Delete',
}),
};
default:
return { color: 'default', text: policy };
}
};
const columns: ProListMetas<MasterModel.ThingPolicy> = {
title: {
dataIndex: 'name',
render: (_, record: MasterModel.ThingPolicy) => (
<Paragraph copyable>{record?.thing_name}</Paragraph>
),
},
subTitle: {
dataIndex: 'metadata.external_id',
render: (_, record: MasterModel.ThingPolicy) => (
<Paragraph copyable>{record?.external_id}</Paragraph>
),
},
description: {
dataIndex: 'policies',
render: (_, record: MasterModel.ThingPolicy) => {
return record?.policies?.map((policy) => {
const info = getPolicyInfo(policy);
return (
<Tag key={policy} color={info.color}>
{info.text}
</Tag>
);
});
},
},
};
const handleShareThings = async (thingIds: string[]) => {
const thingsFiltered = thingIds.filter((thingId) => {
return !thingPolicy.find((thing) => thing.thing_id === thingId);
});
if (thingsFiltered.length === 0) return;
const key = 'share';
try {
messageApi.open({
type: 'loading',
content: intl.formatMessage({
id: 'master.users.things.sharing',
defaultMessage: 'Sharing devices...',
}),
key,
});
const allShare = thingsFiltered.map(async (thingId) => {
const resp = await apiShareThingToUser(
thingId,
user?.id || '',
Object.keys(policyShare).filter(
(key) => policyShare[key as keyof PolicyShareDefault],
),
);
});
await Promise.all(allShare);
messageApi.open({
type: 'success',
content: intl.formatMessage({
id: 'master.users.thing.share.success',
defaultMessage: 'Share successfully and will refresh soon',
}),
key,
});
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
if (listActionRef.current) {
listActionRef.current.reload();
}
} catch (error) {
console.error('Error when share thing: ', error);
messageApi.open({
type: 'error',
content: intl.formatMessage({
id: 'master.users.thing.share.fail',
defaultMessage: 'Share failed, please try again!',
}),
key,
});
}
};
const onChange: GetProp<typeof Checkbox.Group, 'onChange'> = (
checkedValues,
) => {
setPolicyShare({
read: checkedValues.includes('read'),
write: checkedValues.includes('write'),
delete: checkedValues.includes('delete'),
});
};
const handleUnshare = async (selectedRows: MasterModel.ThingPolicy[]) => {
if (!selectedRows) return true;
const key = 'unshare';
try {
messageApi.open({
type: 'loading',
content: intl.formatMessage({
id: 'master.users.things.unsharing',
defaultMessage: 'Unsharing devices...',
}),
key,
});
const allUnshare = selectedRows.map(async (row) => {
const resp = await apiDeleteUserThingPolicy(
row?.thing_id || '',
user?.id || '',
);
});
await Promise.all(allUnshare);
messageApi.open({
type: 'success',
content: intl.formatMessage({
id: 'master.users.thing.unshare.success',
defaultMessage: 'Unshare successfully and will refresh soon',
}),
key,
});
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
return true;
} catch (error) {
console.error('Error when unshare thing: ', error);
messageApi.open({
type: 'error',
content: intl.formatMessage({
id: 'master.users.thing.unshare.fail',
defaultMessage: 'Unshare failed, please try again!',
}),
key,
});
return false;
}
};
return (
<>
{contextHolder}
<ProList
<ThingsFilter
isOpen={shareThingModalVisible}
setIsOpen={setShareThingModalVisible}
thingIds={thingPolicy.map((thing) => thing.thing_id!)}
disabled
extra={
<Checkbox.Group
options={[
{
label: intl.formatMessage({
id: 'master.users.things.relation.read',
defaultMessage: 'Read',
}),
value: 'read',
disabled: true,
},
{
label: intl.formatMessage({
id: 'master.users.things.relation.write',
defaultMessage: 'Write',
}),
value: 'write',
},
{
label: intl.formatMessage({
id: 'master.users.things.relation.delete',
defaultMessage: 'Delete',
}),
value: 'delete',
},
]}
value={Object.keys(policyShare).filter(
(key) => policyShare[key as keyof PolicyShareDefault],
)}
onChange={onChange}
/>
}
onSubmit={handleShareThings}
/>
<ProList<MasterModel.ThingPolicy>
headerTitle={intl.formatMessage({
id: 'pages.users.things.list',
id: 'master.users.things.list',
defaultMessage: 'List things',
})}
actionRef={listActionRef}
toolBarRender={() => [
// <Button
// type="primary"
// key="primary"
// onClick={() => {
// handleShareModalVisible(true);
// }}
// >
// <PlusOutlined />{" "}
// <FormattedMessage
// id="pages.things.share.text"
// defaultMessage="Share"
// />
// </Button>,
<Button
type="primary"
key="primary"
icon={<ShareAltOutlined />}
onClick={() => {
setShareThingModalVisible(true);
}}
>
<FormattedMessage
id="master.users.thing.share.title"
defaultMessage="Share"
/>
</Button>,
]}
pagination={{
pageSize: DEFAULT_PAGE_SIZE,
}}
metas={columns}
request={async () => {
request={async (params) => {
const { current, pageSize } = params;
const query = {
type: 'sub',
id: user?.id || '',
};
if (user?.id) {
const resp = (await apiQueryThingsByPolicy(
query,
)) as PolicyResponse;
const { relations } = resp;
if (relations) {
const queries = relations.map(async (rel: PolicyRelation) => {
const thg = await apiQueryThing(rel.id);
return {
...thg,
relations: rel?.actions,
};
});
const policies = await Promise.all(queries);
const offset = current === 1 ? 0 : (current! - 1) * pageSize!;
const policyBody: Partial<MasterModel.SearchPaginationBody> = {
offset: offset,
limit: pageSize,
};
const resp = await apiGetThingPolicyByUser(policyBody, user.id);
if (resp.things) {
setThingPolicy(resp.things);
return Promise.resolve({
success: true,
data: policies,
total: policies.length,
data: resp.things,
total: resp.total,
});
} else {
return {
success: false,
data: [],
total: 0,
};
}
}
return Promise.resolve({
@@ -67,32 +326,67 @@ const ShareThing = ({ user }: ShareThingProps) => {
total: 0,
});
}}
rowKey="id"
rowKey="external_id"
search={false}
// rowSelection={{
// selectedRowKeys: selectedRowsState.map((row) => row.id).filter((id): id is string => id !== undefined),
// onChange: (_: React.Key[], selectedRows: API.Thing[]) => {
// setSelectedRows(selectedRows);
// },
// }}
/>
{/* <FormShareVms
visible={shareModalVisibale}
onVisibleChange={handleShareModalVisible}
user={user}
onSubmit={async (values: ShareFormValues) => {
console.log(values);
const success = await handleShare(values);
if (success) {
handleShareModalVisible(false);
onReload();
if (actionRef.current) {
//await delay(1000);
actionRef.current.reload();
}
}
rowSelection={{
selectedRowKeys: selectedRowsState
.map((row) => row.external_id)
.filter((id): id is string => id !== undefined),
onChange: (_, selectedRows: MasterModel.ThingPolicy[]) => {
setSelectedRows(selectedRows);
},
}}
/> */}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
<FormattedMessage
id="master.footer.chosen"
defaultMessage="Chosen"
/>{' '}
<a
style={{
fontWeight: 600,
}}
>
{selectedRowsState.length}
</a>{' '}
<FormattedMessage
id="common.paginations.things"
defaultMessage="item"
/>
</div>
}
>
<Popconfirm
title={intl.formatMessage({
id: 'master.users.thing.unshare.confirm',
defaultMessage: 'Are you sure to stop sharing these devices?',
})}
okText={intl.formatMessage({
id: 'common.sure',
defaultMessage: 'Sure',
})}
onConfirm={async () => {
const success = await handleUnshare(selectedRowsState);
if (success) {
setSelectedRows([]);
if (listActionRef.current) {
listActionRef.current.reload();
}
}
}}
>
<Button type="primary" danger icon={<DeleteOutlined />}>
<FormattedMessage
id="master.users.thing.unshare.title"
defaultMessage="Sure"
/>
</Button>
</Popconfirm>
</FooterToolbar>
)}
</>
);
};

View File

@@ -343,7 +343,7 @@ const ManagerUserPage = () => {
>
<Popconfirm
title={intl.formatMessage({
id: 'master.users.deletion.title',
id: 'master.users.delete.title',
defaultMessage: 'Are you sure to delete this selected items',
})}
okText={intl.formatMessage({