diff --git a/components/KernDropdown.tsx b/components/KernDropdown.tsx index b1a0541..6975432 100644 --- a/components/KernDropdown.tsx +++ b/components/KernDropdown.tsx @@ -61,7 +61,7 @@ export default function KernDropdown(props: KernDropdownProps) { setDropdownCaptions(prepareOptions); setSearchIndexes(null); } - }, [props.options, searchText, selectedCheckboxes, props.hasSearchBar, props.hasCheckboxes, props.selectedCheckboxes, props.hasSelectAll, props.valuePropertyPath]); + }, [props.options, searchText, props.hasSearchBar, props.hasCheckboxes, props.valuePropertyPath, props.selectedCheckboxes, props.hasSelectAll]); useEffect(() => { if (!props.disabledOptions || !props.options) return; @@ -94,8 +94,7 @@ export default function KernDropdown(props: KernDropdownProps) { return { "maxHeight": `${maxHeight}rem`, "overflowY": "auto" }; }, [props.scrollAfterNOptions]); - function setOptionsWithCheckboxes(options: any[]) { - if (selectedCheckboxes.length > 0) return; + const setOptionsWithCheckboxes = useCallback((options: any[]) => { const newSelectedCheckboxes = options.map((option: any, index: number) => { return { name: option, @@ -105,12 +104,12 @@ export default function KernDropdown(props: KernDropdownProps) { if (props.hasSelectAll) { newSelectedCheckboxes.push({ name: SELECT_ALL, - checked: false + checked: newSelectedCheckboxes.every((checkbox) => checkbox.checked) }); } setSelectedCheckboxes(newSelectedCheckboxes); setDropdownCaptions(newSelectedCheckboxes.map((option: any) => option.name)); - } + }, [props.hasSelectAll, props.selectedCheckboxes]); function toggleDropdown() { if (isDisabled && !props.hasCheckboxes) return; // if the dropdown has checkboxes, it shouldn't be disabled because the user can still select options @@ -118,12 +117,14 @@ export default function KernDropdown(props: KernDropdownProps) { setIsOpen(!isOpen); } - function handleSelectedCheckboxes(option: string, index: number, e: any) { + const handleSelectedCheckboxes = useCallback((option: string, index: number, e: any) => { let newSelectedCheckboxes = [...selectedCheckboxes]; if (option == SELECT_ALL) { newSelectedCheckboxes.forEach((checkbox) => { checkbox.checked = e.target.checked; }); + const allSelected = newSelectedCheckboxes.every((checkbox) => checkbox.checked); + newSelectedCheckboxes[newSelectedCheckboxes.length - 1].checked = allSelected; } else { const lastIdx = newSelectedCheckboxes.length - 1; if (props.hasSelectAll && newSelectedCheckboxes[lastIdx].checked) { @@ -136,7 +137,7 @@ export default function KernDropdown(props: KernDropdownProps) { newSelectedCheckboxes = newSelectedCheckboxes.filter((checkbox) => checkbox.name != SELECT_ALL); } props.selectedOption(newSelectedCheckboxes); - } + }, [selectedCheckboxes, props.hasSelectAll]); function handleSelectedCheckboxesThreeStates(index: number) { const optionSave = { ...props.options[index] }; @@ -161,8 +162,7 @@ export default function KernDropdown(props: KernDropdownProps) { setSavedIndex(index); } - - function performActionOnClick(option: string, index: number) { + const performActionOnClick = useCallback((option: string, index: number) => { if (props.hasCheckboxes) { handleSelectedCheckboxes(option, index, { target: { checked: !selectedCheckboxes[index].checked } }); return; @@ -180,8 +180,9 @@ export default function KernDropdown(props: KernDropdownProps) { props.selectedOption(props.options[index]); } setIsOpen(false); + setSelectedCheckboxes([]); } - } + }, [props, selectedCheckboxes, searchIndexes]); return ( @@ -212,8 +213,8 @@ export default function KernDropdown(props: KernDropdownProps) { ) : ( -
+ disabled={isDisabled}> +
{props.buttonPrefixIcon} {!props.hasCheckboxesThreeStates && props.buttonName}
@@ -266,7 +267,7 @@ export default function KernDropdown(props: KernDropdownProps) { if (!props.optionsHaveHoverBox) return; setHoverBoxPosition(null); }}> - {props.hasCheckboxes && handleSelectedCheckboxes(option, index, e)} />} {props.hasCheckboxesThreeStates &&
diff --git a/components/kern-icons/icons.ts b/components/kern-icons/icons.ts index 06b17c2..b5636eb 100644 --- a/components/kern-icons/icons.ts +++ b/components/kern-icons/icons.ts @@ -1,5 +1,5 @@ import { memo } from 'react'; -import { IconActivity, IconAdjustments, IconAdjustmentsAlt, IconAdjustmentsOff, IconAlertCircle, IconAlertTriangle, IconAlertTriangleFilled, IconAngle, IconApi, IconArchive, IconArrowAutofitDown, IconArrowCurveRight, IconArrowDown, IconArrowLeft, IconArrowNarrowLeft, IconArrowNarrowRight, IconArrowRight, IconArrowsRandom, IconArrowsSort, IconArrowUp, IconArrowUpRight, IconAssembly, IconBallpen, IconBallpenOff, IconBell, IconBolt, IconBottle, IconBox, IconBoxOff, IconBrandGithub, IconBrandOpenai, IconBrandPython, IconBulb, IconBulldozer, IconCamera, IconCategoryPlus, IconCell, IconChartBubble, IconChartCircles, IconChartDots3, IconChartLine, IconChartPie, IconCheck, IconChecks, IconChevronCompactLeft, IconChevronCompactRight, IconChevronDown, IconChevronLeft, IconChevronRight, IconChevronUp, IconCircle, IconCircleCheck, IconCircleCheckFilled, IconCircleMinus, IconCirclePlus, IconClick, IconClipboard, IconClipboardCheck, IconClipboardOff, IconClock, IconCode, IconCodePlus, IconColorPicker, IconColumns, IconColumns1, IconColumns2, IconColumns3, IconCopy, IconCrown, IconCrownOff, IconDatabase, IconDatabasePlus, IconDeviceFloppy, IconDots, IconDotsVertical, IconDownload, IconEdit, IconEngine, IconExclamationCircle, IconExclamationMark, IconExternalLink, IconEye, IconEyeCancel, IconEyeCheck, IconEyeOff, IconFile, IconFileDownload, IconFileImport, IconFileInfo, IconFilePencil, IconFiles, IconFileText, IconFileUpload, IconFilter, IconFilterOff, IconFishHook, IconFolderBolt, IconGitCommit, IconGripVertical, IconHandClick, IconHeading, IconHelp, IconHexagons, IconHierarchy, IconHierarchy3, IconHistory, IconHome, IconHourglass, IconHourglassEmpty, IconInfoCircle, IconInfoCircleFilled, IconInfoSquare, IconLayoutList, IconLayoutNavbarCollapse, IconLayoutSidebar, IconLetterGSmall, IconLink, IconList, IconLoader, IconLoader2, IconLockAccess, IconMap, IconMaximize, IconMessageCircle, IconMinus, IconMessageCircleSearch, IconMessages, IconMinimize, IconMoustache, IconNews, IconNotes, IconPencil, IconPlayCardStar, IconPlayerPlay, IconPlayerPlayFilled, IconPlus, IconPoint, IconPointerOff, IconPointerSearch, IconPointFilled, IconQuestionMark, IconRecycle, IconRefresh, IconRefreshAlert, IconResize, IconRobot, IconRotate, IconScissors, IconScreenshot, IconSearch, IconSend, IconSettings, IconShare, IconShieldCheckFilled, IconShieldFilled, IconSquare, IconSquareCheck, IconStar, IconTag, IconTemplate, IconTerminal, IconThumbDown, IconThumbDownFilled, IconThumbUp, IconThumbUpFilled, IconTrash, IconTrashXFilled, IconTriangleInverted, IconTriangleSquareCircle, IconUpload, IconUser, IconUsersGroup, IconUserX, IconVariable, IconVariablePlus, IconVersions, IconWand, IconWaveSine, IconWebhook, IconWreckingBall, IconX, IconZoomCode, IconDragDrop2, IconWorld } from '@tabler/icons-react'; +import { IconActivity, IconAdjustments, IconAdjustmentsAlt, IconAdjustmentsOff, IconAlertCircle, IconAlertTriangle, IconAlertTriangleFilled, IconAngle, IconApi, IconArchive, IconArrowAutofitDown, IconArrowCurveRight, IconArrowDown, IconArrowLeft, IconArrowNarrowLeft, IconArrowNarrowRight, IconArrowRight, IconArrowsRandom, IconArrowsSort, IconArrowUp, IconArrowUpRight, IconAssembly, IconBallpen, IconBallpenOff, IconBell, IconBolt, IconBottle, IconBox, IconBoxOff, IconBrandGithub, IconBrandOpenai, IconBrandPython, IconBulb, IconBulldozer, IconCamera, IconCategoryPlus, IconCell, IconChartBubble, IconChartCircles, IconChartDots3, IconChartLine, IconChartPie, IconCheck, IconChecks, IconChevronCompactLeft, IconChevronCompactRight, IconChevronDown, IconChevronLeft, IconChevronRight, IconChevronUp, IconCircle, IconCircleCheck, IconCircleCheckFilled, IconCircleMinus, IconCirclePlus, IconClick, IconClipboard, IconClipboardCheck, IconClipboardOff, IconClock, IconCode, IconCodePlus, IconColorPicker, IconColumns, IconColumns1, IconColumns2, IconColumns3, IconCopy, IconCrown, IconCrownOff, IconDatabase, IconDatabasePlus, IconDeviceFloppy, IconDots, IconDotsVertical, IconDownload, IconEdit, IconEngine, IconExclamationCircle, IconExclamationMark, IconExternalLink, IconEye, IconEyeCancel, IconEyeCheck, IconEyeOff, IconFile, IconFileDownload, IconFileImport, IconFileInfo, IconFilePencil, IconFiles, IconFileText, IconFileUpload, IconFilter, IconFilterOff, IconFishHook, IconFolderBolt, IconGitCommit, IconGripVertical, IconHandClick, IconHeading, IconHelp, IconHexagons, IconHierarchy, IconHierarchy3, IconHistory, IconHome, IconHourglass, IconHourglassEmpty, IconInfoCircle, IconInfoCircleFilled, IconInfoSquare, IconLayoutList, IconLayoutNavbarCollapse, IconLayoutSidebar, IconLetterGSmall, IconLink, IconList, IconLoader, IconLoader2, IconLockAccess, IconMap, IconMaximize, IconMessageCircle, IconMinus, IconMessageCircleSearch, IconMessages, IconMinimize, IconMoustache, IconNews, IconNotes, IconPencil, IconPlayCardStar, IconPlayerPlay, IconPlayerPlayFilled, IconPlus, IconPoint, IconPointerOff, IconPointerSearch, IconPointFilled, IconQuestionMark, IconRecycle, IconRefresh, IconRefreshAlert, IconResize, IconRobot, IconRotate, IconScissors, IconScreenshot, IconSearch, IconSend, IconSettings, IconShare, IconShieldCheckFilled, IconShieldFilled, IconSquare, IconSquareCheck, IconStar, IconTag, IconTemplate, IconTerminal, IconThumbDown, IconThumbDownFilled, IconThumbUp, IconThumbUpFilled, IconTrash, IconTrashXFilled, IconTriangleInverted, IconTriangleSquareCircle, IconUpload, IconUser, IconUsersGroup, IconUserX, IconVariable, IconVariablePlus, IconVersions, IconWand, IconWaveSine, IconWebhook, IconWreckingBall, IconX, IconZoomCode, IconDragDrop2, IconWorld, IconCircleDotted } from '@tabler/icons-react'; export const MemoIconHome = memo(IconHome); export const MemoIconInfoCircle = memo(IconInfoCircle); @@ -184,3 +184,4 @@ export const MemoIconArrowNarrowRight = memo(IconArrowNarrowRight); export const MemoIconMinus = memo(IconMinus); export const MemoIconDragDrop2 = memo(IconDragDrop2); export const MemoIconWorld = memo(IconWorld); +export const MemoIconCircleDotted = memo(IconCircleDotted); \ No newline at end of file diff --git a/components/kern-table/CellComponents.tsx b/components/kern-table/CellComponents.tsx index 77ec1e4..a8cd1fd 100644 --- a/components/kern-table/CellComponents.tsx +++ b/components/kern-table/CellComponents.tsx @@ -345,4 +345,54 @@ function ConfigReleaseNotificationCell({ onClickView, onClickEdit }) {
; } -export { OrganizationAndUsersCell, MaxRowsColsCharsCell, CommentsCell, ExportConsumptionAndDeleteCell, BadgeCell, OrganizationUserCell, DeleteCell, LevelCell, ArchiveReasonCell, ProjectNameTaskCell, CancelTaskCell, IconCell, ConfigCell, EditDeleteOrgButtonCell, ViewStackCell, AbortSessionButtonCell, FeedbackMessageCell, FeedbackMessageTextCell, JumpToConversationCell, RemoteVersionCell, ExternalLinkCell, ModelDateCell, FileSizeCell, StatusModelCell, DeleteModelCell, LabelCell, ViewCell, EvaluationRunStateCell, EvaluationRunDetailsCell, EtlApiTokenCell, EmailCell, EditIntegrationCell, ExpiredTokenCell, LinkCell, ConfigReleaseNotificationCell } \ No newline at end of file +function TruncateAndTooltipCell({ value, hasError = false }) { + return
+ {hasError && } + {value ? {value}} color="invert" hideArrow={true} placement='bottom'> + {value} + : } +
; +} + +function JumpToConversationAndAssignCell({ onClick, jumpTo }) { + return
+ + + +
+} + +function TaskStateCell({ value, color, tooltipValue }) { + const className = useMemo(() => { + return `inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color === 'green' + ? 'bg-green-300' + : 'bg-' + color + '-100 text-' + color + '-800'}`; + }, [color]); + + return ( + <> + {tooltipValue ? ( + + + + + + {value} + + + ) : ( + + + + + {value} + + )} + + ); +} + +export { OrganizationAndUsersCell, MaxRowsColsCharsCell, CommentsCell, ExportConsumptionAndDeleteCell, BadgeCell, OrganizationUserCell, DeleteCell, LevelCell, ArchiveReasonCell, ProjectNameTaskCell, CancelTaskCell, IconCell, ConfigCell, EditDeleteOrgButtonCell, ViewStackCell, AbortSessionButtonCell, FeedbackMessageCell, FeedbackMessageTextCell, JumpToConversationCell, RemoteVersionCell, ExternalLinkCell, ModelDateCell, FileSizeCell, StatusModelCell, DeleteModelCell, LabelCell, ViewCell, EvaluationRunStateCell, EvaluationRunDetailsCell, EtlApiTokenCell, EmailCell, EditIntegrationCell, ExpiredTokenCell, LinkCell, ConfigReleaseNotificationCell, TruncateAndTooltipCell, JumpToConversationAndAssignCell, TaskStateCell } \ No newline at end of file diff --git a/components/kern-table/KernTable.tsx b/components/kern-table/KernTable.tsx index ab346cc..3b8657f 100644 --- a/components/kern-table/KernTable.tsx +++ b/components/kern-table/KernTable.tsx @@ -1,6 +1,6 @@ import SortArrows from "@/submodules/react-components/components/kern-table/SortArrows"; import { KernTableProps } from "../../types/kern-table"; -import { AbortSessionButtonCell, ArchiveReasonCell, BadgeCell, CancelTaskCell, CommentsCell, ConfigCell, DeleteModelCell, DeleteCell, EditDeleteOrgButtonCell, EmailCell, EtlApiTokenCell, EvaluationRunDetailsCell, EvaluationRunStateCell, ExportConsumptionAndDeleteCell, ExternalLinkCell, FeedbackMessageCell, FeedbackMessageTextCell, FileSizeCell, IconCell, JumpToConversationCell, LabelCell, LevelCell, MaxRowsColsCharsCell, ModelDateCell, OrganizationAndUsersCell, OrganizationUserCell, ProjectNameTaskCell, RemoteVersionCell, StatusModelCell, ViewCell, ViewStackCell, EditIntegrationCell, ExpiredTokenCell, LinkCell, ConfigReleaseNotificationCell } from "./CellComponents"; +import { AbortSessionButtonCell, ArchiveReasonCell, BadgeCell, CancelTaskCell, CommentsCell, ConfigCell, DeleteModelCell, DeleteCell, EditDeleteOrgButtonCell, EmailCell, EtlApiTokenCell, EvaluationRunDetailsCell, EvaluationRunStateCell, ExportConsumptionAndDeleteCell, ExternalLinkCell, FeedbackMessageCell, FeedbackMessageTextCell, FileSizeCell, IconCell, JumpToConversationCell, LabelCell, LevelCell, MaxRowsColsCharsCell, ModelDateCell, OrganizationAndUsersCell, OrganizationUserCell, ProjectNameTaskCell, RemoteVersionCell, StatusModelCell, ViewCell, ViewStackCell, EditIntegrationCell, ExpiredTokenCell, LinkCell, ConfigReleaseNotificationCell, TruncateAndTooltipCell, JumpToConversationAndAssignCell, TaskStateCell } from "./CellComponents"; import { Fragment, useMemo } from "react"; import KernDropdown from "../KernDropdown"; import { NotApplicableBadge } from "@/submodules/react-components/components/Badges"; @@ -162,6 +162,12 @@ function ComponentMapper(cell: any) { return ; case 'ConfigReleaseNotificationCell': return ; + case 'TruncateAndTooltipCell': + return ; + case 'JumpToConversationAndAssignCell': + return ; + case 'TaskStateCell': + return ; case '@provided@': return cell.jsx ?? ; } diff --git a/types/dropdown.ts b/types/dropdown.ts index cef95d6..0746bce 100644 --- a/types/dropdown.ts +++ b/types/dropdown.ts @@ -44,6 +44,7 @@ import React from "react"; * @positionDropdown {string} - The position of the dropdown * @dropdownAdd {JSX.Element} - array of JSX elements that will be added to the dropdown items * @forceOverwriteOpen {boolean} - forces the dropdown to stay open until set to false/undefined + * @truncateButtonName {boolean} - If the button name should be truncated when it exceeds the button width */ export type KernDropdownProps = { buttonName?: string; @@ -93,6 +94,7 @@ export type KernDropdownProps = { scrollAfterNOptions?: number; dropdownAdd?: JSX.Element[]; forceOverwriteOpen?: boolean; + truncateButtonName?: boolean; } export type AppSelectionDropdownProps = {