Переработан PrivateMenu для работы с любыми указанными переменными

This commit is contained in:
Александр Сироткин 2022-12-05 20:35:29 +05:00
parent 540da341da
commit cb8be79274
6 changed files with 33 additions and 33 deletions

View File

@ -5,11 +5,11 @@ import { AutoComplete } from 'antd'
import { join } from 'path' import { join } from 'path'
import { useWell } from '@asb/context' import { useWell } from '@asb/context'
import { makeItem, PrivateWellMenuItem } from './PrivateWellMenu' import { makeItem, PrivateMenuItem } from './PrivateMenu'
import { hasPermission, isURLAvailable } from '@utils' import { hasPermission, isURLAvailable } from '@utils'
import { menuItems as adminMenuItems } from '@pages/AdminPanel/AdminNavigationMenu' import { menuItems as adminMenuItems } from '@pages/AdminPanel/AdminNavigationMenu'
import { menuItems as wellMenuItems } from '@pages/Well/NavigationMenu' import { menuItems as wellMenuItems } from '@pages/Well/WellNavigationMenu'
import '@styles/fast_run_menu.less' import '@styles/fast_run_menu.less'
@ -29,7 +29,7 @@ const transliterateToEn = (text: string) => Object.entries(transliterationTable)
const applyVars = (route: string, vars?: object): string => !vars ? route : const applyVars = (route: string, vars?: object): string => !vars ? route :
Object.entries(vars).reduce((out, [key, value]) => out.replaceAll(`{${key}}`, value), route) Object.entries(vars).reduce((out, [key, value]) => out.replaceAll(`{${key}}`, value), route)
const makeOptions = (items: PrivateWellMenuItem[], vars?: object): OptionType[] => { const makeOptions = (items: PrivateMenuItem[], vars?: object): OptionType[] => {
const out: OptionType[] = [] const out: OptionType[] = []
items.forEach((item) => { items.forEach((item) => {
if (!hasPermission(item.permissions)) return if (!hasPermission(item.permissions)) return
@ -78,7 +78,7 @@ export const FastRunMenu = memo(() => {
] ]
if (isURLAvailable('/admin')) if (isURLAvailable('/admin'))
menus.push(makeItem('Панель администратора', '/admin', [], undefined, adminMenuItems as PrivateWellMenuItem[])) menus.push(makeItem('Панель администратора', '/admin', [], undefined, adminMenuItems as PrivateMenuItem[]))
if (well.id) if (well.id)
menus.push( menus.push(

View File

@ -2,16 +2,16 @@ import { Breadcrumb, BreadcrumbItemProps } from 'antd'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { join } from 'path' import { join } from 'path'
import { PrivateWellMenuItem } from '@components/PrivateWellMenu' import { PrivateMenuItem } from '@components/PrivateMenu'
import { FunctionalValue, getFunctionalValue, } from '@utils' import { FunctionalValue, getFunctionalValue, } from '@utils'
export const makeBreadcrumbItems = (items: PrivateWellMenuItem[], pathParts: string[], root: string = '/') => { export const makeBreadcrumbItems = (items: PrivateMenuItem[], pathParts: string[], root: string = '/') => {
const out = [] const out = []
const parts = [...pathParts] const parts = [...pathParts]
let route = root let route = root
let arr: PrivateWellMenuItem[] | undefined = items let arr: PrivateMenuItem[] | undefined = items
while (arr && parts.length > 0) { while (arr && parts.length > 0) {
const child: PrivateWellMenuItem | undefined = arr.find(elm => elm.route.toLowerCase() === parts[0].toLowerCase()) const child: PrivateMenuItem | undefined = arr.find(elm => elm.route.toLowerCase() === parts[0].toLowerCase())
if (!child) break if (!child) break
route = join(route, child.route) route = join(route, child.route)
out.push({ ...child, route }) out.push({ ...child, route })
@ -22,11 +22,11 @@ export const makeBreadcrumbItems = (items: PrivateWellMenuItem[], pathParts: str
} }
export const makeMenuBreadcrumbItems = ( export const makeMenuBreadcrumbItems = (
menuItems: PrivateWellMenuItem[], menuItems: PrivateMenuItem[],
path: string, path: string,
pathRoot: RegExp = /^\//, pathRoot: RegExp = /^\//,
itemsProps?: FunctionalValue<(item: PrivateWellMenuItem) => BreadcrumbItemProps>, itemsProps?: FunctionalValue<(item: PrivateMenuItem) => BreadcrumbItemProps>,
itemRender?: (item: PrivateWellMenuItem) => JSX.Element, itemRender?: (item: PrivateMenuItem) => JSX.Element,
) => { ) => {
const getItemProps = getFunctionalValue(itemsProps) const getItemProps = getFunctionalValue(itemsProps)

View File

@ -1,21 +1,21 @@
import { ItemType } from 'antd/lib/menu/hooks/useItems' import { ItemType } from 'antd/lib/menu/hooks/useItems'
import { Menu, MenuProps } from 'antd'
import { memo, ReactNode, useMemo } from 'react' import { memo, ReactNode, useMemo } from 'react'
import { Link, useLocation } from 'react-router-dom' import { Link, useLocation } from 'react-router-dom'
import { join } from 'path' import { join } from 'path'
import { Menu, MenuProps } from 'antd'
import { hasPermission, Permission } from '@utils' import { hasPermission, Permission } from '@utils'
export type PrivateWellMenuItem = { export type PrivateMenuItem = {
title: string title: string
route: string route: string
permissions: Permission | Permission[] permissions: Permission | Permission[]
icon?: ReactNode icon?: ReactNode
visible?: boolean visible?: boolean
children?: PrivateWellMenuItem[] children?: PrivateMenuItem[]
} }
const makeItems = (items: PrivateWellMenuItem[], parentRoute: string, pathParser?: (path: string, parent: string) => string): ItemType[] => { const makeItems = (items: PrivateMenuItem[], parentRoute: string, pathParser?: (path: string, parent: string) => string): ItemType[] => {
return items.map((item) => { return items.map((item) => {
if (item.visible === false || !(item.visible === true || hasPermission(item.permissions))) return null if (item.visible === false || !(item.visible === true || hasPermission(item.permissions))) return null
@ -43,11 +43,11 @@ const makeItems = (items: PrivateWellMenuItem[], parentRoute: string, pathParser
}).filter(Boolean) }).filter(Boolean)
} }
const makeItemList = (items: PrivateWellMenuItem[], rootPath: string, wellId?: number): ItemType[] => { const makeItemList = (items: PrivateMenuItem[], rootPath: string, variables: Record<string, number | string>): ItemType[] => {
const parser = (path: string, parent: string) => { const parser = (path: string, parent: string) => {
if (!path.startsWith('/')) if (!path.startsWith('/'))
path = join(parent, path) path = join(parent, path)
return path.replace(/\{wellId\}/, String(wellId)) return Object.entries(variables).reduce((out, [key, value]) => out.replaceAll(`{${key}}`, String(value)), path)
} }
return makeItems(items, rootPath, parser) return makeItems(items, rootPath, parser)
@ -58,9 +58,9 @@ export const makeItem = (
route: string, route: string,
permissions: Permission | Permission[], permissions: Permission | Permission[],
icon?: ReactNode, icon?: ReactNode,
children?: PrivateWellMenuItem[], children?: PrivateMenuItem[],
visible?: boolean visible?: boolean
): PrivateWellMenuItem => ({ ): PrivateMenuItem => ({
title, title,
route, route,
icon, icon,
@ -69,16 +69,16 @@ export const makeItem = (
visible, visible,
}) })
export type PrivateWellMenuProps = Omit<MenuProps, 'items'> & { export type PrivateMenuProps = Omit<MenuProps, 'items'> & {
idWell?: number variables?: Record<string, number | string>
items: PrivateWellMenuItem[] items: PrivateMenuItem[]
rootPath?: string rootPath?: string
} }
export const PrivateWellMenu = memo<PrivateWellMenuProps>(({ idWell, items, rootPath = '/', ...other }) => { export const PrivateMenu = memo<PrivateMenuProps>(({ variables, items, rootPath = '/', ...other }) => {
const location = useLocation() const location = useLocation()
const menuItems = useMemo(() => makeItemList(items, rootPath, idWell), [items, rootPath, idWell]) const menuItems = useMemo(() => makeItemList(items, rootPath, variables || {}), [items, rootPath, variables])
const tabKeys = useMemo(() => { const tabKeys = useMemo(() => {
const out = [] const out = []

View File

@ -12,7 +12,7 @@ import {
UserOutlined, UserOutlined,
} from '@ant-design/icons' } from '@ant-design/icons'
import { makeItem, PrivateWellMenu } from '@components/PrivateWellMenu' import { makeItem, PrivateMenu } from '@components/PrivateMenu'
import { isDev } from '@utils' import { isDev } from '@utils'
export const menuItems = [ export const menuItems = [
@ -33,7 +33,7 @@ export const menuItems = [
].filter(Boolean) ].filter(Boolean)
export const AdminNavigationMenu = memo((props) => ( export const AdminNavigationMenu = memo((props) => (
<PrivateWellMenu <PrivateMenu
{...props} {...props}
items={menuItems} items={menuItems}
rootPath={'/admin'} rootPath={'/admin'}

View File

@ -13,7 +13,7 @@ import {
TableOutlined, TableOutlined,
} from '@ant-design/icons' } from '@ant-design/icons'
import { makeItem, PrivateWellMenu } from '@components/PrivateWellMenu' import { makeItem, PrivateMenu } from '@components/PrivateMenu'
export const menuItems = [ export const menuItems = [
makeItem('Телеметрия', 'telemetry', [], <FundViewOutlined />, [ makeItem('Телеметрия', 'telemetry', [], <FundViewOutlined />, [
@ -59,15 +59,15 @@ export const menuItems = [
makeItem('Дело скважины', 'well_case', [], <FolderOutlined />), makeItem('Дело скважины', 'well_case', [], <FolderOutlined />),
] ]
export const NavigationMenu = memo((props) => ( export const WellNavigationMenu = memo((props) => (
<PrivateWellMenu <PrivateMenu
{...props} {...props}
items={menuItems} items={menuItems}
rootPath={'/well/{wellId}'} rootPath={'/well/{idWell}'}
mode={'inline'} mode={'inline'}
theme={'dark'} theme={'dark'}
style={{ backgroundColor: 'transparent' }} style={{ backgroundColor: 'transparent' }}
/> />
)) ))
export default NavigationMenu export default WellNavigationMenu

View File

@ -8,7 +8,7 @@ import { makeMenuBreadcrumbItems } from '@components/MenuBreadcrumb'
import { NoAccessComponent, withPermissions } from '@utils' import { NoAccessComponent, withPermissions } from '@utils'
import { WellService } from '@api' import { WellService } from '@api'
import { NavigationMenu, menuItems } from './NavigationMenu' import { WellNavigationMenu, menuItems } from './WellNavigationMenu'
import '@styles/index.css' import '@styles/index.css'
@ -81,7 +81,7 @@ const Well = memo(() => {
}, [idWell]) }, [idWell])
useEffect(() => setLayoutProps({ useEffect(() => setLayoutProps({
sider: <NavigationMenu idWell={well.id} />, sider: <WellNavigationMenu variables={{ idWell: well.id }} />,
breadcrumb: makeMenuBreadcrumbItems(menuItems, location.pathname, /^\/well\/[0-9]+\//), breadcrumb: makeMenuBreadcrumbItems(menuItems, location.pathname, /^\/well\/[0-9]+\//),
topRightBlock: topRightBlock?.(well), topRightBlock: topRightBlock?.(well),
}), [well, location.pathname, setLayoutProps, topRightBlock]) }), [well, location.pathname, setLayoutProps, topRightBlock])