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

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-класс корневого элемента

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