Skip to content
Draft
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
2 changes: 2 additions & 0 deletions assets/design-system/src/components/table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ function Table({
string | null
>(null)

useEffect(() => setFixedGridTemplateColumns(null), [columns.length])

const { rows: tableRows } = table.getRowModel()
const getItemKey = useCallback<
Parameters<typeof useVirtualizer>[0]['getItemKey']
Expand Down
222 changes: 0 additions & 222 deletions assets/src/components/ai/agent-runs/AgentRunFixButton.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,71 @@ import {
} from 'components/utils/contentEditableChips'
import {
forwardRef,
ReactNode,
RefObject,
useEffect,
useLayoutEffect,
useState,
} from 'react'
import { MentionKind } from './mentionTypes'
import {
hasVulnerabilityChipTooltip,
VulnerabilityChipTooltipLabel,
vulnerabilityChipTooltipText,
} from './VulnerabilityChipTooltipLabel'

const SKILL_SELECTOR = `[${CHIP_DATA_ATTR}="true"][${CHIP_TAG_ATTR}="${MentionKind.Skill}"]`
const PLRL_CHIP_SELECTOR = [MentionKind.Skill, MentionKind.Vulnerability]
.map((kind) => `[${CHIP_DATA_ATTR}="true"][${CHIP_TAG_ATTR}="${kind}"]`)
.join(',')
const DESC_ATTR = `${CHIP_ATTR_PREFIX}description`
const NAME_ATTR = `${CHIP_ATTR_PREFIX}item-name`
const TITLE_ATTR = `${CHIP_ATTR_PREFIX}title`

const TIP_ON_INPUT_STYLE = {
maxWidth: 500,
overflowWrap: 'break-word' as const,
zIndex: 11_000,
}

/** Skill chip + tooltip label, resolved from pointer event target. */
function skillHintFromTarget(
function chipHintFromTarget(
eventTarget: EventTarget | null
): { chip: HTMLElement; label: string } | null {
): { chip: HTMLElement; label: ReactNode; hintKey: string } | null {
if (!(eventTarget instanceof Element)) return null
const chip = eventTarget.closest(SKILL_SELECTOR)
const chip = eventTarget.closest(PLRL_CHIP_SELECTOR)
if (!(chip instanceof HTMLElement)) return null
const label =
chip.getAttribute(DESC_ATTR)?.trim() ||
chip.getAttribute(NAME_ATTR)?.trim() ||
null
return label ? { chip, label } : null

const tag = chip.getAttribute(CHIP_TAG_ATTR)
const itemId = chip.getAttribute(`${CHIP_ATTR_PREFIX}item-id`) ?? ''
const description = chip.getAttribute(DESC_ATTR)?.trim()
const name = chip.getAttribute(NAME_ATTR)?.trim()
const title = chip.getAttribute(TITLE_ATTR)?.trim()

switch (tag) {
case MentionKind.Skill: {
const label = description || name
if (!label) return null
return {
chip,
label,
hintKey: `${tag}|${itemId}|${description ?? ''}|${name ?? ''}`,
}
}
case MentionKind.Vulnerability: {
if (!hasVulnerabilityChipTooltip({ title, description })) return null
return {
chip,
label: (
<VulnerabilityChipTooltipLabel
title={title}
description={description}
/>
),
hintKey: `${tag}|${itemId}|${title ?? ''}|${description ?? ''}`,
}
}
default:
return null
}
}

const ChipAnchorStub = forwardRef<HTMLSpanElement, { chip: HTMLElement }>(
Expand Down Expand Up @@ -81,19 +117,21 @@ export function EditableSkillChipTooltip({
}: {
containerRef: RefObject<HTMLElement | null>
}) {
const [hint, setHint] = useState<{ chip: HTMLElement; label: string } | null>(
null
)
const [hint, setHint] = useState<{
chip: HTMLElement
label: ReactNode
hintKey: string
} | null>(null)

useEffect(() => {
const editorRoot = containerRef.current
if (!editorRoot) return

const onPointerMove = (event: PointerEvent) => {
const next = skillHintFromTarget(event.target)
const next = chipHintFromTarget(event.target)
setHint((current) => {
if (!next) return null
return current?.chip === next.chip && current.label === next.label
return current?.chip === next.chip && current.hintKey === next.hintKey
? current
: next
})
Expand All @@ -111,13 +149,24 @@ export function EditableSkillChipTooltip({

if (!hint) return null

const textValue =
hint.chip.getAttribute(CHIP_TAG_ATTR) === MentionKind.Vulnerability
? vulnerabilityChipTooltipText({
title: hint.chip.getAttribute(TITLE_ATTR) ?? undefined,
description: hint.chip.getAttribute(DESC_ATTR) ?? undefined,
})
: typeof hint.label === 'string'
? hint.label
: undefined

return (
<Tooltip
key={hint.chip.getAttribute(`${CHIP_ATTR_PREFIX}item-id`) ?? hint.label}
key={hint.hintKey}
dismissable={false}
displayOn="manual"
manualOpen
label={hint.label}
textValue={textValue}
placement="top"
style={TIP_ON_INPUT_STYLE}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ClusterIcon,
GitPullIcon,
StackIcon,
WarningShieldIcon,
WorkbenchIcon,
} from '@pluralsh/design-system'
import { ReactNode, useEffect, useRef } from 'react'
Expand All @@ -17,6 +18,7 @@ const itemToIcon: Record<MentionKind, ReactNode> = {
[MentionKind.Service]: <GitPullIcon size={14} />,
[MentionKind.Stack]: <StackIcon size={14} />,
[MentionKind.Skill]: <WorkbenchIcon size={14} />,
[MentionKind.Vulnerability]: <WarningShieldIcon size={14} />,
}

function subtitleForItem(item: ChipAttrs) {
Expand All @@ -29,6 +31,8 @@ function subtitleForItem(item: ChipAttrs) {
return item.type ? stackTypeLabel(item.type as StackType) : undefined
case MentionKind.Skill:
return item.description
case MentionKind.Vulnerability:
return item.resource ?? item['vuln-id'] ?? undefined
}
}

Expand Down
Loading
Loading