Skip to content

Commit

Permalink
feat: Improve segment override UI (#4633)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyle-ssg authored Oct 1, 2024
1 parent 364ad3f commit a265d74
Show file tree
Hide file tree
Showing 13 changed files with 538 additions and 334 deletions.
6 changes: 4 additions & 2 deletions frontend/web/components/ActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ type ActionButtonType = {
const ActionButton: FC<ActionButtonType> = ({ onClick, ...rest }) => {
return (
<Button
className={classNames('btn btn-with-icon btn-sm')}
className={classNames('btn btn-with-icon btn-xs')}
data-test={rest['data-test']}
onClick={(e) => {
e.stopPropagation()
onClick()
}}
>
<Icon name='more-vertical' width={16} fill='#656D7B' />
<div className='pointer-events-none'>
<Icon name='more-vertical' width={16} fill='#656D7B' />
</div>
</Button>
)
}
Expand Down
4 changes: 3 additions & 1 deletion frontend/web/components/Highlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ class Highlight extends React.Component {
return (
<div className={this.state.expandable ? 'expandable' : ''}>
<pre
className='mb-2'
style={{
...(this.props.style || {}),
height:
Expand Down Expand Up @@ -173,8 +174,9 @@ class Highlight extends React.Component {
/>
</pre>
{this.state.expandable && (
<div className='expand text-center mt-2'>
<div className='expand text-center mb-2'>
<Button
className='h-auto'
theme='text'
onClick={() => this.setState({ expanded: !this.state.expanded })}
>
Expand Down
1 change: 1 addition & 0 deletions frontend/web/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type IconName =
| 'arrow-left'
| 'file-text'
| 'copy'
| 'paste'
| 'copy-outlined'
| 'trash-2'
| 'setting'
Expand Down
157 changes: 157 additions & 0 deletions frontend/web/components/SegmentOverrideActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { FC, useCallback, useLayoutEffect, useRef, useState } from 'react'
import classNames from 'classnames'

import useOutsideClick from 'common/useOutsideClick'
import Utils from 'common/utils/utils'
import Constants from 'common/constants'
import Permission from 'common/providers/Permission'
import Button from './base/forms/Button'
import Icon from './Icon'
import ActionButton from './ActionButton'

interface SegmentOverrideActionProps {
canRemove: boolean
onRemove: () => void
onEdit: () => void
onCopyValue: () => void
canEdit: boolean
canCopyValue: boolean
}

type ActionType = 'edit' | 'remove'

function calculateListPosition(
btnEl: HTMLElement,
listEl: HTMLElement,
): { top: number; left: number } {
const top = btnEl.offsetTop + btnEl.offsetHeight
const left = btnEl.offsetLeft + btnEl.offsetWidth - listEl.offsetWidth
return { left, top }
}

export const SegmentOverrideAction: FC<SegmentOverrideActionProps> = ({
canCopyValue,
canEdit,
canRemove,
onCopyValue,
onEdit,
onRemove,
}) => {
const [isOpen, setIsOpen] = useState<boolean>(false)

const btnRef = useRef<HTMLDivElement>(null)
const listRef = useRef<HTMLDivElement>(null)

const close = useCallback(() => setIsOpen(false), [])

const handleOutsideClick = useCallback(
() => isOpen && close(),
[close, isOpen],
)

const handleActionClick = useCallback(
(action: ActionType) => {
if (action === 'edit') {
onEdit()
} else if (action === 'remove') {
onRemove()
} else if (action === 'copy') {
onCopyValue()
}
close()
},
[close, onRemove, onCopyValue, onEdit],
)

useOutsideClick(listRef, handleOutsideClick)

useLayoutEffect(() => {
if (!isOpen || !listRef.current || !btnRef.current) return
const listPosition = calculateListPosition(btnRef.current, listRef.current)
listRef.current.style.top = `${listPosition.top}px`
listRef.current.style.left = `${listPosition.left}px`
}, [isOpen])

if (!canEdit && !!canRemove) {
return (
<Button onClick={onRemove} size='small' className='btn-with-icon'>
<span>Remove Override</span>
</Button>
)
}

if (!!canEdit && !canRemove) {
return (
<Button onClick={() => handleActionClick('edit')} size='small'>
View Segment
</Button>
)
}

if (!canEdit && !canRemove) {
return null
}

return (
<div className='position-relative'>
<div ref={btnRef}>
<ActionButton
onClick={() => {
setIsOpen(true)
}}
/>
</div>

{isOpen && (
<div
onMouseDown={(e) => {
e.stopPropagation()
}}
onClick={(e) => e.stopPropagation()}
ref={listRef}
className='feature-action__list'
>
{!!canEdit && (
<div
className='feature-action__item'
onClick={(e) => {
e.stopPropagation()
handleActionClick('edit')
}}
>
<Icon name='eye' width={18} fill='#9DA4AE' />
<span>View segment</span>
</div>
)}
{!!canCopyValue && (
<div
className='feature-action__item'
onClick={(e) => {
e.stopPropagation()
handleActionClick('copy')
}}
>
<Icon name='copy' width={18} fill='#9DA4AE' />
<span>Set value from environment</span>
</div>
)}

{!!canRemove && (
<div
className='feature-action__item'
onClick={(e) => {
e.stopPropagation()
handleActionClick('remove')
}}
>
<Icon name='trash-2' width={18} fill='#9DA4AE' />
<span>Remove Override</span>
</div>
)}
</div>
)}
</div>
)
}

export default SegmentOverrideAction
Loading

0 comments on commit a265d74

Please sign in to comment.