Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions src/common/Breadcrumbs/Breadcrumbs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,45 @@ illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
import React, { useMemo, useRef, useState } from 'react'
import React, { useEffect, useMemo, useRef, useState } from 'react'
import PropTypes from 'prop-types'
import { useLocation, useParams } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { useDispatch, useSelector } from 'react-redux'

import BreadcrumbsStep from './BreadcrumbsStep/BreadcrumbsStep'

import { generateMlrunScreens, generateTabsList } from './breadcrumbs.util'
import { MONITORING_APP_PAGE, PROJECTS_PAGE_PATH } from '../../constants'
import { generateProjectsList } from '../../utils/projects'
import { fetchNuclioFunctions } from '../../reducers/nuclioReducer'

import './breadcrumbs.scss'

const Breadcrumbs = ({ onClick = () => {} }) => {
const [searchValue, setSearchValue] = useState('')
const [showScreensList, setShowScreensList] = useState(false)
const [showProjectsList, setShowProjectsList] = useState(false)
const [showFunctionsList, setShowFunctionsList] = useState(false)
const breadcrumbsRef = useRef()
const params = useParams()
const location = useLocation()
const dispatch = useDispatch()

const projectStore = useSelector(state => state.projectStore)
const nuclioStore = useSelector(state => state.nuclioStore)

const projectsList = useMemo(() => {
return generateProjectsList(projectStore.projectsNames.data)
}, [projectStore.projectsNames.data])

const currentProjectFunctions = nuclioStore.currentProjectFunctions || []

useEffect(() => {
if (params.projectName && location.pathname.includes('real-time-functions')) {
dispatch(fetchNuclioFunctions({ project: params.projectName }))
}
}, [dispatch, params.projectName, location.pathname])

const mlrunScreens = useMemo(() => {
return generateMlrunScreens(params)
}, [params])
Expand All @@ -53,30 +65,35 @@ const Breadcrumbs = ({ onClick = () => {} }) => {

const urlParts = useMemo(() => {
if (params.projectName) {
const [projects, projectName, screenName] = location.pathname.split('/').slice(1, 4)
const pathParts = location.pathname.split('/').slice(1)
const [projects, projectName, screenName, functionName, ...functionPath] = pathParts

const screen = mlrunScreens.find(screen => screen.id === screenName)
let tab = projectTabs.find(tab =>
location.pathname
.split('/')
.slice(3)
.find(pathItem => pathItem === tab.id)
)

if (screen.id === MONITORING_APP_PAGE) {
let tab = projectTabs.find(tab => pathParts[2] === tab.id)

if (screen?.id === MONITORING_APP_PAGE) {
tab = {}
}

const pathItems = [projects, projectName, screen?.id || screenName]

if (screen?.id === 'real-time-functions' && functionName) {
pathItems.push(functionName)
}

return {
pathItems: [projects, projectName, screen?.label || screenName],
pathItems,
screen,
tab
tab,
functionName,
functionPath
}
} else {
const [page] = location.pathname.split('/').slice(3, 4)
const screen = mlrunScreens.find(screen => screen.id === page)

return {
pathItems: [PROJECTS_PAGE_PATH, screen?.label || page],
pathItems: [PROJECTS_PAGE_PATH, screen?.id || page],
screen
}
}
Expand All @@ -99,8 +116,11 @@ const Breadcrumbs = ({ onClick = () => {} }) => {
setSearchValue={setSearchValue}
setShowProjectsList={setShowProjectsList}
setShowScreensList={setShowScreensList}
setShowFunctionsList={setShowFunctionsList}
showProjectsList={showProjectsList}
showScreensList={showScreensList}
showFunctionsList={showFunctionsList}
currentProjectFunctions={currentProjectFunctions}
urlPart={urlPart}
urlParts={urlParts}
/>
Expand Down
86 changes: 70 additions & 16 deletions src/common/Breadcrumbs/BreadcrumbsStep/BreadcrumbsStep.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ const BreadcrumbsStep = React.forwardRef(
setSearchValue,
setShowProjectsList,
setShowScreensList,
setShowFunctionsList,
showProjectsList,
showScreensList,
showFunctionsList,
currentProjectFunctions,
urlPart,
urlParts
},
Expand All @@ -54,10 +57,13 @@ const BreadcrumbsStep = React.forwardRef(
const separatorRef = useRef()

const isParam = useMemo(() => Object.values(params ?? {}).includes(urlPart), [urlPart, params])
const label = useMemo(
() => (isParam ? urlPart : urlPart.charAt(0).toUpperCase() + urlPart.slice(1)),
[urlPart, isParam]
)
const label = useMemo(() => {
if (isParam || urlPart === urlParts.functionName) return urlPart
if (urlParts.screen && urlPart === urlParts.screen.id) {
return urlParts.screen.label || urlPart
}
return urlPart.charAt(0).toUpperCase() + urlPart.slice(1)
}, [urlPart, isParam, urlParts.screen, urlParts.functionName])
const to = useMemo(
() => `/${urlParts.pathItems.slice(0, index + 1).join('/')}`,
[index, urlParts.pathItems]
Expand All @@ -70,15 +76,35 @@ const BreadcrumbsStep = React.forwardRef(
const separatorClassNames = classnames(
'breadcrumbs__separator',
((urlParts.pathItems[index + 1] === urlParts.screen?.id && !isParam) ||
urlParts.pathItems[index + 1] === params.projectName) &&
urlParts.pathItems[index + 1] === params.projectName ||
urlParts.pathItems[index + 1] === urlParts.functionName) &&
'breadcrumbs__separator_tumbler'
)

const functionsListFormatted = useMemo(() => {
if (!Array.isArray(currentProjectFunctions)) return []

return currentProjectFunctions.map(func => {
const functionId = func?.metadata?.name || ''
const functionPath = urlParts?.functionPath?.length
? `/${urlParts.functionPath.join('/')}`
: ''

return {
id: functionId,
label: functionId,
linkTo: `${to}/${functionId}${functionPath}`
}
})
}, [currentProjectFunctions, to, urlParts.functionPath])

const handleSelectDropdownItem = separatorRef => {
if (showProjectsList) setShowProjectsList(false)

if (showScreensList) setShowScreensList(false)

if (showFunctionsList) setShowFunctionsList(false)

separatorRef.current.classList.remove('breadcrumbs__separator_active')
}

Expand All @@ -94,6 +120,8 @@ const BreadcrumbsStep = React.forwardRef(
if (showScreensList) setShowScreensList(false)

if (showProjectsList) setShowProjectsList(false)

if (showFunctionsList) setShowFunctionsList(false)
}

setSearchValue('')
Expand All @@ -103,8 +131,10 @@ const BreadcrumbsStep = React.forwardRef(
setSearchValue,
setShowProjectsList,
setShowScreensList,
setShowFunctionsList,
showProjectsList,
showScreensList
showScreensList,
showFunctionsList
]
)

Expand All @@ -127,9 +157,12 @@ const BreadcrumbsStep = React.forwardRef(
}, [handleCloseDropdown])

const handleSeparatorClick = (nextItem, separatorRef) => {
const nextItemIsScreen = Boolean(mlrunScreens.find(screen => screen.label === nextItem))
const nextItemIsScreen = Boolean(mlrunScreens.find(screen => screen.id === nextItem))
const nextItemIsFunction = Boolean(
currentProjectFunctions.find(func => func.metadata.name === nextItem)
)

if (nextItemIsScreen || nextItem === params.projectName) {
if (nextItemIsScreen || nextItem === params.projectName || nextItemIsFunction) {
const [activeSeparator] = document.getElementsByClassName('breadcrumbs__separator_active')

if (
Expand All @@ -142,17 +175,22 @@ const BreadcrumbsStep = React.forwardRef(
if (nextItemIsScreen) {
setShowScreensList(state => !state)

if (showProjectsList) {
setShowProjectsList(false)
}
if (showProjectsList) setShowProjectsList(false)
if (showFunctionsList) setShowFunctionsList(false)
}

if (nextItem === params.projectName) {
setShowProjectsList(state => !state)

if (showScreensList) {
setShowScreensList(false)
}
if (showScreensList) setShowScreensList(false)
if (showFunctionsList) setShowFunctionsList(false)
}

if (nextItemIsFunction) {
setShowFunctionsList(state => !state)

if (showScreensList) setShowScreensList(false)
if (showProjectsList) setShowProjectsList(false)
}

separatorRef.current.classList.toggle('breadcrumbs__separator_active')
Expand Down Expand Up @@ -185,7 +223,7 @@ const BreadcrumbsStep = React.forwardRef(
>
<ArrowIcon />
</RoundedIcon>
{showScreensList && urlParts.pathItems[index + 1] === urlParts.screen?.label && (
{showScreensList && urlParts.pathItems[index + 1] === urlParts.screen?.id && (
<BreadcrumbsDropdown
link={to}
list={mlrunScreens}
Expand All @@ -195,6 +233,17 @@ const BreadcrumbsStep = React.forwardRef(
setSearchValue={setSearchValue}
/>
)}
{showFunctionsList && urlParts.pathItems[index + 1] === urlParts.functionName && (
<BreadcrumbsDropdown
link={to}
list={functionsListFormatted}
onClick={() => handleSelectDropdownItem(separatorRef)}
selectedItem={urlParts.functionName}
searchValue={searchValue}
setSearchValue={setSearchValue}
withSearch
/>
)}
{showProjectsList && urlParts.pathItems[index + 1] === params.projectName && (
<>
<BreadcrumbsDropdown
Expand Down Expand Up @@ -231,8 +280,11 @@ BreadcrumbsStep.propTypes = {
setSearchValue: PropTypes.func.isRequired,
setShowProjectsList: PropTypes.func.isRequired,
setShowScreensList: PropTypes.func.isRequired,
setShowFunctionsList: PropTypes.func,
showProjectsList: PropTypes.bool.isRequired,
showScreensList: PropTypes.bool.isRequired,
showFunctionsList: PropTypes.bool,
currentProjectFunctions: PropTypes.arrayOf(PropTypes.object),
urlPart: PropTypes.string.isRequired,
urlParts: PropTypes.shape({
pathItems: PropTypes.arrayOf(PropTypes.string).isRequired,
Expand All @@ -242,7 +294,9 @@ BreadcrumbsStep.propTypes = {
}),
tab: PropTypes.shape({
id: PropTypes.string
})
}),
functionName: PropTypes.string,
functionPath: PropTypes.arrayOf(PropTypes.string)
}).isRequired
}

Expand Down
Loading