Улучшен роутинг. Добавлен компонент PrivateMenu

This commit is contained in:
goodmice 2022-04-19 12:51:30 +05:00
parent 6d833c75c5
commit 4b55f0e891
12 changed files with 132 additions and 87 deletions

View File

@ -0,0 +1,45 @@
import { join } from 'path'
import { Menu, MenuItemProps, MenuProps } from 'antd'
import { Children, cloneElement, memo, ReactElement } from 'react'
import { Link, useLocation } from 'react-router-dom'
import { isURLAvailable } from '@utils/permissions'
export type PrivateMenuProps = MenuProps & { root?: string }
export type PrivateMenuLinkProps = MenuItemProps & {
tabName?: string
path?: string
title: string
visible?: boolean
}
export const PrivateMenuLink = memo<PrivateMenuLinkProps>(({ tabName = '', path = '', title, ...other }) => {
const location = useLocation()
return (
<Menu.Item key={tabName} {...other}>
<Link to={{ pathname: path, state: { from: location.pathname }}}>{title}</Link>
</Menu.Item>
)
})
const PrivateMenuMain = memo<PrivateMenuProps>(({ root = '', children, ...other }) => {
const items = Children.toArray(children).map((child) => {
const element = child as ReactElement
let key = element.key?.toString()
const visible: boolean | undefined = element.props.visible
if (key && visible !== false) {
key = key.slice(key.lastIndexOf('$') + 1) // Ключ автоматический преобразуется в "(.+)\$ключ"
const path = join(root, key)
if (visible || isURLAvailable(path))
return cloneElement(element, { key, path, tabName: key })
}
return null
})
return <Menu children={items} {...other} />
})
export const PrivateMenu = Object.assign(PrivateMenuMain, { Link: PrivateMenuLink })
export default PrivateMenu

View File

@ -1,22 +1,22 @@
import { join } from 'path'
import { Menu, MenuItemProps } from 'antd'
import { memo, NamedExoticComponent } from 'react'
import { Link, useLocation } from 'react-router-dom'
import { isURLAvailable } from '@utils/permissions'
import { Link, useLocation } from 'react-router-dom'
export type PrivateMenuItemProps = MenuItemProps & {
root: string
path: string
}
export type PrivateMenuLinkProps = MenuItemProps & {
export type PrivateMenuItemLinkProps = MenuItemProps & {
root?: string
path: string
title: string
}
export const PrivateMenuItemLink = memo<PrivateMenuLinkProps>(({ root = '', path, title, ...other }) => {
export const PrivateMenuItemLink = memo<PrivateMenuItemLinkProps>(({ root = '', path, title, ...other }) => {
const location = useLocation()
return (
<PrivateMenuItem key={path} root={root} path={path} {...other}>
@ -26,9 +26,9 @@ export const PrivateMenuItemLink = memo<PrivateMenuLinkProps>(({ root = '', path
})
export const PrivateMenuItem: NamedExoticComponent<PrivateMenuItemProps> & {
Link: NamedExoticComponent<PrivateMenuLinkProps>
Link: NamedExoticComponent<PrivateMenuItemLinkProps>
} = Object.assign(memo<PrivateMenuItemProps>(({ root, path, ...other }) =>
isURLAvailable(join(root, path)) ? <Menu.Item key={path} {...other}/> : null
<Menu.Item key={path} hidden={!isURLAvailable(join(root, path))} {...other} />
), {
Link: PrivateMenuItemLink
})

View File

@ -1,9 +1,11 @@
export { PrivateRoute, defaultRedirect } from './PrivateRoute'
export { PrivateContent } from './PrivateContent'
export { PrivateMenuItem, PrivateMenuItemLink } from './PrivateMenuItem'
export { PrivateContent } from './PrivateContent' // TODO: Remove
export { PrivateMenuItem, PrivateMenuItemLink } from './PrivateMenuItem' // TODO: Remove
export { PrivateDefaultRoute } from './PrivateDefaultRoute'
export { PrivateMenu, PrivateMenuLink } from './PrivateMenu'
export type { PrivateRouteProps } from './PrivateRoute'
export type { PrivateContentProps } from './PrivateContent'
export type { PrivateMenuItemProps, PrivateMenuLinkProps } from './PrivateMenuItem'
export type { PrivateContentProps } from './PrivateContent' // TODO: Remove
export type { PrivateMenuItemProps, PrivateMenuItemLinkProps } from './PrivateMenuItem' // TODO: Remove
export type { PrivateDefaultRouteProps } from './PrivateDefaultRoute'
export type { PrivateMenuProps, PrivateMenuLinkProps } from './PrivateMenu'

View File

@ -1,8 +1,8 @@
import { Layout, Menu } from 'antd'
import { Layout } from 'antd'
import { lazy, memo, Suspense } from 'react'
import { Switch, useParams } from 'react-router-dom'
import { PrivateMenuItem, PrivateRoute, PrivateDefaultRoute } from '@components/Private'
import { PrivateRoute, PrivateDefaultRoute, PrivateMenu } from '@components/Private'
import { SuspenseFallback } from '@pages/SuspenseFallback'
@ -16,10 +16,10 @@ export const Telemetry = memo(() => {
return (
<Layout>
<Menu mode={'horizontal'} selectable={true} selectedKeys={[tab]}>
<PrivateMenuItem.Link root={rootPath} key={'viewer'} path={'viewer'} title={'Просмотр'} />
<PrivateMenuItem.Link root={rootPath} key={'merger'} path={'merger'} title={'Объединение'} />
</Menu>
<PrivateMenu root={rootPath} mode={'horizontal'} selectable={true} selectedKeys={[tab]}>
<PrivateMenu.Link key={'viewer'} title={'Просмотр'} />
<PrivateMenu.Link key={'merger'} title={'Объединение'} />
</PrivateMenu>
<Layout>
<Layout.Content className={'site-layout-background'}>

View File

@ -1,8 +1,8 @@
import { Layout, Menu } from 'antd'
import { Layout } from 'antd'
import { lazy, memo, Suspense } from 'react'
import { Switch, useParams } from 'react-router-dom'
import { PrivateMenuItem, PrivateRoute, PrivateDefaultRoute } from '@components/Private'
import { PrivateRoute, PrivateDefaultRoute, PrivateMenu } from '@components/Private'
import { SuspenseFallback } from '@pages/SuspenseFallback'
@ -24,18 +24,18 @@ export const AdminPanel = memo(() => {
return (
<Layout>
<Menu mode={'horizontal'} selectable={true} selectedKeys={[tab]}>
<PrivateMenuItem.Link root={rootPath} key={'deposit' } path={'deposit' } title={'Месторождения' } />
<PrivateMenuItem.Link root={rootPath} key={'cluster' } path={'cluster' } title={'Кусты' } />
<PrivateMenuItem.Link root={rootPath} key={'well' } path={'well' } title={'Скважины' } />
<PrivateMenuItem.Link root={rootPath} key={'user' } path={'user' } title={'Пользователи' } />
<PrivateMenuItem.Link root={rootPath} key={'company' } path={'company' } title={'Компании' } />
<PrivateMenuItem.Link root={rootPath} key={'company_type'} path={'company_type'} title={'Типы компаний' } />
<PrivateMenuItem.Link root={rootPath} key={'role' } path={'role' } title={'Роли' } />
<PrivateMenuItem.Link root={rootPath} key={'permission' } path={'permission' } title={'Разрешения' } />
<PrivateMenuItem.Link root={rootPath} key={'telemetry' } path={'telemetry' } title={'Телеметрия' } />
<PrivateMenuItem.Link root={rootPath} key={'visit_log' } path={'visit_log' } title={'Журнал посещений'} />
</Menu>
<PrivateMenu root={rootPath} mode={'horizontal'} selectable={true} selectedKeys={[tab]}>
<PrivateMenu.Link key={'deposit' } title={'Месторождения' } />
<PrivateMenu.Link key={'cluster' } title={'Кусты' } />
<PrivateMenu.Link key={'well' } title={'Скважины' } />
<PrivateMenu.Link key={'user' } title={'Пользователи' } />
<PrivateMenu.Link key={'company' } title={'Компании' } />
<PrivateMenu.Link key={'company_type'} title={'Типы компаний' } />
<PrivateMenu.Link key={'role' } title={'Роли' } />
<PrivateMenu.Link key={'permission' } title={'Разрешения' } />
<PrivateMenu.Link key={'telemetry' } title={'Телеметрия' } />
<PrivateMenu.Link key={'visit_log' } title={'Журнал посещений'} />
</PrivateMenu>
<Layout>
<Layout.Content className={'site-layout-background'}>

View File

@ -1,6 +1,6 @@
import { useState, useEffect, memo } from 'react'
import { Switch, useParams } from 'react-router-dom'
import { Col, Layout, Menu, Row } from 'antd'
import { Col, Layout, Row } from 'antd'
import {
OperationStatService,
@ -10,7 +10,7 @@ import { arrayOrDefault } from '@utils'
import LoaderPortal from '@components/LoaderPortal'
import WellSelector from '@components/selectors/WellSelector'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { PrivateDefaultRoute, PrivateMenuItemLink, PrivateRoute } from '@components/Private'
import { PrivateDefaultRoute, PrivateMenu, PrivateMenuItemLink, PrivateRoute } from '@components/Private'
import ClusterWells from '@pages/Cluster/ClusterWells'
import { WellCompositeSections } from './WellCompositeSections'
@ -67,10 +67,10 @@ export const WellCompositeEditor = memo(({ idWell, rootPath }) => {
/>
</Col>
<Col span={6}>
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
<PrivateMenuItemLink root={rootPath} key={'wells'} path={'wells'} title={'Статистика по скважинам'} />
<PrivateMenuItemLink root={rootPath} key={'sections'} path={'sections'} title={'Статистика по секциям'} />
</Menu>
<PrivateMenu root={rootPath} mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
<PrivateMenuItemLink key={'wells'} title={'Статистика по скважинам'} />
<PrivateMenuItemLink key={'sections'} title={'Статистика по секциям'} />
</PrivateMenu>
</Col>
</Row>
<Layout>

View File

@ -1,8 +1,8 @@
import { memo, useMemo } from 'react'
import { Layout, Menu } from 'antd'
import { Layout } from 'antd'
import { Switch, useParams } from 'react-router-dom'
import { PrivateDefaultRoute, PrivateMenuItemLink, PrivateRoute } from '@components/Private'
import { PrivateDefaultRoute, PrivateMenu, PrivateRoute } from '@components/Private'
import WellCompositeEditor from './WellCompositeEditor'
import Statistics from './Statistics'
@ -13,10 +13,10 @@ export const Analytics = memo(({ idWell }) => {
return (
<Layout>
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
<PrivateMenuItemLink root={rootPath} key={'composite'} path={'composite'} title={'Композитная скважина'} />
<PrivateMenuItemLink root={rootPath} key={'statistics'} path={'statistics'} title={'Оценка по ЦБ'} />
</Menu>
<PrivateMenu root={rootPath} mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
<PrivateMenu.Link key={'composite'} title={'Композитная скважина'} />
<PrivateMenu.Link key={'statistics'} title={'Оценка по ЦБ'} />
</PrivateMenu>
<Layout>
<Layout.Content>
<Switch>

View File

@ -1,10 +1,10 @@
import { join } from 'path'
import { memo, useMemo } from 'react'
import { Layout, Menu } from 'antd'
import { Layout } from 'antd'
import { FolderOutlined } from '@ant-design/icons'
import { Switch, useParams } from 'react-router-dom'
import { PrivateDefaultRoute, PrivateMenuItemLink, PrivateRoute } from '@components/Private'
import { PrivateDefaultRoute, PrivateMenu, PrivateRoute } from '@components/Private'
import DocumentsTemplate from './DocumentsTemplate'
@ -29,18 +29,16 @@ export const MenuDocuments = memo(({ idWell }) => {
return (
<>
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[category]}>
<PrivateMenu root={root} mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[category]}>
{documentCategories.map(category => (
<PrivateMenuItemLink
root={root}
<PrivateMenu.Link
key={`${category.key}`}
path={`${category.key}`}
className={'ant-menu-item'}
icon={<FolderOutlined/>}
title={category.title}
/>
))}
</Menu>
</PrivateMenu>
<Layout>
<Content className={'site-layout-background'}>
<Switch>

View File

@ -1,9 +1,10 @@
import { Switch, useParams } from 'react-router-dom'
import { memo, useMemo } from 'react'
import { Layout, Menu } from 'antd'
import { Layout } from 'antd'
import { AlertOutlined, FundViewOutlined, DatabaseOutlined } from '@ant-design/icons'
import { PrivateRoute, PrivateDefaultRoute, PrivateMenuItem } from '@components/Private'
import PrivateMenu from '@components/Private/PrivateMenu'
import { PrivateRoute, PrivateDefaultRoute } from '@components/Private'
import Archive from './Archive'
import Messages from './Messages'
@ -20,12 +21,12 @@ export const Telemetry = memo(({ idWell }) => {
return (
<Layout>
<Menu mode={'horizontal'} selectable={true} selectedKeys={[tab]} className={'well_menu'}>
<PrivateMenuItem.Link root={rootPath} key={'monitoring'} path={'monitoring'} icon={<FundViewOutlined />} title={'Мониторинг'}/>
<PrivateMenuItem.Link root={rootPath} key={'messages'} path={'messages'} icon={<AlertOutlined/>} title={'Сообщения'} />
<PrivateMenuItem.Link root={rootPath} key={'archive'} path={'archive'} icon={<DatabaseOutlined />} title={'Архив'} />
<PrivateMenuItem.Link root={rootPath} key={'dashboard_nnb'} path={'dashboard_nnb'} title={'ННБ'} />
</Menu>
<PrivateMenu root={rootPath} mode={'horizontal'} selectable={true} selectedKeys={[tab]} className={'well_menu'}>
<PrivateMenu.Link key={'monitoring'} icon={<FundViewOutlined />} title={'Мониторинг'}/>
<PrivateMenu.Link key={'messages'} icon={<AlertOutlined/>} title={'Сообщения'} />
<PrivateMenu.Link key={'archive'} icon={<DatabaseOutlined />} title={'Архив'} />
<PrivateMenu.Link key={'dashboard_nnb'} title={'ННБ'} />
</PrivateMenu>
<Layout>
<Content className={'site-layout-background'}>

View File

@ -1,10 +1,9 @@
import { memo } from 'react'
import { Layout, Menu } from 'antd'
import { Layout } 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 { PrivateDefaultRoute, PrivateMenu, PrivateRoute } from '@components/Private'
import TelemetryAnalysisDepthToDay from './TelemetryAnalysisDepthToDay'
import TelemetryAnalysisDepthToInterval from './TelemetryAnalysisDepthToInterval'
@ -19,12 +18,12 @@ export const TelemetryAnalysis = memo(({ idWell }) => {
return (
<>
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
<PrivateMenuItemLink root={rootPath} icon={<FolderOutlined />} key={'depthToDay'} path={'depthToDay'} title={'Глубина-день'} />
<PrivateMenuItemLink root={rootPath} icon={<FolderOutlined />} key={'depthToInterval'} path={'depthToInterval'} title={'Глубина-интервал'} />
<PrivateMenuItemLink root={rootPath} icon={<FolderOutlined />} key={'operationsSummary'} path={'operationsSummary'} title={'Все операции'} />
<PrivateMenuItemLink root={rootPath} icon={<FolderOutlined />} key={'operationsToInterval'} path={'operationsToInterval'} title={'Операции-интервал'} />
</Menu>
<PrivateMenu root={rootPath} mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
<PrivateMenu.Link icon={<FolderOutlined />} key={'depthToDay'} title={'Глубина-день'} />
<PrivateMenu.Link icon={<FolderOutlined />} key={'depthToInterval'} title={'Глубина-интервал'} />
<PrivateMenu.Link icon={<FolderOutlined />} key={'operationsSummary'} title={'Все операции'} />
<PrivateMenu.Link icon={<FolderOutlined />} key={'operationsToInterval'} title={'Операции-интервал'} />
</PrivateMenu>
<Layout>
<Content className={'site-layout-background'}>

View File

@ -6,10 +6,10 @@ import {
ExperimentOutlined,
DeploymentUnitOutlined,
} from '@ant-design/icons'
import { Layout, Menu } from 'antd'
import { Layout } from 'antd'
import { Switch, useParams } from 'react-router-dom'
import { PrivateRoute, PrivateDefaultRoute, PrivateMenuItem } from '@components/Private'
import { PrivateRoute, PrivateDefaultRoute, PrivateMenu } from '@components/Private'
import Report from './Report'
import Measure from './Measure'
@ -30,16 +30,16 @@ export const Well = memo(() => {
return (
<Layout>
<Menu mode={'horizontal'} selectable={true} selectedKeys={[tab]} className={'well_menu'}>
<PrivateMenuItem.Link root={rootPath} key={'telemetry'} path={'telemetry'} icon={<FundViewOutlined />} title={'Телеметрия'}/>
<PrivateMenuItem.Link root={rootPath} key={'report'} path={'report'} icon={<FilePdfOutlined />} title={'Рапорт'} />
<PrivateMenuItem.Link root={rootPath} key={'analytics'} path={'analytics'} icon={<DeploymentUnitOutlined />} title={'Аналитика'} />
<PrivateMenuItem.Link root={rootPath} key={'operations'} path={'operations'} icon={<FolderOutlined />} title={'Операции по скважине'} />
{/* <PrivateMenuItem.Link root={rootPath} key={'telemetryAnalysis'} path={'telemetryAnalysis'} icon={<FundProjectionScreenOutlined />} title={'Операции по телеметрии'} /> */}
<PrivateMenuItem.Link root={rootPath} key={'document'} path={'document'} icon={<FolderOutlined />} title={'Документы'} />
<PrivateMenuItem.Link root={rootPath} key={'measure'} path={'measure'} icon={<ExperimentOutlined />} title={'Измерения'} />
<PrivateMenuItem.Link root={rootPath} key={'drillingProgram'} path={'drillingProgram'} icon={<FolderOutlined />} title={'Программа бурения'} />
</Menu>
<PrivateMenu root={rootPath} mode={'horizontal'} selectable={true} selectedKeys={[tab]} className={'well_menu'}>
<PrivateMenu.Link key={'telemetry'} icon={<FundViewOutlined />} title={'Телеметрия'}/>
<PrivateMenu.Link key={'report'} icon={<FilePdfOutlined />} title={'Рапорт'} />
<PrivateMenu.Link key={'analytics'} icon={<DeploymentUnitOutlined />} title={'Аналитика'} />
<PrivateMenu.Link key={'operations'} icon={<FolderOutlined />} title={'Операции по скважине'} />
{/* <PrivateMenu.Link key={'telemetryAnalysis'} icon={<FundProjectionScreenOutlined />} title={'Операции по телеметрии'} /> */}
<PrivateMenu.Link key={'document'} icon={<FolderOutlined />} title={'Документы'} />
<PrivateMenu.Link key={'measure'} icon={<ExperimentOutlined />} title={'Измерения'} />
<PrivateMenu.Link key={'drillingProgram'} icon={<FolderOutlined />} title={'Программа бурения'} />
</PrivateMenu>
<Layout>
<Content className={'site-layout-background'}>

View File

@ -1,5 +1,5 @@
import { memo, useCallback } from 'react'
import { Layout, Menu } from 'antd'
import { Layout } from 'antd'
import { Switch, useParams, useHistory, useLocation } from 'react-router-dom'
import {
BarChartOutlined,
@ -9,7 +9,7 @@ import {
TableOutlined,
} from '@ant-design/icons'
import { PrivateDefaultRoute, PrivateRoute, PrivateMenuItemLink } from '@components/Private'
import { PrivateDefaultRoute, PrivateRoute, PrivateMenu } from '@components/Private'
import { Tvd } from './Tvd'
import { ImportExportBar } from './ImportExportBar'
@ -36,14 +36,14 @@ export const WellOperations = memo(({ idWell }) => {
return(
<>
<Flex style={{ width: '100%' }}>
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]} style={{ flex: 1 }}>
<PrivateMenuItemLink root={rootPath} icon={<LineChartOutlined />} key={'tvd'} path={'tvd'} title={'TVD'} />
<PrivateMenuItemLink root={rootPath} icon={<BuildOutlined />} key={'sections'} path={'sections'} title={'Секции'} />
<PrivateMenuItemLink root={rootPath} icon={<TableOutlined />} key={'plan'} path={'plan'} title={'План'} />
<PrivateMenuItemLink root={rootPath} icon={<TableOutlined />} key={'fact'} path={'fact'} title={'Факт'} />
<PrivateMenuItemLink root={rootPath} icon={<BarChartOutlined />} key={'drillProcessFlow'} path={'drillProcessFlow'} title={'РТК'} />
<PrivateMenuItemLink root={rootPath} icon={<ControlOutlined />} key={'params'} path={'params'} title={'Режимы'} />
</Menu>
<PrivateMenu root={rootPath} mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]} style={{ flex: 1 }}>
<PrivateMenu.Link icon={<LineChartOutlined />} key={'tvd'} title={'TVD'} />
<PrivateMenu.Link icon={<BuildOutlined />} key={'sections'} title={'Секции'} />
<PrivateMenu.Link icon={<TableOutlined />} key={'plan'} title={'План'} />
<PrivateMenu.Link icon={<TableOutlined />} key={'fact'} title={'Факт'} />
<PrivateMenu.Link icon={<BarChartOutlined />} key={'drillProcessFlow'} title={'РТК'} />
<PrivateMenu.Link icon={<ControlOutlined />} key={'params'} title={'Режимы'} />
</PrivateMenu>
<ImportExportBar idWell={idWell} disabled={isIEBarDisabled} onImported={onImported}/>
</Flex>
<Layout>