diff --git a/src/components/Private/PrivateContent.tsx b/src/components/Private/PrivateContent.tsx index c10810e..8e9369d 100644 --- a/src/components/Private/PrivateContent.tsx +++ b/src/components/Private/PrivateContent.tsx @@ -1,11 +1,13 @@ import React from 'react' -import { Role, Permission, hasPermission, isInRole } from '../../utils/permissions' -type PrivateContentProps = { - roles?: Role[] | Role - permission?: Permission +import { isURLAvailable } from '@utils/permissions' + +export type PrivateContentProps = { + absolutePath: string children?: React.ReactElement } -export const PrivateContent: React.FC = ({ permission, roles, children = null }) => - hasPermission(permission) && isInRole(roles) ? children : null +export const PrivateContent: React.FC = ({ absolutePath, children = null }) => + isURLAvailable(absolutePath) ? children : null + +export default PrivateContent diff --git a/src/components/Private/PrivateDefaultRoute.tsx b/src/components/Private/PrivateDefaultRoute.tsx new file mode 100644 index 0000000..5e8ddbc --- /dev/null +++ b/src/components/Private/PrivateDefaultRoute.tsx @@ -0,0 +1,17 @@ +import { memo } from 'react' +import { Redirect, Route, RouteProps } from 'react-router-dom' + +import { isURLAvailable } from '@utils/permissions' + +export type PrivateDefaultRouteProps = RouteProps & { + urls: string[] + elseRedirect?: string +} + +export const PrivateDefaultRoute = memo(({ elseRedirect, urls, ...other }) => ( + + isURLAvailable(url)) ?? elseRedirect ?? '/access_denied' }} /> + +)) + +export default PrivateDefaultRoute diff --git a/src/components/Private/PrivateMenuItem.tsx b/src/components/Private/PrivateMenuItem.tsx index 0b123c0..16dd34b 100644 --- a/src/components/Private/PrivateMenuItem.tsx +++ b/src/components/Private/PrivateMenuItem.tsx @@ -1,14 +1,34 @@ -import React from 'react' +import { join } from 'path' import { Menu, MenuItemProps } from 'antd' -import { Role, Permission, hasPermission, isInRole } from '../../utils/permissions' +import { memo, NamedExoticComponent } from 'react' +import { isURLAvailable } from '@utils/permissions' +import { Link } from 'react-router-dom' -type PrivateMenuItemProps = MenuItemProps & { - roles?: Role[] | Role - permission?: Permission +export type PrivateMenuItemProps = MenuItemProps & { + root: string + path: string } -export const PrivateMenuItem: React.FC = ({ roles, permission, ...props }) => - hasPermission(permission) && isInRole(roles) ? : null +export type PrivateMenuLinkProps = MenuItemProps & { + root?: string + path: string + title: string +} + +export const PrivateMenuItemLink = memo(({ root = '', path, title, ...other }) => ( + + {title} + +)) + +export const PrivateMenuItem: NamedExoticComponent & { + Link: NamedExoticComponent +} = Object.assign(memo(({ root, path, ...other }) => + isURLAvailable(join(root, path)) ? : null +), { + Link: PrivateMenuItemLink +}) + export default PrivateMenuItem diff --git a/src/components/Private/PrivateRoute.tsx b/src/components/Private/PrivateRoute.tsx index ac5bfce..158f1b8 100644 --- a/src/components/Private/PrivateRoute.tsx +++ b/src/components/Private/PrivateRoute.tsx @@ -1,30 +1,32 @@ -import { FC, ReactNode } from 'react' import { Location } from 'history' +import { memo, ReactNode } from 'react' import { Redirect, Route, RouteProps } from 'react-router-dom' +import { join } from 'path' -import { Role, Permission, hasPermission, isInRole } from '../../utils/permissions' -import { getUserToken } from '../../utils/storage' +import { isURLAvailable } from '@utils/permissions' export type PrivateRouteProps = RouteProps & { - roles: Role[] | Role - permission?: Permission + root: string + path: string children?: ReactNode redirect?: (location?: Location) => ReactNode } export const defaultRedirect = (location?: Location) => ( - + ) -export const PrivateRoute: FC = ({ permission, roles, component, children, redirect = defaultRedirect, ...other }) => { - const available = getUserToken() && (hasPermission(permission) && isInRole(roles)) +export const PrivateRoute = memo(({ root = '', path, component, children, redirect = defaultRedirect, ...other }) => { + const available = isURLAvailable(join(root, path)) return ( - available ? children : redirect(location)} /> ) -} +}) export default PrivateRoute diff --git a/src/components/Private/index.ts b/src/components/Private/index.ts index a8db623..d37eb64 100644 --- a/src/components/Private/index.ts +++ b/src/components/Private/index.ts @@ -1,3 +1,9 @@ -export { PrivateRoute } from './PrivateRoute' +export { PrivateRoute, defaultRedirect } from './PrivateRoute' export { PrivateContent } from './PrivateContent' -export { PrivateMenuItem } from './PrivateMenuItem' +export { PrivateMenuItem, PrivateMenuItemLink } from './PrivateMenuItem' +export { PrivateDefaultRoute } from './PrivateDefaultRoute' + +export type { PrivateRouteProps } from './PrivateRoute' +export type { PrivateContentProps } from './PrivateContent' +export type { PrivateMenuItemProps, PrivateMenuLinkProps } from './PrivateMenuItem' +export type { PrivateDefaultRouteProps } from './PrivateDefaultRoute' diff --git a/src/components/UserMenu.tsx b/src/components/UserMenu.tsx index a75c165..4fd88ba 100644 --- a/src/components/UserMenu.tsx +++ b/src/components/UserMenu.tsx @@ -1,18 +1,16 @@ -import { MouseEventHandler, useState } from 'react' +import { memo, MouseEventHandler, useState } from 'react' import { Link, useHistory } from 'react-router-dom' -import { Button, Dropdown, Menu } from 'antd' +import { Button, Dropdown, DropDownProps, Menu } from 'antd' import { UserOutlined } from '@ant-design/icons' -import { getUserLogin, removeUser } from '../utils/storage' +import { getUserLogin, removeUser } from '@utils/storage' -import { PrivateMenuItem } from './Private' import { ChangePassword } from './ChangePassword' +import { PrivateMenuItemLink } from './Private/PrivateMenuItem' -type UserMenuProps = { - isAdmin?: boolean -} +type UserMenuProps = Omit & { isAdmin?: boolean } -export const UserMenu: React.FC = ({ isAdmin }) => { +export const UserMenu = memo(({ isAdmin, ...other }) => { const [isModalVisible, setIsModalVisible] = useState(false) const history = useHistory() @@ -30,16 +28,15 @@ export const UserMenu: React.FC = ({ isAdmin }) => { return ( <> - - {isAdmin ? ( - Вернуться на сайт - ) : ( - Панель администратора - )} - + {isAdmin ? ( + + ) : ( + + )} Сменить пароль @@ -58,4 +55,4 @@ export const UserMenu: React.FC = ({ isAdmin }) => { /> ) -} +}) diff --git a/src/pages/AccessDenied.jsx b/src/pages/AccessDenied.jsx new file mode 100644 index 0000000..a844099 --- /dev/null +++ b/src/pages/AccessDenied.jsx @@ -0,0 +1,15 @@ +import { memo } from 'react' + +export const AccessDenied = memo(() => ( +
+ Доступ запрещён +
+)) + +export default AccessDenied diff --git a/src/pages/AdminPanel/ClusterController.jsx b/src/pages/AdminPanel/ClusterController.jsx index 6acfc8b..17e5242 100644 --- a/src/pages/AdminPanel/ClusterController.jsx +++ b/src/pages/AdminPanel/ClusterController.jsx @@ -1,7 +1,5 @@ import { useEffect, useState } from 'react' -import { invokeWebApiWrapperAsync } from '../../components/factory' -import LoaderPortal from '../../components/LoaderPortal' import { EditableTable, makeColumn, @@ -9,10 +7,13 @@ import { makeActionHandler, makeStringSorter, defaultPagination -} from '../../components/Table' -import { AdminClusterService, AdminDepositService } from '../../services/api' -import { arrayOrDefault } from '../../utils' -import { min1 } from '../../utils/validationRules' +} from '@components/Table' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { AdminClusterService, AdminDepositService } from '@api' +import { arrayOrDefault } from '@utils' +import { min1 } from '@utils/validationRules' +import { hasPermission } from '@utils/permissions' import { coordsFixed } from './DepositController' @@ -73,9 +74,9 @@ export const ClusterController = () => { dataSource={clusters} columns={clusterColumns} pagination={defaultPagination} - onRowAdd={makeActionHandler('insert', handlerProps)} - onRowEdit={makeActionHandler('put', handlerProps)} - onRowDelete={makeActionHandler('delete', handlerProps)} + onRowAdd={hasPermission('AdminCluster.edit') && makeActionHandler('insert', handlerProps)} + onRowEdit={hasPermission('AdminCluster.edit') && makeActionHandler('put', handlerProps)} + onRowDelete={hasPermission('AdminCluster.delete') && makeActionHandler('delete', handlerProps)} /> ) diff --git a/src/pages/AdminPanel/CompanyController.jsx b/src/pages/AdminPanel/CompanyController.jsx index 0ebe59e..7eecce6 100644 --- a/src/pages/AdminPanel/CompanyController.jsx +++ b/src/pages/AdminPanel/CompanyController.jsx @@ -1,7 +1,5 @@ import { useEffect, useState } from 'react' -import { invokeWebApiWrapperAsync } from '../../components/factory' -import LoaderPortal from '../../components/LoaderPortal' import { EditableTable, makeColumn, @@ -9,10 +7,13 @@ import { makeStringSorter, makeSelectColumn, defaultPagination -} from '../../components/Table' -import { AdminCompanyService, AdminCompanyTypeService } from '../../services/api' -import { arrayOrDefault } from '../../utils' -import { min1 } from '../../utils/validationRules' +} from '@components/Table' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { AdminCompanyService, AdminCompanyTypeService } from '@api' +import { arrayOrDefault } from '@utils' +import { min1 } from '@utils/validationRules' +import { hasPermission } from '@utils/permissions' export const CompanyController = () => { @@ -70,9 +71,9 @@ export const CompanyController = () => { columns={columns} dataSource={companies} pagination={defaultPagination} - onRowAdd={makeActionHandler('insert', handlerProps)} - onRowEdit={makeActionHandler('put', handlerProps)} - onRowDelete={makeActionHandler('delete', handlerProps)} + onRowAdd={hasPermission('AdminCompany.edit') && makeActionHandler('insert', handlerProps)} + onRowEdit={hasPermission('AdminCompany.edit') && makeActionHandler('put', handlerProps)} + onRowDelete={hasPermission('AdminCompany.delete') && makeActionHandler('delete', handlerProps)} /> ) diff --git a/src/pages/AdminPanel/CompanyTypeController.jsx b/src/pages/AdminPanel/CompanyTypeController.jsx index 3cd0415..99b5110 100644 --- a/src/pages/AdminPanel/CompanyTypeController.jsx +++ b/src/pages/AdminPanel/CompanyTypeController.jsx @@ -1,17 +1,18 @@ import { useEffect, useState } from 'react' -import { invokeWebApiWrapperAsync } from '../../components/factory' -import LoaderPortal from '../../components/LoaderPortal' import { EditableTable, makeColumn, makeActionHandler, makeStringSorter, defaultPagination -} from '../../components/Table' -import { AdminCompanyTypeService } from '../../services/api' -import { arrayOrDefault } from '../../utils' -import { min1 } from '../../utils/validationRules' +} from '@components/Table' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { AdminCompanyTypeService } from '@api' +import { arrayOrDefault } from '@utils' +import { min1 } from '@utils/validationRules' +import { hasPermission } from '@asb/utils/permissions' const columns = [ makeColumn('Название', 'caption', { @@ -52,9 +53,9 @@ export const CompanyTypeController = () => { columns={columns} dataSource={companyTypes} pagination={defaultPagination} - onRowAdd={makeActionHandler('insert', handlerProps)} - onRowEdit={makeActionHandler('put', handlerProps)} - onRowDelete={makeActionHandler('delete', handlerProps)} + onRowAdd={hasPermission('AdminCompanyType.edit') && makeActionHandler('insert', handlerProps)} + onRowEdit={hasPermission('AdminCompanyType.edit') && makeActionHandler('put', handlerProps)} + onRowDelete={hasPermission('AdminCompanyType.delete') && makeActionHandler('delete', handlerProps)} /> ) diff --git a/src/pages/AdminPanel/DepositController.jsx b/src/pages/AdminPanel/DepositController.jsx index 69e77fe..8ded1ae 100644 --- a/src/pages/AdminPanel/DepositController.jsx +++ b/src/pages/AdminPanel/DepositController.jsx @@ -1,11 +1,12 @@ import { useEffect, useState } from 'react' -import LoaderPortal from '../../components/LoaderPortal' -import { invokeWebApiWrapperAsync } from '../../components/factory' -import { EditableTable, makeColumn, makeActionHandler, defaultPagination } from '../../components/Table' -import { AdminDepositService } from '../../services/api' -import { arrayOrDefault } from '../../utils' -import { min1 } from '../../utils/validationRules' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { EditableTable, makeColumn, makeActionHandler, defaultPagination } from '@components/Table' +import { AdminDepositService } from '@api' +import { arrayOrDefault } from '@utils' +import { min1 } from '@utils/validationRules' +import { hasPermission } from '@utils/permissions' export const coordsFixed = (coords) => coords && isFinite(coords) ? (+coords).toPrecision(10) : '-' @@ -45,9 +46,9 @@ export const DepositController = () => { dataSource={deposits} columns={depositColumns} pagination={defaultPagination} - onRowAdd={makeActionHandler('insert', handlerProps)} - onRowEdit={makeActionHandler('put', handlerProps)} - onRowDelete={makeActionHandler('delete', handlerProps)} + onRowAdd={hasPermission('AdminDeposit.edit') && makeActionHandler('insert', handlerProps)} + onRowEdit={hasPermission('AdminDeposit.edit') && makeActionHandler('put', handlerProps)} + onRowDelete={hasPermission('AdminDeposit.delete') && makeActionHandler('delete', handlerProps)} /> ) diff --git a/src/pages/AdminPanel/PermissionController.jsx b/src/pages/AdminPanel/PermissionController.jsx index 2c89964..b35f3c8 100644 --- a/src/pages/AdminPanel/PermissionController.jsx +++ b/src/pages/AdminPanel/PermissionController.jsx @@ -1,16 +1,17 @@ import { useEffect, useState } from 'react' -import { invokeWebApiWrapperAsync } from '../../components/factory' -import LoaderPortal from '../../components/LoaderPortal' import { EditableTable, makeActionHandler, makeColumn, makeStringSorter -} from '../../components/Table' -import { AdminPermissionService } from '../../services/api' -import { arrayOrDefault } from '../../utils' -import { min1 } from '../../utils/validationRules' +} from '@components/Table' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { AdminPermissionService } from '@api' +import { arrayOrDefault } from '@utils' +import { min1 } from '@utils/validationRules' +import { hasPermission } from '@utils/permissions' const columns = [ makeColumn('Название', 'name', { @@ -55,9 +56,9 @@ export const PermissionController = () => { columns={columns} dataSource={permissions} pagination={{ showSizeChanger: true }} - onRowAdd={makeActionHandler('insert', handlerProps)} - onRowEdit={makeActionHandler('put', handlerProps)} - onRowDelete={makeActionHandler('delete', handlerProps)} + onRowAdd={hasPermission('AdminPermission.edit') && makeActionHandler('insert', handlerProps)} + onRowEdit={hasPermission('AdminPermission.edit') && makeActionHandler('put', handlerProps)} + onRowDelete={hasPermission('AdminPermission.delete') && makeActionHandler('delete', handlerProps)} /> ) diff --git a/src/pages/AdminPanel/RoleController.jsx b/src/pages/AdminPanel/RoleController.jsx index cfc6e32..f006f97 100644 --- a/src/pages/AdminPanel/RoleController.jsx +++ b/src/pages/AdminPanel/RoleController.jsx @@ -1,12 +1,13 @@ import { memo, useEffect, useState } from 'react' -import LoaderPortal from '../../components/LoaderPortal' -import { PermissionView, RoleView } from '../../components/views' -import { invokeWebApiWrapperAsync } from '../../components/factory' -import { EditableTable, makeActionHandler, makeColumn, makeTagColumn } from '../../components/Table' -import { AdminPermissionService, AdminUserRoleService } from '../../services/api' -import { arrayOrDefault } from '../../utils' -import { min1 } from '../../utils/validationRules' +import LoaderPortal from '@components/LoaderPortal' +import { PermissionView, RoleView } from '@components/views' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { EditableTable, makeActionHandler, makeColumn, makeTagColumn } from '@components/Table' +import { AdminPermissionService, AdminUserRoleService } from '@api' +import { arrayOrDefault } from '@utils' +import { min1 } from '@utils/validationRules' +import { hasPermission } from '@utils/permissions' export const RoleController = memo(() => { const [permissions, setPermissions] = useState([]) @@ -62,9 +63,9 @@ export const RoleController = memo(() => { size={'small'} columns={columns} dataSource={roles} - onRowAdd={makeActionHandler('insert', handlerProps)} - onRowEdit={makeActionHandler('put', handlerProps)} - onRowDelete={makeActionHandler('delete', handlerProps)} + onRowAdd={hasPermission('AdminUserRole.edit') && makeActionHandler('insert', handlerProps)} + onRowEdit={hasPermission('AdminUserRole.edit') && makeActionHandler('put', handlerProps)} + onRowDelete={hasPermission('AdminUserRole.delete') && makeActionHandler('delete', handlerProps)} /> ) diff --git a/src/pages/AdminPanel/UserController/index.jsx b/src/pages/AdminPanel/UserController/index.jsx index cd649e0..06ac995 100644 --- a/src/pages/AdminPanel/UserController/index.jsx +++ b/src/pages/AdminPanel/UserController/index.jsx @@ -2,10 +2,6 @@ import { Button, Tag } from 'antd' import { UserSwitchOutlined } from '@ant-design/icons' import { useEffect, useState } from 'react' -import { RoleView } from '../../../components/views' -import LoaderPortal from '../../../components/LoaderPortal' -import { ChangePassword } from '../../../components/ChangePassword' -import { invokeWebApiWrapperAsync } from '../../../components/factory' import { EditableTable, makeColumn, @@ -14,14 +10,19 @@ import { makeStringSorter, makeNumericSorter, defaultPagination -} from '../../../components/Table' -import { AdminCompanyService, AdminUserRoleService, AdminUserService } from '../../../services/api' -import { createLoginRules, nameRules, phoneRules, emailRules } from '../../../utils/validationRules' -import { arrayOrDefault } from '../../../utils' +} from '@components/Table' +import { RoleView } from '@components/views' +import LoaderPortal from '@components/LoaderPortal' +import { ChangePassword } from '@components/ChangePassword' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { AdminCompanyService, AdminUserRoleService, AdminUserService } from '@api' +import { createLoginRules, nameRules, phoneRules, emailRules } from '@utils/validationRules' +import { makeTextOnFilter, makeTextFilters } from '@utils/table' +import { hasPermission } from '@utils/permissions' +import { arrayOrDefault } from '@utils' import RoleTag from './RoleTag' -import { makeTextOnFilter, makeTextFilters } from '../../../utils/table' export const UserController = () => { const [users, setUsers] = useState([]) @@ -153,9 +154,9 @@ export const UserController = () => { bordered columns={columns} dataSource={users} - onRowAdd={makeActionHandler('insert', handlerProps)} - onRowEdit={makeActionHandler('put', handlerProps)} - onRowDelete={makeActionHandler('delete', handlerProps)} + onRowAdd={hasPermission('AdminUser.edit') && makeActionHandler('insert', handlerProps)} + onRowEdit={hasPermission('AdminUser.edit') && makeActionHandler('put', handlerProps)} + onRowDelete={hasPermission('AdminUser.delete') && makeActionHandler('delete', handlerProps)} additionalButtons={additionalButtons} buttonsWidth={120} pagination={defaultPagination} diff --git a/src/pages/AdminPanel/WellController/TelemetrySelect.jsx b/src/pages/AdminPanel/WellController/TelemetrySelect.jsx index 10d58ac..9890e10 100644 --- a/src/pages/AdminPanel/WellController/TelemetrySelect.jsx +++ b/src/pages/AdminPanel/WellController/TelemetrySelect.jsx @@ -3,26 +3,20 @@ import { Select } from 'antd' import { getTelemetryLabel } from '@components/views' -export const TelemetrySelect = memo(({ telemetry, value, onChange }) => { - const onSelectChange = (id) => { - onChange?.(telemetry.find((row) => row.id === id)) - } - - return ( - - ) -}) +export const TelemetrySelect = memo(({ telemetry, value, onChange }) => ( + +)) export default TelemetrySelect diff --git a/src/pages/AdminPanel/WellController/index.jsx b/src/pages/AdminPanel/WellController/index.jsx index 43f8e5f..c873841 100644 --- a/src/pages/AdminPanel/WellController/index.jsx +++ b/src/pages/AdminPanel/WellController/index.jsx @@ -2,9 +2,12 @@ import { useEffect, useState } from 'react' import { Button } from 'antd' import { CopyOutlined } from '@ant-design/icons' -import LoaderPortal from '../../../components/LoaderPortal' -import { invokeWebApiWrapperAsync } from '../../../components/factory' -import { TelemetryView, CompanyView } from '../../../components/views' +import { + AdminClusterService, + AdminCompanyService, + AdminTelemetryService, + AdminWellService, +} from '@api' import { EditableTable, makeColumn, @@ -14,19 +17,17 @@ import { makeNumericSorter, makeTagColumn, defaultPagination, -} from '../../../components/Table' -import { - AdminClusterService, - AdminCompanyService, - AdminTelemetryService, - AdminWellService, -} from '../../../services/api' -import { arrayOrDefault } from '../../../utils' +} from '@components/Table' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { TelemetryView, CompanyView } from '@components/views' +import { arrayOrDefault } from '@utils' import { coordsFixed } from '../DepositController' import TelemetrySelect from './TelemetrySelect' -import '../../../styles/admin.css' +import '@styles/admin.css' +import { hasPermission } from '@asb/utils/permissions' const wellTypes = [ { value: 1, label: 'Наклонно-направленная' }, @@ -124,9 +125,9 @@ export const WellController = () => { columns={columns} dataSource={wells} pagination={defaultPagination} - onRowAdd={makeActionHandler('insert', handlerProps, recordParser)} - onRowEdit={makeActionHandler('put', handlerProps, recordParser)} - onRowDelete={makeActionHandler('delete', handlerProps)} + onRowAdd={hasPermission('AdminWell.edit') && makeActionHandler('insert', handlerProps, recordParser)} + onRowEdit={hasPermission('AdminWell.edit') && makeActionHandler('put', handlerProps, recordParser)} + onRowDelete={hasPermission('AdminWell.delete') && makeActionHandler('delete', handlerProps)} //additionalButtons={addititonalButtons} buttonsWidth={95} /> diff --git a/src/pages/AdminPanel/index.jsx b/src/pages/AdminPanel/index.jsx index 6b05d8e..5a64775 100644 --- a/src/pages/AdminPanel/index.jsx +++ b/src/pages/AdminPanel/index.jsx @@ -1,76 +1,68 @@ import { Layout, Menu } from 'antd' import { lazy, Suspense } from 'react' -import { Switch, Link, useParams, Redirect, Route } from 'react-router-dom' -import { PrivateMenuItem, PrivateRoute } from '../../components/Private' -import { SuspenseFallback } from '../SuspenseFallback' +import { Switch, useParams } from 'react-router-dom' -const ClusterController = lazy(() => import('./ClusterController')) -const CompanyController = lazy(() => import('./CompanyController')) -const DepositController = lazy(() => import('./DepositController')) -const UserController = lazy(() => import('./UserController')) -const WellController = lazy(() => import('./WellController')) -const RoleController = lazy(() => import('./RoleController')) +import { PrivateMenuItem, PrivateRoute, PrivateDefaultRoute } from '@components/Private' + +import { SuspenseFallback } from '@pages/SuspenseFallback' + +const ClusterController = lazy(() => import( './ClusterController')) +const CompanyController = lazy(() => import( './CompanyController')) +const DepositController = lazy(() => import( './DepositController')) +const UserController = lazy(() => import( './UserController')) +const WellController = lazy(() => import( './WellController')) +const RoleController = lazy(() => import( './RoleController')) const CompanyTypeController = lazy(() => import('./CompanyTypeController')) -const PermissionController = lazy(() => import('./PermissionController')) -const TelemetryController = lazy(() => import('./TelemetryController')) -const VisitLog = lazy(() => import('./VisitLog')) +const PermissionController = lazy(() => import( './PermissionController')) +const TelemetryController = lazy(() => import( './TelemetryController')) +const VisitLog = lazy(() => import( './VisitLog')) + +const rootPath = '/admin' export const AdminPanel = () => { const { tab } = useParams() - const rootPath = '/admin' return ( - - Месторождения - - - Кусты - - - Скважины - - - Пользователи - - - Компании - - - Типы компаний - - - Роли - - - Разрешения - - - Телеметрия - - - Журнал посещений - + + + + + + + + + + }> - - - - - + + + + + - - - - - - - + + + + + diff --git a/src/pages/Documents/DocumentsTemplate.jsx b/src/pages/Documents/DocumentsTemplate.jsx index d6d8d65..5b1dd33 100644 --- a/src/pages/Documents/DocumentsTemplate.jsx +++ b/src/pages/Documents/DocumentsTemplate.jsx @@ -3,6 +3,7 @@ import { useState, useEffect } from 'react' import { DatePicker, Button, Input } from 'antd' import { FileService } from '@api' +import { hasPermission } from '@utils/permissions' import LoaderPortal from '@components/LoaderPortal' import { UploadForm } from '@components/UploadForm' import { CompanyView, UserView } from '@components/views' @@ -145,15 +146,17 @@ export const DocumentsTemplate = ({ idCategory, idWell, accept, headerChild, cus    -
- Загрузка - setShowLoader(true)} - onUploadComplete={handleUploadComplete} - /> -
+ {hasPermission(`File.edit${idCategory}`) && ( +
+ Загрузка + setShowLoader(true)} + onUploadComplete={handleUploadComplete} + /> +
+ )}    {headerChild} @@ -167,7 +170,7 @@ export const DocumentsTemplate = ({ idCategory, idWell, accept, headerChild, cus showSizeChanger: false, onChange: (page) => setPage(page), }} - onRowDelete={handleFileDelete} + onRowDelete={hasPermission(`File.edit${idCategory}`) && handleFileDelete} rowKey={(record) => record.id} /> diff --git a/src/pages/Documents/index.jsx b/src/pages/Documents/index.jsx index 6185a8b..3b2e2ba 100644 --- a/src/pages/Documents/index.jsx +++ b/src/pages/Documents/index.jsx @@ -1,10 +1,10 @@ -import path from 'path' import { memo } from 'react' import { Layout, Menu } from 'antd' import { FolderOutlined } from '@ant-design/icons' -import { Switch, useParams, Link, Route } from 'react-router-dom' -import { PrivateMenuItem } from '../../components/Private' -import { isInRole } from '../../utils/permissions' +import { Switch, useParams } from 'react-router-dom' + +import { PrivateDefaultRoute, PrivateMenuItem, PrivateRoute } from '@components/Private' + import DocumentsTemplate from './DocumentsTemplate' const { Content } = Layout @@ -22,45 +22,33 @@ export const documentCategories = [ { id: 9, key: 'closingService', title: 'Сервис по заканчиванию скважины' }, ] -const getUserCategories = () => documentCategories.filter(cat => isInRole(cat.roles)) - -export const makeMenuItems = (root, cats) => (cats ?? getUserCategories()).map(category => ( - } - permission={category.permission} - roles={category.roles} - > - {category.title} - -)) - export const MenuDocuments = memo(({ idWell }) => { const { category } = useParams() - const rootPath = `/well/${idWell}` - - const root = path.join(rootPath, '/document') - const categories = getUserCategories() + const root = `/well/${idWell}/document` return ( <> - - {makeMenuItems(root, categories)} + + {documentCategories.map(category => ( + } + title={category.title} + /> + ))} - {categories.map(category => ( - + {documentCategories.map(category => ( + - + ))} + `${root}/${cat.key}`)}/> diff --git a/src/pages/Main.jsx b/src/pages/Main.jsx index 951b780..e090edf 100644 --- a/src/pages/Main.jsx +++ b/src/pages/Main.jsx @@ -1,37 +1,42 @@ -import { Redirect, Route, Switch } from 'react-router-dom' -import { PrivateRoute } from '../components/Private' -import { AdminLayoutPortal, LayoutPortal } from '../components/Layout' -import Deposit from './Deposit' -import Cluster from './Cluster' -import Well from './Well' -import AdminPanel from './AdminPanel' +import { memo } from 'react' +import { Route, Switch } from 'react-router-dom' -export const Main = () => ( +import { AdminLayoutPortal, LayoutPortal } from '@components/Layout' +import { PrivateDefaultRoute, PrivateRoute } from '@components/Private' + +import Well from './Well' +import Cluster from './Cluster' +import Deposit from './Deposit' +import AdminPanel from './AdminPanel' +import AccessDenied from './AccessDenied' + +export const Main = memo(() => ( - + - + - - + + - - + + + + + - - - + -) +)) export default Main diff --git a/src/pages/TelemetryAnalysis/index.jsx b/src/pages/TelemetryAnalysis/index.jsx index 1b8b75f..1a06a09 100644 --- a/src/pages/TelemetryAnalysis/index.jsx +++ b/src/pages/TelemetryAnalysis/index.jsx @@ -1,56 +1,57 @@ -import {Layout, Menu} from "antd"; -import {Switch, Link, Route, useParams, Redirect} from "react-router-dom"; -import { FolderOutlined } from "@ant-design/icons"; -import TelemetryAnalysisOperationsSummary from "./TelemetryAnalysisOperationsSummary"; -import TelemetryAnalysisOperationsToInterval from "./TelemetryAnalysisOperationsToInterval"; +import { memo } from 'react' +import { Layout, Menu } from 'antd' +import { FolderOutlined } from '@ant-design/icons' +import { Switch, useParams } from 'react-router-dom' + +import { PrivateDefaultRoute, PrivateRoute } from '@components/Private' +import { PrivateMenuItemLink } from '@components/Private/PrivateMenuItem' + import TelemetryAnalysisDepthToDay from './TelemetryAnalysisDepthToDay' import TelemetryAnalysisDepthToInterval from './TelemetryAnalysisDepthToInterval' +import TelemetryAnalysisOperationsSummary from './TelemetryAnalysisOperationsSummary' +import TelemetryAnalysisOperationsToInterval from './TelemetryAnalysisOperationsToInterval' const { Content } = Layout -export default function TelemetryAnalysis({idWell}) { - let {tab} = useParams() - const rootPath = `/well/${idWell}/telemetryAnalysis`; +export const TelemetryAnalysis = memo(({ idWell }) => { + const { tab } = useParams() + const rootPath = `/well/${idWell}/telemetryAnalysis` - return (<> - - }> - Глубина-день - - }> - Глубина-интервал - - }> - Все операции - - }> - Операции-интервал - - - - - - - - - - - - - - - - - - - - - - - - ) -} + return ( + <> + + } key={'depthToDay'} path={'depthToDay'} title={'Глубина-день'} /> + } key={'depthToInterval'} path={'depthToInterval'} title={'Глубина-интервал'} /> + } key={'operationsSummary'} path={'operationsSummary'} title={'Все операции'} /> + } key={'operationsToInterval'} path={'operationsToInterval'} title={'Операции-интервал'} /> + + + + + + + + + + + + + + + + + + + + + + + ) +}) + +export default TelemetryAnalysis diff --git a/src/pages/Well.jsx b/src/pages/Well.jsx index 42de06c..170ab62 100644 --- a/src/pages/Well.jsx +++ b/src/pages/Well.jsx @@ -1,4 +1,4 @@ -import { Layout, Menu } from 'antd' +import { memo } from 'react' import { FolderOutlined, FundViewOutlined, @@ -8,9 +8,10 @@ import { ExperimentOutlined, FundProjectionScreenOutlined, } from '@ant-design/icons' -import { Link, Redirect, Route, Switch, useParams } from 'react-router-dom' +import { Layout, Menu } from 'antd' +import { Switch, useParams } from 'react-router-dom' -import { PrivateMenuItem } from '@components/Private' +import { PrivateRoute, PrivateDefaultRoute, PrivateMenuItem } from '@components/Private' import Report from './Report' import Archive from './Archive' @@ -18,102 +19,76 @@ import Measure from './Measure' import Messages from './Messages' import Documents from './Documents' import TelemetryView from './TelemetryView' -import { makeMenuItems } from './Documents' import WellOperations from './WellOperations' import DrillingProgram from './DrillingProgram' import TelemetryAnalysis from './TelemetryAnalysis' const { Content } = Layout -const { SubMenu } = Menu -export const Well = () => { +export const Well = memo(() => { const { idWell, tab } = useParams() const rootPath = `/well/${idWell}` return ( - - }> - Мониторинг - - }> - Сообщения - - }> - Рапорт - - }> - Операции по скважине - - }> - Архив - - } roles={'admin'}> - Операции по телеметрии - - - Документы - - } - icon={} - selectable={true} - > - {makeMenuItems(`${rootPath}/document`)} - - }> - Измерения - - }> - Программа бурения - + + } title={'Мониторинг'}/> + } title={'Сообщения'} /> + } title={'Рапорт'} /> + } title={'Операции по скважине'} /> + } title={'Архив'} /> + } title={'Операции по телеметрии'} /> + } title={'Документы'} /> + } title={'Измерения'} /> + } title={'Программа бурения'} /> - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - + + ) -} +}) export default Well diff --git a/src/pages/WellOperations/DrillProcessFlow.jsx b/src/pages/WellOperations/DrillProcessFlow.jsx index cb62fe7..68c87c8 100644 --- a/src/pages/WellOperations/DrillProcessFlow.jsx +++ b/src/pages/WellOperations/DrillProcessFlow.jsx @@ -1,13 +1,15 @@ -import { useState, useEffect } from 'react' +import { useState, useEffect, memo } from 'react' + import { EditableTable, makeNumericMinMax, makeNumericStartEnd, -} from '../../components/Table' -import LoaderPortal from '../../components/LoaderPortal' -import { invokeWebApiWrapperAsync } from '../../components/factory' -import { DrillFlowChartService } from '../../services/api' -import { arrayOrDefault } from '../../utils' +} from '@components/Table' +import { DrillFlowChartService } from '@api' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { hasPermission } from '@utils/permissions' +import { arrayOrDefault } from '@utils' const columns = [ makeNumericStartEnd('Глубина, м', 'depth'), @@ -18,7 +20,7 @@ const columns = [ makeNumericMinMax('Расход, л/с', 'flow') ] -export const DrillProcessFlow = ({ idWell }) => { +export const DrillProcessFlow = memo(({ idWell }) => { const [flows, setFlows] = useState([]) const [showLoader, setShowLoader] = useState(false) @@ -59,11 +61,13 @@ export const DrillProcessFlow = ({ idWell }) => { bordered columns={columns} dataSource={flows} - onRowAdd={onAdd} - onRowEdit={onEdit} - onRowDelete={onDelete} + onRowAdd={hasPermission('DrillFlowChart.edit') && onAdd} + onRowEdit={hasPermission('DrillFlowChart.edit') && onEdit} + onRowDelete={hasPermission('DrillFlowChart.delete') && onDelete} pagination={false} /> ) -} +}) + +export default DrillProcessFlow diff --git a/src/pages/WellOperations/ImportExportBar.jsx b/src/pages/WellOperations/ImportExportBar.jsx index a5485a5..6dd3481 100644 --- a/src/pages/WellOperations/ImportExportBar.jsx +++ b/src/pages/WellOperations/ImportExportBar.jsx @@ -1,12 +1,14 @@ +import { memo, useState } from 'react' import { Button, Tooltip, Modal } from 'antd' -import {useState} from 'react' import { FileOutlined, ImportOutlined, ExportOutlined } from '@ant-design/icons' -import { download } from '../../components/factory' + +import { download } from '@components/factory' + import { ImportOperations } from './ImportOperations' -const style = {margin:4} +const style = { margin: 4 } -export const ImportExportBar = ({idWell, onImported, disabled}) =>{ +export const ImportExportBar = memo(({ idWell, onImported, disabled }) => { const [isImportModalVisible, setIsImportModalVisible] = useState(false) const downloadTemplate = async () => download(`/api/well/${idWell}/wellOperations/template`) @@ -14,44 +16,41 @@ export const ImportExportBar = ({idWell, onImported, disabled}) =>{ const onDone = () => { setIsImportModalVisible(false) - if(onImported) - onImported() + onImported?.() } - return <> - -