From 1a1836fd85e14887168055553cf546ccfcf92d5e Mon Sep 17 00:00:00 2001 From: Maria Lordwill Date: Wed, 29 Apr 2026 11:23:07 +0400 Subject: [PATCH 1/3] 46276 feat(Dropdown): add disabled support for individual options; disable empty datasets in template editor --- .../components/TemplateEdit/ExtraFields/types.ts | 3 ++- .../ExtraFields/utils/ExtraFieldDropdown.tsx | 2 ++ .../TemplateEdit/ExtraFields/utils/types.ts | 1 + .../ExtraFields/utils/useDatasetOptions.ts | 6 +++++- .../public/components/UI/Dropdown/Dropdown.css | 9 +++++++++ .../public/components/UI/Dropdown/Dropdown.tsx | 16 ++++++++++++---- 6 files changed, 31 insertions(+), 6 deletions(-) diff --git a/frontend/src/public/components/TemplateEdit/ExtraFields/types.ts b/frontend/src/public/components/TemplateEdit/ExtraFields/types.ts index 66837d30b..af24dcf61 100644 --- a/frontend/src/public/components/TemplateEdit/ExtraFields/types.ts +++ b/frontend/src/public/components/TemplateEdit/ExtraFields/types.ts @@ -3,6 +3,7 @@ import { IntlShape } from 'react-intl'; import { EExtraFieldMode, IExtraField } from '../../../types/template'; import { EInputNameBackgroundColor } from '../../../types/workflow'; +import { IDatasetOption } from './utils/types'; export interface IWorkflowExtraFieldProps { field: IExtraField; @@ -26,5 +27,5 @@ export interface IExtraFieldProps extends IWorkflowExtraFieldProps { wrapperClassName?: string; fieldsCount?: number; id?: number; - datasetOptions?: { label: string; value: string }[]; + datasetOptions?: IDatasetOption[]; } diff --git a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/ExtraFieldDropdown.tsx b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/ExtraFieldDropdown.tsx index cc48d47be..1655f0510 100644 --- a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/ExtraFieldDropdown.tsx +++ b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/ExtraFieldDropdown.tsx @@ -40,10 +40,12 @@ export function ExtraFieldDropdown({ return datasetOptions.map((option) => { const isSelected = String(selectedDatasetId) === option.value; + const isEmpty = option.itemsCount === 0; return { mapKey: `dataset-${option.value}`, label: option.label, + disabled: isEmpty, className: classnames(styles['dataset-option'], isSelected && styles['dataset-option-selected']), onClick: (closeDropdown: () => void) => { onDatasetSelect?.(Number(option.value)); diff --git a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/types.ts b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/types.ts index d10031d61..aae26a2ca 100644 --- a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/types.ts +++ b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/types.ts @@ -3,6 +3,7 @@ import { IExtraField } from '../../../../types/template'; export interface IDatasetOption { label: string; value: string; + itemsCount: number; } export interface IKickoffDropdownProps { diff --git a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/useDatasetOptions.ts b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/useDatasetOptions.ts index d1dbe3194..78e05bed4 100644 --- a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/useDatasetOptions.ts +++ b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/useDatasetOptions.ts @@ -22,7 +22,11 @@ export function useDatasetOptions(fields: IExtraField[]) { }, [hasDatasetFields, isDatasetsLoaded, isDatasetsLoading, dispatch]); return useMemo( - () => datasetsList.map((dataset) => ({ label: dataset.name, value: String(dataset.id) })), + () => datasetsList.map(({ name, id, itemsCount }) => ({ + label: name, + value: String(id), + itemsCount, + })), [datasetsList], ); } diff --git a/frontend/src/public/components/UI/Dropdown/Dropdown.css b/frontend/src/public/components/UI/Dropdown/Dropdown.css index 6829d31d4..d4c770bea 100644 --- a/frontend/src/public/components/UI/Dropdown/Dropdown.css +++ b/frontend/src/public/components/UI/Dropdown/Dropdown.css @@ -84,6 +84,15 @@ } } } + +.dropdown-item_disabled { + pointer-events: none; + color: var(--pneumatic-color-black32); + + .label { + color: var(--pneumatic-color-black32); + } +} .dropdown-item-mobile { justify-content: space-between; } diff --git a/frontend/src/public/components/UI/Dropdown/Dropdown.tsx b/frontend/src/public/components/UI/Dropdown/Dropdown.tsx index 673c67f7e..e59ac8cdd 100644 --- a/frontend/src/public/components/UI/Dropdown/Dropdown.tsx +++ b/frontend/src/public/components/UI/Dropdown/Dropdown.tsx @@ -23,6 +23,7 @@ export type TDropdownOption = { customSubOption?: React.ReactElement; color?: TDropdownItemColor; isHidden?: boolean; + disabled?: boolean; size?: 'lg' | 'sm'; className?: string; Icon?(props: React.SVGAttributes): JSX.Element; @@ -103,6 +104,7 @@ export function Dropdown({ withConfirmation, initialConfirmationState, isHidden, + disabled, className: optionClassName, Icon, onClick, @@ -151,22 +153,28 @@ export function Dropdown({
{withUpperline &&
} { onClick?.(() => setIsOpen(false)); closeDropdown(); }, })} cssModule={{ - 'dropdown-item': classnames(styles['dropdown-item'], getDropdownItemColorClass(color), { - [styles['dropdown-item-mobile']]: isMobile && isFromBreakdownItem, - }), + 'dropdown-item': classnames( + styles['dropdown-item'], + getDropdownItemColorClass(color), + { + [styles['dropdown-item-mobile']]: isMobile && isFromBreakdownItem, + [styles['dropdown-item_disabled']]: disabled, + }, + ), }} withConfirmation={withConfirmation} initialConfirmationState={initialConfirmationState} closeDropdown={closeDropdown} toggle={false} className={optionClassName} + {...(disabled && { 'aria-disabled': true })} > {renderOptionContent()} From 01246fd7b1fee4ad4ef19975851ca83efb95f1cb Mon Sep 17 00:00:00 2001 From: Maria Lordwill Date: Wed, 29 Apr 2026 11:37:43 +0400 Subject: [PATCH 2/3] 46276 fix(datasets): use natural sort order for dataset items (1, 2, 10 instead of 1, 10, 2) --- frontend/src/public/utils/dataset.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/public/utils/dataset.ts b/frontend/src/public/utils/dataset.ts index a8f1cc4b4..7d48a124f 100644 --- a/frontend/src/public/utils/dataset.ts +++ b/frontend/src/public/utils/dataset.ts @@ -14,10 +14,10 @@ export function getSortedAndFilteredDatasetItems( result.sort((a, b) => { if (sorting === EDatasetsSorting.NameAsc) { - return a.value.localeCompare(b.value); + return a.value.localeCompare(b.value, undefined, { numeric: true }); } if (sorting === EDatasetsSorting.NameDesc) { - return b.value.localeCompare(a.value); + return b.value.localeCompare(a.value, undefined, { numeric: true }); } if (sorting === EDatasetsSorting.DateAsc) { return a.order - b.order; From 25431ea92c4020732c4c0011576df0e4fcf334d7 Mon Sep 17 00:00:00 2001 From: Maria Lordwill Date: Wed, 29 Apr 2026 12:29:26 +0400 Subject: [PATCH 3/3] 46276 fix(datasets): hide empty datasets from selection menu in template editor --- .../components/TemplateEdit/ExtraFields/types.ts | 3 +-- .../ExtraFields/utils/ExtraFieldDropdown.tsx | 2 -- .../TemplateEdit/ExtraFields/utils/types.ts | 1 - .../ExtraFields/utils/useDatasetOptions.ts | 8 +++----- .../public/components/UI/Dropdown/Dropdown.css | 9 --------- .../public/components/UI/Dropdown/Dropdown.tsx | 16 ++++------------ 6 files changed, 8 insertions(+), 31 deletions(-) diff --git a/frontend/src/public/components/TemplateEdit/ExtraFields/types.ts b/frontend/src/public/components/TemplateEdit/ExtraFields/types.ts index af24dcf61..66837d30b 100644 --- a/frontend/src/public/components/TemplateEdit/ExtraFields/types.ts +++ b/frontend/src/public/components/TemplateEdit/ExtraFields/types.ts @@ -3,7 +3,6 @@ import { IntlShape } from 'react-intl'; import { EExtraFieldMode, IExtraField } from '../../../types/template'; import { EInputNameBackgroundColor } from '../../../types/workflow'; -import { IDatasetOption } from './utils/types'; export interface IWorkflowExtraFieldProps { field: IExtraField; @@ -27,5 +26,5 @@ export interface IExtraFieldProps extends IWorkflowExtraFieldProps { wrapperClassName?: string; fieldsCount?: number; id?: number; - datasetOptions?: IDatasetOption[]; + datasetOptions?: { label: string; value: string }[]; } diff --git a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/ExtraFieldDropdown.tsx b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/ExtraFieldDropdown.tsx index 1655f0510..cc48d47be 100644 --- a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/ExtraFieldDropdown.tsx +++ b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/ExtraFieldDropdown.tsx @@ -40,12 +40,10 @@ export function ExtraFieldDropdown({ return datasetOptions.map((option) => { const isSelected = String(selectedDatasetId) === option.value; - const isEmpty = option.itemsCount === 0; return { mapKey: `dataset-${option.value}`, label: option.label, - disabled: isEmpty, className: classnames(styles['dataset-option'], isSelected && styles['dataset-option-selected']), onClick: (closeDropdown: () => void) => { onDatasetSelect?.(Number(option.value)); diff --git a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/types.ts b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/types.ts index aae26a2ca..d10031d61 100644 --- a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/types.ts +++ b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/types.ts @@ -3,7 +3,6 @@ import { IExtraField } from '../../../../types/template'; export interface IDatasetOption { label: string; value: string; - itemsCount: number; } export interface IKickoffDropdownProps { diff --git a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/useDatasetOptions.ts b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/useDatasetOptions.ts index 78e05bed4..bc0248d1c 100644 --- a/frontend/src/public/components/TemplateEdit/ExtraFields/utils/useDatasetOptions.ts +++ b/frontend/src/public/components/TemplateEdit/ExtraFields/utils/useDatasetOptions.ts @@ -22,11 +22,9 @@ export function useDatasetOptions(fields: IExtraField[]) { }, [hasDatasetFields, isDatasetsLoaded, isDatasetsLoading, dispatch]); return useMemo( - () => datasetsList.map(({ name, id, itemsCount }) => ({ - label: name, - value: String(id), - itemsCount, - })), + () => datasetsList + .filter(({ itemsCount }) => itemsCount > 0) + .map(({ name, id }) => ({ label: name, value: String(id) })), [datasetsList], ); } diff --git a/frontend/src/public/components/UI/Dropdown/Dropdown.css b/frontend/src/public/components/UI/Dropdown/Dropdown.css index d4c770bea..6829d31d4 100644 --- a/frontend/src/public/components/UI/Dropdown/Dropdown.css +++ b/frontend/src/public/components/UI/Dropdown/Dropdown.css @@ -84,15 +84,6 @@ } } } - -.dropdown-item_disabled { - pointer-events: none; - color: var(--pneumatic-color-black32); - - .label { - color: var(--pneumatic-color-black32); - } -} .dropdown-item-mobile { justify-content: space-between; } diff --git a/frontend/src/public/components/UI/Dropdown/Dropdown.tsx b/frontend/src/public/components/UI/Dropdown/Dropdown.tsx index e59ac8cdd..673c67f7e 100644 --- a/frontend/src/public/components/UI/Dropdown/Dropdown.tsx +++ b/frontend/src/public/components/UI/Dropdown/Dropdown.tsx @@ -23,7 +23,6 @@ export type TDropdownOption = { customSubOption?: React.ReactElement; color?: TDropdownItemColor; isHidden?: boolean; - disabled?: boolean; size?: 'lg' | 'sm'; className?: string; Icon?(props: React.SVGAttributes): JSX.Element; @@ -104,7 +103,6 @@ export function Dropdown({ withConfirmation, initialConfirmationState, isHidden, - disabled, className: optionClassName, Icon, onClick, @@ -153,28 +151,22 @@ export function Dropdown({
{withUpperline &&
} { onClick?.(() => setIsOpen(false)); closeDropdown(); }, })} cssModule={{ - 'dropdown-item': classnames( - styles['dropdown-item'], - getDropdownItemColorClass(color), - { - [styles['dropdown-item-mobile']]: isMobile && isFromBreakdownItem, - [styles['dropdown-item_disabled']]: disabled, - }, - ), + 'dropdown-item': classnames(styles['dropdown-item'], getDropdownItemColorClass(color), { + [styles['dropdown-item-mobile']]: isMobile && isFromBreakdownItem, + }), }} withConfirmation={withConfirmation} initialConfirmationState={initialConfirmationState} closeDropdown={closeDropdown} toggle={false} className={optionClassName} - {...(disabled && { 'aria-disabled': true })} > {renderOptionContent()}