Skip to content

feat: add tree view component #803

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: release-candidate-v0.39.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
67af0c3
feat: refactor ActionMenuItem and add TrailingItem component for impr…
AbhishekA1509 Jun 23, 2025
0c20da6
feat: add base structure for TreeView
AbhishekA1509 Jun 23, 2025
73acec4
fix: css alignment for dividers
AbhishekA1509 Jun 25, 2025
739b759
feat: make variant prop optional in TrailingItemProps and improve Tre…
AbhishekA1509 Jun 25, 2025
439a4c6
feat: add mode prop to TreeViewProps for navigation and form modes, a…
AbhishekA1509 Jun 26, 2025
5eba693
feat: update TreeViewProps to support optional depth, flatNodeList, a…
AbhishekA1509 Jun 27, 2025
9367515
feat: enhance TreeView component with selected state styling and refa…
AbhishekA1509 Jun 27, 2025
4be78b7
feat: refactor Tooltip component and introduce TreeViewNodeContent fo…
AbhishekA1509 Jun 30, 2025
d0fc33f
feat: integrate framer-motion for animated transitions in TreeView co…
AbhishekA1509 Jun 30, 2025
7db4a2d
feat: copilot review
AbhishekA1509 Jun 30, 2025
6aa852b
feat: add click handlers for TreeView node items to manage button and…
AbhishekA1509 Jun 30, 2025
029324c
feat: update TreeView and related components to support selection sta…
AbhishekA1509 Jul 1, 2025
fa6b56e
feat: enhance Sidebar component to support TreeView structure and add…
AbhishekA1509 Jul 1, 2025
6445985
feat: refactor TreeView component to support uncontrolled mode and up…
AbhishekA1509 Jul 1, 2025
1df23b8
Merge branch 'fix/rb-table' of https://github.com/devtron-labs/devtro…
AbhishekA1509 Jul 1, 2025
4e9118d
feat: add variant support to TreeView for customizable background and…
AbhishekA1509 Jul 1, 2025
e9355d7
feat: add scroll to selected item functionality in TreeView component
AbhishekA1509 Jul 2, 2025
6cb2706
Merge branch 'develop' of https://github.com/devtron-labs/devtron-fe-…
AbhishekA1509 Jul 2, 2025
5e6c67d
feat: add defaultExpandedMap prop to TreeView and update state initia…
AbhishekA1509 Jul 2, 2025
d31006e
feat: remove isExpanded property from K8SObjectBaseType interface
AbhishekA1509 Jul 2, 2025
443d6e4
feat: add generic support for DataAttributeType in TreeView component…
AbhishekA1509 Jul 3, 2025
494c363
Merge branch 'release-candidate-v0.39.0' of https://github.com/devtro…
AbhishekA1509 Jul 3, 2025
f5469f0
feat: enhance TreeView component with controlled state management and…
AbhishekA1509 Jul 3, 2025
841056a
fix: handle undefined dataAttributes in TreeView component to prevent…
AbhishekA1509 Jul 3, 2025
4b439de
feat: enhance TreeView component with improved type definitions and r…
AbhishekA1509 Jul 4, 2025
761fc26
fix: simplify useEffect condition for setting expanded map in TreeVie…
AbhishekA1509 Jul 4, 2025
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
18 changes: 3 additions & 15 deletions src/Common/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
* limitations under the License.
*/

import { cloneElement, useState } from 'react'
import { cloneElement } from 'react'
import TippyJS from '@tippyjs/react'

import { SUB_PIXEL_ERROR } from './constants'
import ShortcutKeyComboTooltipContent from './ShortcutKeyComboTooltipContent'
import { TooltipProps } from './types'
import useIsTextTruncated from './UseIsTextTruncated'

import './styles.scss'

Expand All @@ -32,19 +32,7 @@ const Tooltip = ({
children: child,
...rest
}: TooltipProps) => {
const [isTextTruncated, setIsTextTruncated] = useState(false)

const handleMouseEnterEvent: React.MouseEventHandler = (event) => {
const { currentTarget: node } = event
const isTextOverflowing =
node.scrollWidth > node.clientWidth + SUB_PIXEL_ERROR ||
node.scrollHeight > node.clientHeight + SUB_PIXEL_ERROR
if (isTextOverflowing && !isTextTruncated) {
setIsTextTruncated(true)
} else if (!isTextOverflowing && isTextTruncated) {
setIsTextTruncated(false)
}
}
const { isTextTruncated, handleMouseEnterEvent } = useIsTextTruncated()

const showTooltipWhenShortcutKeyComboProvided =
!!shortcutKeyCombo && (alwaysShowTippyOnHover === undefined || alwaysShowTippyOnHover)
Expand Down
26 changes: 26 additions & 0 deletions src/Common/Tooltip/UseIsTextTruncated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useState } from 'react'

import { SUB_PIXEL_ERROR } from './constants'

const useIsTextTruncated = () => {
const [isTextTruncated, setIsTextTruncated] = useState(false)

const handleMouseEnterEvent: React.MouseEventHandler = (event) => {
const { currentTarget: node } = event
const isTextOverflowing =
node.scrollWidth > node.clientWidth + SUB_PIXEL_ERROR ||
node.scrollHeight > node.clientHeight + SUB_PIXEL_ERROR
if (isTextOverflowing && !isTextTruncated) {
setIsTextTruncated(true)
} else if (!isTextOverflowing && isTextTruncated) {
setIsTextTruncated(false)
}
}

return {
isTextTruncated,
handleMouseEnterEvent,
}
}

export default useIsTextTruncated
1 change: 1 addition & 0 deletions src/Common/Tooltip/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
export { TOOLTIP_CONTENTS } from './constants'
export { default as Tooltip } from './Tooltip'
export type { TooltipProps } from './types'
export { default as useIsTextTruncated } from './UseIsTextTruncated'
1 change: 0 additions & 1 deletion src/Pages/ResourceBrowser/ResourceBrowser.Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export interface ApiResourceType {

export interface K8SObjectBaseType {
name: string
isExpanded: boolean
}

interface K8sRequestResourceIdentifierType {
Expand Down
62 changes: 3 additions & 59 deletions src/Shared/Components/ActionMenu/ActionMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ import { LegacyRef, MouseEvent, Ref } from 'react'
import { Link } from 'react-router-dom'

import { Tooltip } from '@Common/Tooltip'
import { ComponentSizeType } from '@Shared/constants'

import { Button, ButtonProps, ButtonVariantType } from '../Button'
import { Icon } from '../Icon'
import { NumbersCount } from '../NumbersCount'
import { getTooltipProps } from '../SelectPicker/common'
import { DTSwitch, DTSwitchProps } from '../Switch'
import { ActionMenuItemProps, ActionMenuItemType } from './types'
import { TrailingItem } from '../TrailingItem'
import { ActionMenuItemProps } from './types'

const COMMON_ACTION_MENU_ITEM_CLASS = 'w-100 flex left top dc__gap-8 py-6 px-8'

Expand Down Expand Up @@ -48,24 +45,6 @@ export const ActionMenuItem = <T extends string | number>({
onClick(item, e)
}

const handleTrailingSwitchChange =
({ type: trailingItemType, config }: ActionMenuItemType<T>['trailingItem']): DTSwitchProps['onChange'] =>
(e) => {
if (trailingItemType === 'switch') {
e.stopPropagation()
config.onChange(e)
}
}

const handleTrailingButtonClick =
({ type: trailingItemType, config }: ActionMenuItemType<T>['trailingItem']): ButtonProps['onClick'] =>
(e) => {
e.stopPropagation()
if (trailingItemType === 'button' && config.onClick) {
config.onClick(e)
}
}

// RENDERERS
const renderIcon = (iconProps: typeof startIcon) =>
iconProps && (
Expand All @@ -79,42 +58,7 @@ export const ActionMenuItem = <T extends string | number>({
return null
}

const { type: trailingItemType, config } = trailingItem

switch (trailingItemType) {
case 'icon':
return renderIcon(config)
case 'text': {
const { value, icon } = config
return (
<span className="flex dc__gap-2 mt-2">
<span className="fs-12 lh-1-5 fw-4 cn-7">{value}</span>
{icon && <Icon name={icon.name} color={icon.color || (isNegativeType ? 'R500' : 'N700')} />}
</span>
)
}
case 'counter':
return <NumbersCount count={config.value} />
case 'switch':
return (
<DTSwitch
{...config}
onChange={handleTrailingSwitchChange(trailingItem)}
size={ComponentSizeType.small}
/>
)
case 'button':
return (
<Button
{...(config as ButtonProps)}
onClick={handleTrailingButtonClick(trailingItem)}
variant={ButtonVariantType.borderLess}
size={ComponentSizeType.xxs}
/>
)
default:
return null
}
return <TrailingItem {...trailingItem} variant={type} />
}

const renderContent = () => (
Expand Down
51 changes: 2 additions & 49 deletions src/Shared/Components/ActionMenu/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { LegacyRef, MouseEvent, ReactElement, Ref } from 'react'
import { LegacyRef, MouseEvent, Ref } from 'react'
import { LinkProps } from 'react-router-dom'

import { OmitNever } from '@Shared/types'

import { ButtonProps } from '../Button'
import { IconsProps } from '../Icon'
import { NumbersCountProps } from '../NumbersCount'
import { PopoverProps, UsePopoverProps } from '../Popover'
import { SelectPickerOptionType, SelectPickerProps } from '../SelectPicker'
import { DTSwitchProps } from '../Switch'
import { ActionMenuItemIconType, TrailingItemType } from '../TrailingItem'

type ConditionalActionMenuComponentType =
| {
Expand All @@ -32,48 +27,6 @@ type ConditionalActionMenuComponentType =
href?: never
}

type ActionMenuItemIconType = Pick<IconsProps, 'name'> & {
/** @default 'N800' */
color?: IconsProps['color']
}

type TrailingItemType =
| {
type: 'icon'
config: ActionMenuItemIconType
}
| {
type: 'text'
config: {
value: string
icon?: ActionMenuItemIconType
}
}
| {
type: 'counter'
config: {
value: NumbersCountProps['count']
}
}
| {
type: 'switch'
config: Pick<
DTSwitchProps,
| 'ariaLabel'
| 'isChecked'
| 'indeterminate'
| 'isDisabled'
| 'isLoading'
| 'name'
| 'onChange'
| 'tooltipContent'
>
}
| {
type: 'button'
config: OmitNever<Omit<Extract<ButtonProps, { icon: ReactElement }>, 'size' | 'variant'>>
}

export type ActionMenuItemType<T extends string | number = string | number> = Omit<
SelectPickerOptionType,
'label' | 'value' | 'endIcon' | 'startIcon'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const renderWithTippy = (tippyProps: TippyProps) => (children: React.ReactElemen
</Tippy>
)

/**
* @deprecated - Please use `TreeView` component instead.
*/
export const CollapsibleList = <TabType extends TabOptions>({
config,
tabType,
Expand Down
Loading