feat(manager/users/share): Enhance device sharing functionality and update related APIs and UI components
This commit is contained in:
@@ -13,17 +13,23 @@ import TreeGroup from './TreeGroup';
|
||||
|
||||
const { Paragraph } = Typography;
|
||||
type ThingsFilterProps = {
|
||||
title?: string;
|
||||
isOpen?: boolean;
|
||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
thingIds?: string | string[] | null;
|
||||
extra?: React.ReactNode;
|
||||
onSubmit?: (thingIds: string[]) => void;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const ThingsFilter = ({
|
||||
title,
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
thingIds,
|
||||
extra,
|
||||
onSubmit,
|
||||
disabled = false,
|
||||
}: ThingsFilterProps) => {
|
||||
const intl = useIntl();
|
||||
const { useBreakpoint } = Grid;
|
||||
@@ -93,6 +99,7 @@ const ThingsFilter = ({
|
||||
];
|
||||
return (
|
||||
<Modal
|
||||
title={title ? title : null}
|
||||
open={isOpen}
|
||||
centered
|
||||
width="80%"
|
||||
@@ -104,7 +111,10 @@ const ThingsFilter = ({
|
||||
<FormattedMessage id="common.cancel" defaultMessage="Cancel" />
|
||||
}
|
||||
>
|
||||
<ProCard split={screens.md ? 'vertical' : 'horizontal'}>
|
||||
<ProCard
|
||||
split={screens.md ? 'vertical' : 'horizontal'}
|
||||
extra={extra ? extra : null}
|
||||
>
|
||||
<ProCard colSpan={{ xs: 24, sm: 8, md: 8, lg: 6, xl: 6 }}>
|
||||
<TreeGroup
|
||||
disable={isLoading}
|
||||
@@ -128,6 +138,15 @@ const ThingsFilter = ({
|
||||
alwaysShowAlert: true,
|
||||
selectedRowKeys,
|
||||
onChange: (keys) => setSelectedRowKeys(keys),
|
||||
getCheckboxProps: (record) => ({
|
||||
disabled:
|
||||
disabled && thingIds && record.id
|
||||
? (Array.isArray(thingIds)
|
||||
? thingIds
|
||||
: [thingIds]
|
||||
).includes(record.id)
|
||||
: false,
|
||||
}),
|
||||
}}
|
||||
pagination={{
|
||||
size: 'small',
|
||||
|
||||
@@ -8,7 +8,8 @@ export const API_ALARMS_CONFIRM = '/api/alarms/confirm';
|
||||
|
||||
// Thing API Constants
|
||||
export const API_THINGS_SEARCH = '/api/things/search';
|
||||
export const API_THINGS_POLICY = '/api/things/policy';
|
||||
export const API_THING_POLICY = '/api/things/policy2';
|
||||
export const API_SHARE_THING = '/api/things';
|
||||
|
||||
// Group API Constants
|
||||
export const API_GROUPS = '/api/groups';
|
||||
|
||||
@@ -48,7 +48,22 @@ export default {
|
||||
'master.users.unassign.fail': 'Unassign failed',
|
||||
'master.users.assign.success': 'Assign group successful',
|
||||
'master.users.assign.fail': 'Assign group failed',
|
||||
'master.users.deletion.title': 'Are you sure to delete this selected items?',
|
||||
'master.users.delete.title': 'Are you sure to delete this selected items?',
|
||||
'master.users.delete.success': 'User deleted successfully',
|
||||
'master.users.delete.fail': 'User deletion failed',
|
||||
'master.users.things.list': 'List of devices',
|
||||
'master.users.things.relations.text': 'Relations',
|
||||
'master.users.things.relation.write': 'Control',
|
||||
'master.users.things.relation.read': 'View',
|
||||
'master.users.things.relation.delete': 'Config',
|
||||
'master.users.thing.unshare.confirm':
|
||||
'Are you sure you want to stop sharing these devices?',
|
||||
'master.users.thing.unshare.title': 'Stop Sharing',
|
||||
'master.users.things.unsharing': 'Unsharing devices...',
|
||||
'master.users.thing.unshare.success': 'Stop sharing successful',
|
||||
'master.users.thing.unshare.fail': 'Stop sharing failed',
|
||||
'master.users.thing.share.title': 'Share things',
|
||||
'master.users.things.sharing': 'Sharing devices...',
|
||||
'master.users.thing.share.success': 'Device sharing successful',
|
||||
'master.users.thing.share.fail': 'Device sharing failed',
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
'Không thể tạo đơn vị con khi gốc đã có thiết bị',
|
||||
'master.groups.add': 'Tạo đơn vị cấp dưới',
|
||||
'master.groups.delete.confirm': 'Bạn có chắc muốn xóa nhóm này không?',
|
||||
'master.groups.code': 'Mã đỡ vị',
|
||||
'master.groups.code': 'Mã đơn vị',
|
||||
'master.groups.code.exists': 'Mã đã tồn tại',
|
||||
'master.groups.short_name': 'Tên viết tắt',
|
||||
'master.groups.short_name.exists': 'Tên viết tắt đã tồn tại',
|
||||
|
||||
@@ -47,7 +47,22 @@ export default {
|
||||
'master.users.unassign.fail': 'Ngừng phân quyền thất bại',
|
||||
'master.users.assign.success': 'Phân quyền đơn vị thành công',
|
||||
'master.users.assign.fail': 'Phân quyền đơn vị thất bại',
|
||||
'master.users.deletion.title': 'Chắc chắn xoá các tài khoản đã chọn?',
|
||||
'master.users.delete.title': 'Chắc chắn xoá các tài khoản đã chọn?',
|
||||
'master.users.delete.success': 'Xoá người dùng thành công',
|
||||
'master.users.delete.fail': 'Xoá người dùng thất bại',
|
||||
'master.users.things.list': 'Danh sách thiết bị',
|
||||
'master.users.things.relations.text': 'Hành động',
|
||||
'master.users.things.relation.write': 'Điều khiển',
|
||||
'master.users.things.relation.read': 'Giám sát',
|
||||
'master.users.things.relation.delete': 'Quản lí',
|
||||
'master.users.thing.unshare.confirm':
|
||||
'Chắc chắn muốn ngừng chia sẻ các thiết bị này?',
|
||||
'master.users.thing.unshare.title': 'Ngừng chia sẻ',
|
||||
'master.users.thing.unshare.success': 'Ngừng chia sẻ thành công',
|
||||
'master.users.thing.unshare.fail': 'Ngừng chia sẻ thất bại',
|
||||
'master.users.things.unsharing': 'Đang ngừng chia sẻ thiết bị...',
|
||||
'master.users.thing.share.title': 'Chia sẻ thiết bị',
|
||||
'master.users.things.sharing': 'Đang chia sẻ thiết bị...',
|
||||
'master.users.thing.share.success': 'Chia sẻ thiết bị thành công',
|
||||
'master.users.thing.share.fail': 'Chia sẻ thiết bị thất bại',
|
||||
};
|
||||
|
||||
303
src/pages/Manager/Log/components/LogActions.tsx
Normal file
303
src/pages/Manager/Log/components/LogActions.tsx
Normal 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;
|
||||
@@ -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 ?? '...';
|
||||
},
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { API_THINGS_SEARCH } from '@/constants/api';
|
||||
import {
|
||||
API_SHARE_THING,
|
||||
API_THING_POLICY,
|
||||
API_THINGS_SEARCH,
|
||||
} from '@/constants/api';
|
||||
import { request } from '@umijs/max';
|
||||
|
||||
export async function apiSearchThings(
|
||||
@@ -28,3 +32,43 @@ export async function apiSearchThings(
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiGetThingPolicyByUser(
|
||||
params: Partial<MasterModel.SearchPaginationBody>,
|
||||
userId: string,
|
||||
) {
|
||||
return request<MasterModel.ThingPolicyResponse>(
|
||||
`${API_THING_POLICY}/${userId}`,
|
||||
{
|
||||
params: params,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export async function apiDeleteUserThingPolicy(
|
||||
thing_id: string,
|
||||
user_id: string,
|
||||
) {
|
||||
return request(`${API_SHARE_THING}/${thing_id}/share`, {
|
||||
method: 'DELETE',
|
||||
data: {
|
||||
policies: ['read', 'write', 'delete'],
|
||||
user_ids: [user_id],
|
||||
},
|
||||
getResponse: true,
|
||||
});
|
||||
}
|
||||
export async function apiShareThingToUser(
|
||||
thing_id: string,
|
||||
user_id: string,
|
||||
policies: string[],
|
||||
) {
|
||||
return request(`${API_SHARE_THING}/${thing_id}/share`, {
|
||||
method: 'POST',
|
||||
data: {
|
||||
policies: policies,
|
||||
user_ids: [user_id],
|
||||
},
|
||||
getResponse: true,
|
||||
});
|
||||
}
|
||||
|
||||
27
src/services/master/typings.d.ts
vendored
27
src/services/master/typings.d.ts
vendored
@@ -160,21 +160,24 @@ declare namespace MasterModel {
|
||||
}
|
||||
|
||||
// Thing Policy
|
||||
interface ThingPolicyResponse {
|
||||
total?: number;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
order?: string;
|
||||
direction?: string;
|
||||
metadata?: null;
|
||||
things?: ThingPolicy[];
|
||||
}
|
||||
|
||||
interface ThingPolicy {
|
||||
next_page_token?: string;
|
||||
relations?: Relation[];
|
||||
policies?: Policy[];
|
||||
thing_id?: string;
|
||||
thing_name?: string;
|
||||
external_id?: string;
|
||||
}
|
||||
|
||||
interface Relation {
|
||||
id?: string;
|
||||
actions?: Action[];
|
||||
}
|
||||
|
||||
enum Action {
|
||||
Delete = 'delete',
|
||||
Read = 'read',
|
||||
Write = 'write',
|
||||
}
|
||||
type Policy = 'read' | 'delete' | 'write';
|
||||
|
||||
// Group
|
||||
|
||||
|
||||
Reference in New Issue
Block a user