---
metadata:
  - name: generator
    content: Diplodoc Platform v5.54.5
  - property: og:type
    content: article
  - property: article:section
    content: Платформа плагинов
  - property: og:title
    content: PluginFieldsSelect
  - property: article:tag
    content: Техническая инструкция
alternate:
  - https://yandex.ru/support/tracker/en/plugins/components/plugin-fields-select.md
  - https://yandex.ru/support/tracker/ru/plugins/components/plugin-fields-select.md
  - href: ru/plugins/components/plugin-fields-select.md
    type: text/markdown
    title: Markdown version
  - href: ../../llms.txt
    type: text/markdown
    title: llms.txt
---
> **Documentation Index:** Fetch the complete configuration index at https://yandex.ru/support/tracker/ru/llms.txt

[← К списку компонентов](https://yandex.ru/support/tracker/ru/plugins/components/index.md)

# PluginFieldsSelect {#plugin-fields-select}

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

## Базовое использование {#usage}

```tsx
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 — Только начальная загрузка глобальных полей {#example-1}

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

```tsx
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 — Глобальный саджест при вводе пользователя {#example-2}

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

```tsx
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 — Глобальные + локальные поля для конкретных очередей {#example-3}

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

```tsx
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
        />
    );
};
```

## Основные свойства {#props-table}

#|
|| **Свойство** | **Тип** | **По умолчанию** | **Описание** ||
|| `fields` | `PluginFieldsSelectField[]` | — | Плоский список полей для отображения ||
|| `open` | `boolean` | — | Открыт ли выпадающий список ||
|| `onOpenChange`
|

```ts
(open: boolean) =>
  void
```

| — | Колбэк при изменении состояния открытия ||
|| `selectedItems` | `TrackerSelectItem[]` | — | Текущие выбранные элементы ||
|| `loading` | `boolean` | `false` | Состояние загрузки — показывает спиннер ||
|| `onItemSelect`
|

```ts
(item: TrackerSelectItem) =>
  void
```

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

```ts
(item: TrackerSelectItem) =>
  void
```

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

```ts
() => void
  | Promise<void>
```

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

```ts
() =>
  void
```

| — | Колбэк при нажатии кнопки сброса ||
|| `onSearchChange`
|

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