API Reference - @weavix/tracker-plugin-sdk-react

Components

TrackerPluginProvider

Провайдер для инициализации плагина Tracker. Оборачивает приложение и управляет жизненным циклом плагина. Предоставляет тему, язык и контекст слота через контекст React.

Props: TrackerPluginProviderProps

Features

  • Автоматическая инициализация плагина
  • Управление состояниями загрузки и ошибок
  • Предоставление контекста через React Context API
  • Автоматическое уведомление Трекера о готовности плагина
  • Защита от двойной инициализации в React StrictMode

Example (базовое использование)

import { TrackerPluginProvider } from '@weavix/tracker-plugin-sdk-react';
import { createRoot } from 'react-dom/client';
import { App } from './App';

const root = createRoot(document.getElementById('root')!);

root.render(
  <TrackerPluginProvider>
    <App />
  </TrackerPluginProvider>,
);

Example (с кастомными опциями)

import { TrackerPluginProvider } from '@weavix/tracker-plugin-sdk-react';
import { Loader } from './components/Loader';
import { ErrorScreen } from './components/ErrorScreen';

root.render(
  <TrackerPluginProvider
    autoResize={false}
    fallback={<Loader />}
    errorFallback={(error) => <ErrorScreen error={error} />}
    autoNotifyReady={false}
  >
    <App />
  </TrackerPluginProvider>,
);

Example (отключение автоматического уведомления)

import { TrackerPluginProvider, hostApi } from '@weavix/tracker-plugin-sdk-react';

function App() {
  useEffect(() => {
    // Выполняем дополнительную инициализацию, затем уведомляем Трекер
    initializeApp().then(() => {
      hostApi.notifyReady()
    });
  }, []);

  return <div>My Plugin</div>;
}

root.render(
  <TrackerPluginProvider autoNotifyReady={false}>
    <App />
  </TrackerPluginProvider>,
);

Hooks

useTrackerPluginContext

Хук для получения темы, языка и контекста слота из TrackerPluginProvider. Поддерживает несколько перегрузок в зависимости от level и generic-параметра TSlot.

Type Signature

// level: 'basic' — базовый контекст (только entityId и entityMeta), тип slotContext сужается по проверке slot
function useTrackerPluginContext(level: 'basic'): {
    [K in keyof SlotContextMap]: BasicTrackerPluginContextValue<K>;
}[keyof SlotContextMap];

// level: 'full' — полный контекст с живыми данными сущности
function useTrackerPluginContext(level: 'full'): {
    [K in keyof SlotContextMap]: FullTrackerPluginContextValue<K>;
}[keyof SlotContextMap];

// С generic TSlot и level: 'basic' — типизированный базовый контекст для конкретного слота
function useTrackerPluginContext<TSlot extends keyof SlotContextMap>(
    level: 'basic',
): BasicTrackerPluginContextValue<TSlot>;

// С generic TSlot и level: 'full' — типизированный полный контекст для конкретного слота
function useTrackerPluginContext<TSlot extends keyof SlotContextMap>(
    level: 'full',
): FullTrackerPluginContextValue<TSlot>;

Parameters

  • level — 'basic' | 'full' (обязательный) — уровень контекста слота. Должен совпадать со значением contextLevel, указанным для слота в manifest.json. Подробнее — в разделе Уровни контекста слота.

Type Parameters

  • TSlot — тип слота (опционально). С generic — slotContext типизирован под этот слот. Без generic — можно сужать по slot === 'issue.action' и т.д.

Returns

BasicTrackerPluginContextValue<TSlot> или FullTrackerPluginContextValue<TSlot> в зависимости от level, либо union по всем слотам.

Throws

Example (basic контекст)

import { useTrackerPluginContext } from '@weavix/tracker-plugin-sdk-react';

function MyComponent() {
  const { theme, language, slotContext } = useTrackerPluginContext('basic');
  // slotContext.entityId — идентификатор текущей сущности
  // slotContext.entityMeta — дополнительные базовые метаданные (опционально)

  return (
    <div className={theme}>
      <p>Language: {language}</p>
      <p>Entity ID: {slotContext.entityId}</p>
    </div>
  );
}

Example (basic — слот известен)

const { slotContext } = useTrackerPluginContext<'issue.action'>('basic');
slotContext.entityId; // идентификатор тикета
slotContext.entityMeta; // дополнительные метаданные

Example (несколько слотов — сужение по slot)

const { slot, slotContext } = useTrackerPluginContext('basic');
if (slot === 'issue.action') {
  slotContext.entityId; // здесь slotContext типизирован под слот issue.action
}

Example (full контекст с типизацией слота)

import { useTrackerPluginContext } from '@weavix/tracker-plugin-sdk-react';

function IssuePlugin() {
  // В manifest.json для слота: contextLevel: "full"
  const { theme, language, slotContext } = useTrackerPluginContext<'issue.action'>('full');
  return (
    <div>
      <h1>Issue: {slotContext.key}</h1>
      <p>Version: {slotContext.version}</p>
      <p>Theme: {theme}</p>
    </div>
  );
}

useLocalizedString

Хук для получения локализованной строки на основе текущего языка из контекста TrackerPluginProvider.

Type Signature

function useLocalizedString(fallbackLanguage?: string): (value: LocalizedString) => string;

Parameters

  • fallbackLanguage - string (опционально, по умолчанию 'en') - резервный язык, если основной не найден

Returns

Функция для локализации строк (value: LocalizedString) => string.

Example (базовое использование)

import { useLocalizedString } from '@weavix/tracker-plugin-sdk-react';

function MyComponent() {
  const localize = useLocalizedString();

  const field = {
    name: { ru: 'Имя', en: 'Name' },
    description: { ru: 'Описание', en: 'Description' },
  };

  return (
    <div>
      <h1>{localize(field.name)}</h1>
      <p>{localize(field.description)}</p>
    </div>
  );
}

Example (с резервным языком)

import { useLocalizedString } from '@weavix/tracker-plugin-sdk-react';

function MyComponent() {
  // Если перевод на текущем языке не найден, используется русский
  const localize = useLocalizedString('ru');

  const name = { en: 'Name' }; // нет русского перевода

  return <div>{localize(name)}</div>; // вернет 'Name'
}

Example (работа с полями задачи)

import {
  useLocalizedString,
  useTrackerPluginContext,
} from '@weavix/tracker-plugin-sdk-react';
import { trackerApi } from '@weavix/tracker-plugin-sdk-react';

function FieldsList() {
  const localize = useLocalizedString();
  const { slotContext } = useTrackerPluginContext<'issue.action'>();
  const [fields, setFields] = useState([]);

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

  return (
    <ul>
      {fields.map((field) => (
        <li key={field.id}>
          <strong>{localize(field.name)}</strong>
          {field.description && <p>{localize(field.description)}</p>}
        </li>
      ))}
    </ul>
  );
}

useToaster

Хук для показа toast-уведомлений в интерфейсе Трекера. Возвращает объект с методом add.

Permission: в manifest.json нужно запросить tracker:ui:toaster:

{
    "permissions": {
        "ui": ["toaster"]
    }
}

Пример:

import { useToaster } from '@weavix/tracker-plugin-sdk-react';

function MyComponent() {
  const toaster = useToaster();

  const handleSave = async () => {
    await saveData();
    toaster.add({
      title: 'Сохранено',
      theme: 'success',
    });
  };

  const handleDelete = async () => {
    await deleteItem(id);
    toaster.add({
      title: 'Удалено',
      theme: 'info',
      content: 'QUEUE-123',
      actions: [
        {
          label: 'Отменить',
          onClick: () => restoreItem(id),
        },
      ],
    });
  };

  return (
    <div>
      <button onClick={handleSave}>Сохранить</button>
      <button onClick={handleDelete}>Удалить</button>
    </div>
  );
}

Полный список параметров add(options) — в core.

useConfirm

Плагин может показать модальный диалог подтверждения. Диалог рендерится на стороне трекера, а не внутри iframe, поэтому перекрывает всё приложение и фокусирует пользователя на принятии решения.

Permission: в manifest.json нужно запросить tracker:ui:confirm:

{
    "permissions": {
        "ui": ["confirm"]
    }
}

Пример:

import { useConfirm } from '@weavix/tracker-plugin-sdk-react';

function DeleteButton() {
    const confirm = useConfirm();

    const handleClick = async () => {
        const { confirmed } = await confirm.show({
            title: 'Удаление',
            message: 'Уверены что хотите удалить? Действие необратимо.',
            textButtonApply: 'Удалить',
            textButtonCancel: 'Отмена',
            theme: 'danger',
        });

        if (confirmed) {
            // выполняем действие
        }
    };

    return <button onClick={handleClick}>Удалить</button>;
}

Полный список параметров — в core.

Types

TrackerPluginProviderProps

Свойства компонента TrackerPluginProvider.

interface TrackerPluginProviderProps {
  /** Дочерние элементы */
  children: ReactNode;

  /**
   * Автоматически изменять размер контейнера плагина при изменении содержимого
   * @default true
   */
  autoResize?: boolean;

  /**
   * Компонент для отображения во время инициализации
   * @default <PluginLoader />
   */
  fallback?: ReactNode;

  /**
   * Компонент для отображения при ошибке инициализации
   * @default <PluginError error={error} />
   */
  errorFallback?: (error: Error) => ReactNode;

  /**
   * Автоматически уведомить Трекер о готовности плагина после инициализации
   * @default true
   */
  autoNotifyReady?: boolean;
}

Properties

Свойство

Тип

Обязательное

По умолчанию

Описание

children

ReactNode

Да

—

Дочерние компоненты, которые будут отрендерены после успешной инициализации

autoResize

boolean

Нет

true

Автоматически изменять размер контейнера плагина при изменении содержимого. Включает отслеживание изменений DOM и автоматическую отправку новой высоты Трекеру

fallback

ReactNode

Нет

Встроенный компонент <PluginLoader />

Компонент, отображаемый во время инициализации плагина

errorFallback

(error: Error) =>
  ReactNode

Нет

Встроенный компонент

<PluginError
error={error} />

Функция, возвращающая компонент для отображения при ошибке инициализации

autoNotifyReady

boolean

Нет

true

Автоматически уведомлять Трекер о готовности плагина после инициализации

Примеры использования свойств — в разделе Components выше.

Элементы с относительной высотой

Если вы используете элементы с относительной высотой (vh, % и т.п.), то автоматическое изменение размеров (autoResize) может вести себя неожиданно.
Если же вы все-таки хотите использовать компоненты с относительной высотой, то выключите автоматическое изменение размеров.

TrackerPluginContextValue

Значение контекста, предоставляемое TrackerPluginProvider. Тип slotContext зависит от запрошенного уровня контекста (level).

BasicTrackerPluginContextValue

Возвращается при level: 'basic'. slotContext содержит только идентификатор сущности и базовые метаданные.

interface BasicTrackerPluginContextValue<TSlot extends keyof SlotContextMap = keyof SlotContextMap> {
  theme: Theme;
  language: string;
  /** Имя слота, в котором открыт плагин */
  slot: TSlot;
  /** Базовый контекст слота */
  slotContext: {
    /** Идентификатор текущей сущности */
    entityId: string;
    /** Дополнительная базовая информация.
     *  Например, для комментария содержит идентификатор родительского тикета. */
    entityMeta?: Record<string, string>;
  };
}

FullTrackerPluginContextValue

Возвращается при level: 'full'. slotContext содержит полные данные сущности (формат совпадает с типами публичного API).

interface FullTrackerPluginContextValue<TSlot extends keyof SlotContextMap = keyof SlotContextMap> {
  theme: Theme;
  language: string;
  /** Имя слота, в котором открыт плагин */
  slot: TSlot;
  /** Полный контекст слота (зависит от типа слота) */
  slotContext: SlotContextMap[TSlot];
}

Properties (общие для обоих типов)

Свойство

Тип

Описание

Theme ('light' | 'light-hc'
  | 'dark' | 'dark-hc' | 'system')

string

TSlot (ключ из SlotContextMap)

{ entityId: string;
  entityMeta?: Record<string, string> }

при level: 'basic',
SlotContextMap[TSlot] при level: 'full'

Example (basic)

const { theme, language, slotContext } = useTrackerPluginContext<'issue.action'>('basic');
const isDark = theme === 'dark' || theme === 'dark-hc';
console.log(slotContext.entityId); // 'abc123'
console.log(slotContext.entityMeta); // { issueId: 'QUEUE-123' } — для комментария

Example (full)

// В manifest.json для слота: contextLevel: "full"
const { slotContext } = useTrackerPluginContext<'issue.action'>('full');
console.log(slotContext.key); // 'QUEUE-123'
console.log(slotContext.version); // 42

Публичное API

Пакет @weavix/tracker-plugin-sdk-react реэкспортирует hostApi, trackerApi, storageApi и типы из @weavix/tracker-plugin-sdk-core.

  • hostApi — взаимодействие с приложением Трекера: инициализация, тема, язык, контекст слота, размер окна, notifyReady(). Подробнее в API Reference core.
  • trackerApi — вызовы Tracker Public API через типизированное API v3: trackerApi.v3.get, trackerApi.v3.post, trackerApi.v3.put, trackerApi.v3.patch, trackerApi.v3.delete. Ключи — пути эндпоинтов с автоподсказкой и JSDoc из @weavix/tracker-api-types. Описание методов и форматов: Common format.
  • storageApi — JSON-хранилище плагина уровня организации. Подробнее: Хранилище данных.

Пример

import { trackerApi } from '@weavix/tracker-plugin-sdk-react';

const issue = await trackerApi.v3.get['/issues/{id}']({
  pathParams: { id: 'KEY-1' },
  queryParams: { expand: ['COMMENTS'] },
});

Тема, язык и контекст слота доступны через useTrackerPluginContext. Инициализация и уведомление Трекера — через hostApi или внутри TrackerPluginProvider. Вызовы эндпоинтов Tracker — через trackerApi.v3.

Полная документация по API (типы, коды ошибок, утилиты):

API Reference — @weavix/tracker-plugin-sdk-core

Утилиты

getLocalizedString

Получает локализованную строку на основе языка. Полезно для локализации вне React-компонентов или когда нужен прямой контроль над языком.

Type Signature

function getLocalizedString(
  value: LocalizedString,
  language: string,
  fallbackLanguage?: string,
): string;

Parameters

  • value - LocalizedString - локализованная строка (может быть строкой или объектом с переводами)
  • language - string - код языка ('ru' или 'en')
  • fallbackLanguage - string (опционально, по умолчанию 'en') - резервный язык, если основной не найден

Returns

string - локализованная строка на указанном языке.

Example (базовое использование)

import { getLocalizedString } from '@weavix/tracker-plugin-sdk-react';
import type { LocalizedString } from '@weavix/tracker-plugin-sdk-react';

function getFieldName(name: LocalizedString, language: string): string {
  return getLocalizedString(name, language);
}
// language можно получить из useTrackerPluginContext() в компоненте

const name = { ru: 'Название', en: 'Summary' };
const localizedName = getFieldName(name, 'ru');
console.log(localizedName); // 'Название'

Example (с резервным языком)

import { getLocalizedString } from '@weavix/tracker-plugin-sdk-react';

// Если перевод на русский отсутствует, используется английский
const partial = { en: 'Name' };
const name = getLocalizedString(partial, 'ru', 'en');
console.log(name); // 'Name'

// Если передана простая строка, она возвращается как есть
const simple = 'Simple string';
const result = getLocalizedString(simple, 'ru');
console.log(result); // 'Simple string'

Example (в обработчике событий)

import {
  getLocalizedString,
  useTrackerPluginContext,
} from '@weavix/tracker-plugin-sdk-react';
import type { LocalizedString } from '@weavix/tracker-plugin-sdk-react';

type FieldWithName = { id: string; name: LocalizedString };

function FieldSelector({ fields }: { fields: FieldWithName[] }) {
  const { language } = useTrackerPluginContext();
  const handleFieldSelect = (field: FieldWithName) => {
    const localizedName = getLocalizedString(field.name, language);
    alert(`Выбрано поле: ${localizedName}`);
  };

  return (
    <ul>
      {fields.map((field) => (
        <li key={field.id} onClick={() => handleFieldSelect(field)}>
          {field.id}
        </li>
      ))}
    </ul>
  );
}

Примечание

В React-компонентах предпочтительнее использовать хук useLocalizedString, который автоматически получает язык из контекста:

import { useLocalizedString } from '@weavix/tracker-plugin-sdk-react';

function MyComponent() {
  const localize = useLocalizedString();

  const field = { name: { ru: 'Название', en: 'Title' } };
  return <div>{localize(field.name)}</div>;
}
Предыдущая