← К списку компонентов

PluginFieldsSelect

Выпадающий список для выбора полей Трекера внутри плагина. Принимает плоский список полей с метаданными категорий и автоматически группирует их в сворачиваемые секции. Поддерживает поиск, мультивыбор, кнопки применения/сброса и состояние загрузки.

Базовое использование

import {PluginFieldsSelect} from '@weavix/tracker-components';
import type {PluginFieldsSelectField} from '@weavix/tracker-components';

const fields: PluginFieldsSelectField[] = [
    {id: 'summary', name: 'Summary', category: {id: '1', display: 'Системные поля'}},
    {id: 'description', name: 'Description', category: {id: '1', display: 'Системные поля'}},
    {id: 'sprint', name: 'Sprint', category: {id: '2', display: 'Пользовательские поля'}},
];

<PluginFieldsSelect
    open={true}
    fields={fields}
    onOpenChange={(open) => console.log(open)}
    onItemSelect={(item) => console.log('selected', item)}
    onItemDeselect={(item) => console.log('deselected', item)}
/>;

Пример 1 — Только начальная загрузка глобальных полей

Загружает все глобальные поля один раз при монтировании. Поиск работает на стороне клиента по уже загруженному списку.

import React, {useEffect, useState} from 'react';
import {PluginFieldsSelect} from '@weavix/tracker-components';
import type {PluginFieldsSelectField, TrackerSelectItem} from '@weavix/tracker-components';

interface Props {
    trackerApi: TrackerApi;
    onSubmit: (selected: TrackerSelectItem[]) => void;
}

export const GlobalFieldsSelect: React.FC<Props> = ({trackerApi, onSubmit}) => {
    const [fields, setFields] = useState<PluginFieldsSelectField[]>([]);
    const [loading, setLoading] = useState(true);
    const [open, setOpen] = useState(false);
    const [selectedItems, setSelectedItems] = useState<TrackerSelectItem[]>([]);

    useEffect(() => {
        trackerApi.v3
            .get['/fields']()
            .then((result) => setFields(result.data))
            .finally(() => setLoading(false));
    }, [trackerApi]);

    return (
        <PluginFieldsSelect
            open={open}
            fields={fields}
            loading={loading}
            selectedItems={selectedItems}
            onOpenChange={setOpen}
            onItemSelect={(item) => setSelectedItems((prev) => [...prev, item])}
            onItemDeselect={(item) =>
                setSelectedItems((prev) => prev.filter((s) => s.id !== item.id))
            }
            onSubmit={() => onSubmit(selectedItems)}
            expandSystemGroup
        />
    );
};

Пример 2 — Глобальный саджест при вводе пользователя

Использует начальную загрузку для первоначального списка и переключается на саджест-эндпоинт при вводе текста.

import React, {useEffect, useState} from 'react';
import {PluginFieldsSelect} from '@weavix/tracker-components';
import type {PluginFieldsSelectField, TrackerSelectItem} from '@weavix/tracker-components';

export const GlobalFieldsSelectWithSuggest: React.FC<Props> = ({trackerApi, onSubmit}) => {
    const [initialFields, setInitialFields] = useState<PluginFieldsSelectField[]>([]);
    const [fields, setFields] = useState<PluginFieldsSelectField[]>([]);
    const [loading, setLoading] = useState(true);
    const [open, setOpen] = useState(false);
    const [selectedItems, setSelectedItems] = useState<TrackerSelectItem[]>([]);

    useEffect(() => {
        trackerApi.v3
            .get['/fields']()
            .then((result) => {
                setInitialFields(result.data);
                setFields(result.data);
            })
            .finally(() => setLoading(false));
    }, [trackerApi]);

    const handleSearchChange = async (text: string) => {
        // Саджест возвращает пустой ответ при пустом input —
        // возвращаемся к начальному списку при очистке поиска
        if (!text) {
            setFields(initialFields);
            return;
        }
        const result = await trackerApi.v3.post['/fields/_suggest']({
            bodyParams: {input: text, readOnly: true, localFields: false, extended: true},
        });
        setFields(result.data);
    };

    return (
        <PluginFieldsSelect
            open={open}
            fields={fields}
            loading={loading}
            selectedItems={selectedItems}
            onOpenChange={setOpen}
            onSearchChange={handleSearchChange}
            onItemSelect={(item) => setSelectedItems((prev) => [...prev, item])}
            onItemDeselect={(item) =>
                setSelectedItems((prev) => prev.filter((s) => s.id !== item.id))
            }
            onSubmit={() => onSubmit(selectedItems)}
            expandGroupsOnSearch
        />
    );
};

Пример 3 — Глобальные + локальные поля для конкретных очередей

Расширяет пример 2, добавляя поля, специфичные для очередей. Если queueKeys пуст — используется только глобальный саджест, так как localFields: true с пустым массивом queues приводит к ошибке запроса.

import React, {useEffect, useState} from 'react';
import {PluginFieldsSelect} from '@weavix/tracker-components';
import type {PluginFieldsSelectField, TrackerSelectItem} from '@weavix/tracker-components';

interface Props {
    trackerApi: TrackerApi;
    /** Необходимо передать хотя бы один ключ очереди при использовании локальных полей */
    queueKeys: string[];
    onSubmit: (selected: TrackerSelectItem[]) => void;
}

export const LocalFieldsSelectWithSuggest: React.FC<Props> = ({
    trackerApi,
    queueKeys,
    onSubmit,
}) => {
    const [initialFields, setInitialFields] = useState<PluginFieldsSelectField[]>([]);
    const [fields, setFields] = useState<PluginFieldsSelectField[]>([]);
    const [loading, setLoading] = useState(true);
    const [open, setOpen] = useState(false);
    const [selectedItems, setSelectedItems] = useState<TrackerSelectItem[]>([]);

    useEffect(() => {
        trackerApi.v3
            .get['/fields']()
            .then((result) => {
                setInitialFields(result.data);
                setFields(result.data);
            })
            .finally(() => setLoading(false));
    }, [trackerApi]);

    const handleSearchChange = async (text: string) => {
        if (!text) {
            setFields(initialFields);
            return;
        }
        const hasQueues = queueKeys.length > 0;
        const result = await trackerApi.v3.post['/fields/_suggest']({
            bodyParams: {
                input: text,
                readOnly: true,
                localFields: hasQueues,
                extended: true,
                ...(hasQueues && {queues: queueKeys}),
            },
        });
        setFields(result.data);
    };

    return (
        <PluginFieldsSelect
            open={open}
            fields={fields}
            loading={loading}
            selectedItems={selectedItems}
            onOpenChange={setOpen}
            onSearchChange={handleSearchChange}
            onItemSelect={(item) => setSelectedItems((prev) => [...prev, item])}
            onItemDeselect={(item) =>
                setSelectedItems((prev) => prev.filter((s) => s.id !== item.id))
            }
            onSubmit={() => onSubmit(selectedItems)}
            expandGroupsOnSearch
        />
    );
};

Основные свойства

Свойство

Тип

По умолчанию

Описание

fields

PluginFieldsSelectField[]

Плоский список полей для отображения

open

boolean

Открыт ли выпадающий список

onOpenChange

(open: boolean) =>
  void

Колбэк при изменении состояния открытия

selectedItems

TrackerSelectItem[]

Текущие выбранные элементы

loading

boolean

false

Состояние загрузки — показывает спиннер

onItemSelect

(item: TrackerSelectItem) =>
  void

Колбэк при выборе элемента

onItemDeselect

(item: TrackerSelectItem) =>
  void

Колбэк при снятии выбора с элемента

onSubmit

() => void
  | Promise<void>

Колбэк при нажатии кнопки применения

onReset

() =>
  void

Колбэк при нажатии кнопки сброса

onSearchChange

(search: string) =>
  void

Колбэк при изменении текста поиска

showSearch

boolean

true

Показывать поле поиска

showSubmit

boolean

true

Показывать кнопку применения

showReset

boolean

false

Показывать кнопку сброса

submitButtonText

string

Текст кнопки применения

resetButtonText

string

Текст кнопки сброса

expandGroupsOnSearch

boolean

false

Раскрывать группы при вводе в поле поиска

expandSystemGroup

boolean

false

Раскрывать группу системных полей (id='1') по умолчанию

singleSelect

boolean

false

Режим одиночного выбора — закрывает список после выбора

hideCheckbox

boolean

false

Скрыть чекбоксы рядом с элементами

showMeta

boolean

false

Показывать мета-строку под названием элемента

disabledItemsIds

string[]

ID элементов, которые нужно отобразить как недоступные

footer

ReactNode

Дополнительный контент под списком элементов

className

string

Дополнительный CSS-класс корневого элемента

Предыдущая
Следующая