Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9e03d9b
feat: remove LogoutCard, add ProfileMenu, update ThemeSwitcher
RohitRaj011 May 28, 2025
d733252
feat: PageHeader - adjust gap size
RohitRaj011 May 28, 2025
e9cb532
feat: ActionMenu - remove footer bg, HelpButton - add footer bg
RohitRaj011 May 28, 2025
2a12f97
Merge branch 'develop' of github.com:devtron-labs/devtron-fe-common-l…
RohitRaj011 May 28, 2025
a8de0e0
feat: ActionMenu - add support for trailing item
RohitRaj011 May 28, 2025
52588c9
feat: HelpButton - open documentation item in side panel
RohitRaj011 May 28, 2025
e0e2b2a
fix: ProfileMenu - closePopover on ThemeSwitch click, on logout
RohitRaj011 May 28, 2025
f06acb7
fix: CodeEditor - adjust search container width and margin
RohitRaj011 May 28, 2025
37bcb88
fix: Constants - correct DOCUMENTATION_VERSION path
RohitRaj011 May 29, 2025
7629842
fix: Button - add inline-block class to button wrapper for better layout
RohitRaj011 May 29, 2025
5671790
feat: Button, DocLink - add fontWeight prop and update related styles
RohitRaj011 May 29, 2025
5e871a0
fix: CiPipelineSourceConfig - update class names for better text trun…
RohitRaj011 May 29, 2025
7a91d91
feat: ActionMenu - add support for trailing item - button
RohitRaj011 May 29, 2025
5b37674
fix: Button - simplify tooltipProps typing and improve type safety
RohitRaj011 May 29, 2025
7bc7b72
feat: DevtronLicenseCard - update contact support button to use ancho…
RohitRaj011 May 29, 2025
d6b01a8
feat: Popover, ActionMenu, ProfileMenu - modify popover implementatio…
RohitRaj011 May 29, 2025
dc308fd
feat: Constants - add LICENSE_DASHBOARD_HOME_PAGE constant for licens…
RohitRaj011 May 29, 2025
aae3375
feat: DocLink - add startIcon prop and update fullWidth default value…
RohitRaj011 May 30, 2025
50a2ca6
feat: SidePanelConfig - add reinitialize flag and update docLink type…
RohitRaj011 May 30, 2025
34db6ac
feat: Constants, ActionMenu, ProfileMenu - add LOGIN URL constant; up…
RohitRaj011 May 30, 2025
42eb207
Merge branch 'develop' of github.com:devtron-labs/devtron-fe-common-l…
RohitRaj011 May 30, 2025
13ddf40
chore(version): bump to 1.14.2-pre-2
RohitRaj011 May 30, 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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devtron-labs/devtron-fe-common-lib",
"version": "1.14.2-pre-1",
"version": "1.14.2-pre-2",
"description": "Supporting common component library",
"type": "module",
"main": "dist/index.js",
Expand Down
4 changes: 3 additions & 1 deletion src/Common/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ export const Host = window?.__ORCHESTRATOR_ROOT__ ?? '/orchestrator'

export const DOCUMENTATION_HOME_PAGE = 'https://docs.devtron.ai'
export const DEVTRON_HOME_PAGE = 'https://devtron.ai/'
export const DOCUMENTATION_VERSION = '/v/v0.7'
export const DOCUMENTATION_VERSION = '/devtron/v0.7'
export const DISCORD_LINK = 'https://discord.devtron.ai/'
export const DEFAULT_JSON_SCHEMA_URI = 'https://json-schema.org/draft/2020-12/schema'
export const LICENSE_DASHBOARD_HOME_PAGE = 'https://license.devtron.ai/dashboard'
Comment thread
AbhishekA1509 marked this conversation as resolved.

export const PATTERNS = {
STRING: /^[a-zA-Z0-9_]+$/,
Expand All @@ -47,6 +48,7 @@ export const PATTERNS = {
const GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP = '/global-config/templates/devtron-apps'

export const URLS = {
LOGIN: '/login',
LOGIN_SSO: '/login/sso',
PERMISSION_GROUPS: '/global-config/auth/groups',
APP: '/app',
Expand Down
14 changes: 6 additions & 8 deletions src/Shared/Components/ActionMenu/ActionMenu.component.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { MutableRefObject } from 'react'

import { CustomInput } from '../CustomInput'
import { Popover } from '../Popover'
import { SelectPickerMenuListFooter } from '../SelectPicker/common'
import { ActionMenuItem } from './ActionMenuItem'
import { ActionMenuItemType, ActionMenuProps } from './types'
import { ActionMenuItemProps, ActionMenuProps } from './types'
import { useActionMenu } from './useActionMenu.hook'

import './actionMenu.scss'
Expand Down Expand Up @@ -51,8 +49,8 @@ export const ActionMenu = <T extends string | number = string | number>({
// HANDLERS
const handleOptionMouseEnter = (index: number) => () => setFocusedIndex(index)

const handleOptionOnClick = (item: ActionMenuItemType<T>) => () => {
onClick(item)
const handleOptionOnClick: ActionMenuItemProps<T>['onClick'] = (item, e) => {
onClick(item, e)
closePopover()
}

Expand Down Expand Up @@ -82,7 +80,7 @@ export const ActionMenu = <T extends string | number = string | number>({
</div>
)}
<ul
ref={scrollableRef as MutableRefObject<HTMLUListElement>}
ref={scrollableRef}
role="menu"
className="action-menu m-0 p-0 flex-grow-1 dc__overflow-auto dc__overscroll-none"
>
Expand Down Expand Up @@ -114,7 +112,7 @@ export const ActionMenu = <T extends string | number = string | number>({
itemRef={itemsRef.current[index]}
isFocused={index === focusedIndex}
onMouseEnter={handleOptionMouseEnter(index)}
onClick={handleOptionOnClick(item)}
onClick={handleOptionOnClick}
disableDescriptionEllipsis={disableDescriptionEllipsis}
/>
)
Expand All @@ -132,7 +130,7 @@ export const ActionMenu = <T extends string | number = string | number>({
)}
</ul>
{footerConfig && (
<div className="bg__menu--secondary border__secondary-translucent--top">
<div className="border__secondary-translucent--top">
<SelectPickerMenuListFooter menuListFooterConfig={footerConfig} />
</div>
)}
Expand Down
89 changes: 78 additions & 11 deletions src/Shared/Components/ActionMenu/ActionMenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { LegacyRef, Ref } from 'react'
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 { ActionMenuItemProps } from './types'
import { DTSwitch, DTSwitchProps } from '../Switch'
import { ActionMenuItemProps, ActionMenuItemType } from './types'

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

export const ActionMenuItem = <T extends string | number>({
item,
Expand All @@ -22,7 +26,7 @@ export const ActionMenuItem = <T extends string | number>({
description,
label,
startIcon,
endIcon,
trailingItem,
tooltipProps,
type = 'neutral',
isDisabled,
Expand All @@ -40,22 +44,83 @@ export const ActionMenuItem = <T extends string | number>({
const isNegativeType = type === 'negative'

// HANDLERS
const handleClick = () => {
onClick(item)
const handleClick = (e: MouseEvent<HTMLAnchorElement> | MouseEvent<HTMLButtonElement>) => {
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 && (
<div className="mt-2 flex dc__no-shrink">
<span className="mt-2 flex dc__no-shrink">
<Icon {...iconProps} color={iconProps.color || (isNegativeType ? 'R500' : 'N800')} />
</div>
</span>
)

const renderTrailingItem = () => {
if (!trailingItem) {
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
}
}

const renderContent = () => (
<>
{renderIcon(startIcon)}
<span>
<span className="flex-grow-1">
<Tooltip content={label} placement="right">
<span className={`m-0 fs-13 fw-4 lh-20 dc__truncate ${isNegativeType ? 'cr-5' : 'cn-9'}`}>
{label}
Expand All @@ -72,7 +137,7 @@ export const ActionMenuItem = <T extends string | number>({
description
))}
</span>
{renderIcon(endIcon)}
{renderTrailingItem()}
</>
)

Expand All @@ -86,6 +151,7 @@ export const ActionMenuItem = <T extends string | number>({
href={item.href}
target="_blank"
rel="noreferrer"
onClick={handleClick}
>
{renderContent()}
</a>
Expand All @@ -96,6 +162,7 @@ export const ActionMenuItem = <T extends string | number>({
ref={itemRef as Ref<HTMLAnchorElement>}
className={COMMON_ACTION_MENU_ITEM_CLASS}
to={item.to}
onClick={handleClick}
>
{renderContent()}
</Link>
Expand All @@ -107,6 +174,7 @@ export const ActionMenuItem = <T extends string | number>({
ref={itemRef as LegacyRef<HTMLButtonElement>}
type="button"
className={`dc__transparent ${COMMON_ACTION_MENU_ITEM_CLASS}`}
onClick={handleClick}
>
{renderContent()}
</button>
Expand All @@ -124,7 +192,6 @@ export const ActionMenuItem = <T extends string | number>({
tabIndex={-1}
// Intentionally added margin to the left and right to have the gap on the edges of the options
className={`action-menu__option br-4 mr-4 ml-4 ${isDisabled ? 'dc__disabled' : 'cursor'} ${isNegativeType ? 'dc__hover-r50' : 'dc__hover-n50'} ${isFocused ? `action-menu__option--focused${isNegativeType ? '-negative' : ''}` : ''}`}
onClick={!isDisabled ? handleClick : undefined}
aria-disabled={isDisabled}
>
{renderComponent()}
Expand Down
50 changes: 46 additions & 4 deletions src/Shared/Components/ActionMenu/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { LegacyRef, Ref } from 'react'
import { LegacyRef, MouseEvent, ReactElement, 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'

type ConditionalActionMenuComponentType =
| {
Expand Down Expand Up @@ -32,6 +37,43 @@ type ActionMenuItemIconType = Pick<IconsProps, 'name'> & {
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 All @@ -49,8 +91,8 @@ export type ActionMenuItemType<T extends string | number = string | number> = Om
type?: 'neutral' | 'negative'
/** Defines the icon to be displayed at the start of the menu item. */
startIcon?: ActionMenuItemIconType
/** Defines the icon to be displayed at the end of the menu item. */
endIcon?: ActionMenuItemIconType
/** Defines the item to be displayed at the end of the menu item. */
trailingItem?: TrailingItemType
} & ConditionalActionMenuComponentType

export type ActionMenuOptionType<T extends string | number> = {
Expand Down Expand Up @@ -85,7 +127,7 @@ export type ActionMenuProps<T extends string | number = string | number> = UseAc
* Callback function triggered when an item is clicked.
* @param item - The selected item.
*/
onClick: (item: ActionMenuItemType<T>) => void
onClick: (item: ActionMenuItemType<T>, e: MouseEvent<HTMLAnchorElement> | MouseEvent<HTMLButtonElement>) => void
/**
* Config for the footer at the bottom of action menu list. It is sticky by default
*/
Expand Down
12 changes: 4 additions & 8 deletions src/Shared/Components/ActionMenu/useActionMenu.hook.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeEvent, createRef, RefObject, useEffect, useMemo, useRef, useState } from 'react'
import { ChangeEvent, createRef, RefObject, useEffect, useRef, useState } from 'react'

import { usePopover, UsePopoverProps } from '../Popover'
import { UseActionMenuProps } from './types'
Expand All @@ -17,13 +17,9 @@ export const useActionMenu = <T extends string | number>({
const [focusedIndex, setFocusedIndex] = useState(-1)
const [searchTerm, setSearchTerm] = useState('')

// MEMOIZED CONSTANTS
const filteredOptions = useMemo(
() => (isSearchable ? filterActionMenuOptions(options, searchTerm) : options),
[isSearchable, JSON.stringify(options), searchTerm],
)

const flatOptions = useMemo(() => getActionMenuFlatOptions(filteredOptions), [filteredOptions])
// CONSTANTS
const filteredOptions = isSearchable ? filterActionMenuOptions(options, searchTerm) : options
const flatOptions = getActionMenuFlatOptions(filteredOptions)

// REFS
const itemsRef = useRef<RefObject<HTMLAnchorElement | HTMLButtonElement>[]>(
Expand Down
Loading