Инструкция по созданию плагина визуализации (с примерами кода из готового проекта) - Публичная база знаний Modus
Описанная ниже инструкция по созданию плагина представлена также в виде видео — .
Подготовка окружения и запуск проекта
Перейдите на репозиторий GitHub, в нем загружена ветка reference-universal — стартовая точка для разработки с нуля (дефолтные версии всех модулей).
Создайте клон репозитория через интерфейс редактора.


После загрузки проекта запустите npm install.

Перед запуском dev-сервера надо убедиться, что в папке prebuild располагается сборка ядра портала.
Примечание — сборку ядра портала можно скачать в виде zip-архива в настройках портала, нажав на кнопку «Скачать Frontend». Далее этот архив нужно разархивировать в папку prebuild.

Перейдите в package.json. Запустите dev-сервер при помощи скрипта start:dev.
Примечание — версия node в вашей системе должна соответствовать указанной в package.json, иначе возможны ошибки при запуске скриптов.

Примечание — цикл разработки плагина осуществляется при помощи скриптов. Основные:
- start:dev — запускает портал в режиме разработчика, в этом режиме код можно отлаживать;
- build:prod — собирает плагин для продакшена;
- build:plugin — берет сборку плагина и заполненный файл манифеста, создает дистрибутив плагина, готовый для загрузки в портал.
Откройте пустой отчет на localhost:7000, перейдите в редактор компонента отчета.
В списке визуализаций появится плитка DEV — это ваш будущий плагин. Перетащите ее в область «Компонент отображения не задан».

Визуализации пока нет, так как она ещё без функционала. В боковой части, в настройках компонента, по умолчанию добавлены разделы «Общие настройки», «Данные», «Инфо», «Рамка компонента». Эти разделы характерны для всех визуализаций.

Добавленный в отчет компонент DEV необходимо сохранить, а затем сохранить и сам отчет. Все изменения, вносимые в плагин, будут видны после обновления localhost:7000.
Так как весь код дефолтный, далее необходимо создать новую ветку. В этой ветке начните разработку вашего плагина.

Для начала убедитесь, что код рендеринга влияет на то, что отображается в портале.
Раскройте src/modules и зайдите в модуль CustomChart. Там подключён CommandChartAdapter, в который вынесена вся логика по запросу данных. Сам рендеринг вынесен в Content.js, куда после dataAdaptor приходят все нужные пропсы.
Для проверки в Content.js попробуйте, например, вернуть «HELLO WORLD» через return:
return (
<div>HELLO WORLD</div>
);
}

Обновите localhost:7000 — произойдет пересборка проекта плагина. В области предпросмотра компонента отобразится «HELLO WORLD».

Добавление пользовательских настроек и кастомизация интерфейса
Для изменения заголовка компонента и названия типа компонента перейдите в defaultConfig.json и измените значения в title и chartType:
{
"title": "Example Chart",
"subtitle": "",
"chartType": "exampleChart",
"showtitle": true,
"noexport": false,
"nocopy": false,
"filterMode": false,
"bigNumberClasses": [],
"margin": {
"l": 15,
"r": 15,
"t": 15,
"b": 0,
"pad": 0
},

Обновите localhost:7000 — в разделе «Общие настройки» отобразится введенный заголовок.

Далее можно более существенно изменить CustomChart, например, настроить вывод в компоненте данных, которые приходят через plotData.
Перейдите в Content.js, из приложенных заготовок в самом файле перенесите представленный кусок кода внутрь return (раньше там был «HELLO WORLD»):
return (
<div style={{
background: config.backgroundColor,
height: '100%',
overflow: 'auto'
}}>
<pre>{JSON.stringify(plotData, 0, 2)}</pre>
</div>
);
}

Обновите localhost:7000.
Пояснение к коду: этот фрагмент заменяет статический текст на отображение сырых данных (plotData) в виде JSON. Теперь при изменении полей в полках компонента будут меняться и отображаемые данные, как показано на рисунках ниже.


Далее попробуйте изменить CustomReducers и CustomSettings (они работают в связке) для добавления настройки изменения цвета фона компонента.
Перейдите в CustomSettings/MainOptions.js. Добавьте следующий код из заготовок файла MainOptions.js:
<SettingsItem type='inline' title='Цвет фона'>
<SettingsColorPicker
float='right'
color={config.backgroundColor === 'transparent' ? undefined : config.backgroundColor}
onChange={(value) => changeChart('setBackgroundColor', { value })}
/>
</SettingsItem>

Со стороны CustomReducers необходимо добавить обработчик команды setBackgroundColor. Для этого перейдите в CustomReducers/changeCustomChartReducer.js и добавьте следующий код из заготовок самого файла:
if (action.command === 'setBackgroundColor') {
configNew.backgroundColor = action.settings.value;
}

Пояснение к коду: этот код позволяет менять цвет фона компонента. Когда вы выбираете цвет в палитре, срабатывает обработчик onChange, который отправляет команду setBackgroundColor. Затем обработчик (редьюсер react) сохраняет выбранный цвет в настройках, и после обновления компонента фон меняется на новый цвет.
Обновите localhost:7000 — в разделе «Общие настройки» появится добавленное поле «Цвет фона».

Далее попробуйте настроить панели полок компонента через CustomAxes. Через него вы можете подключать новые полки, настраивать состав пилюль на полках, а также их иконки. Попробуйте настроить иконку полки «Серии». Перейдите в CustomAxes/index.js, найдите рендер, связанный с icons. На основе копирования categories добавьте series, не забудьте изменить className и title для серий:
export function renderAxeIcon(props) {
const { axe, field, config, componentType, axisNames, HsMuiFontIcon, HsMuiSvgIcon } = props;
const icons = {
categories: (
<HsMuiFontIcon className='fa fa-bars' title={axisNames.categories} style={{ transform: 'rotate(90deg)' }} />
),
series: (
<HsMuiFontIcon className='fa fa-square' title={axisNames.series} style={{ transform: 'rotate(90deg)' }} />
),
values: <HsMuiFontIcon className='fa fa-bars' title={axisNames.values} />,
};
return icons[axe.type];
}

Обновите localhost:7000. Напротив полки «Серии» отобразится иконка квадрата, а при наведении — заголовок полки.

Построение собственной визуализации (на примере гистограммы)
Теперь попробуем построить визуализацию, которая отслеживает аномалии в данных. Оно будет рассчитываться по количеству символов в значениях. Так можно выявить некоторые аномалии.
Для этого в dataAdaptor.js внутри CustomChart необходимо заменить this.plotData = structuredClone(this.aggregated); на следующее:
const data = this.aggregated?.[0];
const total = data?.length || 0;
if (!total) return [];
const letterCount = (item) => {
return (item?.values + '').length;
};
const countsByLen = new Map();
for (const item of data) {
const len = letterCount(item);
countsByLen.set(len, (countsByLen.get(len) || 0) + 1);
}
this.plotData = Array.from(countsByLen.entries())
.sort((a, b) => a[0] - b[0])
.map(([len, count]) => ({
len,
count,
percent: (count / total) * 100,
}));
Представленный выше код уже есть в файле dataAdaptor.js в качестве альтернативного варианта (закомментирован).

Пояснение к коду: этот код преобразует исходные данные aggregated в массив, где для каждой длины строки (количество символов в значении) подсчитывается количество таких значений и их процент от общего числа. Полученный массив содержит поля len, count и percent, которые далее используются для построения гистограммы.
Далее в Content.js необходимо изменить часть, относящуюся к рендерингу. Будет отрисована горизонтальная гистограмма на основе данных, которые приходят через plotData из dataAdaptor.js. Нужный для этого код уже есть в файле Content.js как заготовка – вы можете просто скопировать его оттуда, заменив предыдущий return:
return (
<div
style={{
background: config.backgroundColor,
height: '100%',
overflow: 'auto',
padding: 10,
}}
>
<div style={{ display: 'grid', gap: 10 }}>
{plotData.map((r) => (
<div
key={r.len}
style={{
display: 'grid',
gridTemplateColumns: '20px 1fr 72px',
gap: 10,
alignItems: 'center',
}}
>
<div style={{ whiteSpace: 'nowrap' }}>{r.len}</div>
<div
style={{
height: 12,
background: '#ffffff',
borderRadius: 12,
overflow: 'hidden',
}}
>
<div
style={{
height: '100%',
width: `${Math.round(r.percent * 10) / 10}%`,
background: '#4c84ff',
borderRadius: 12,
}}
/>
</div>
<div style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>
{`${(Math.round(r.percent * 10) / 10).toFixed(1)}%`}
</div>
</div>
))}
</div>
</div>
);
}

Обновите localhost:7000. Получится следующая визуализация:
При изменении в настройках визуализации полей внутри полок происходит изменение самой визуализации, как показано на рисунках ниже.


Рассмотрены все этапы, которые могут возникнуть при создании плагина. Плагин готов, далее необходимо собрать дистрибутив.
Сборка дистрибутива и установка плагина в портал
Перейдите в файл package.json и запустите build:prod.

После окончания процесса появится папка build, внутри которой будет располагаться файл plugin.js. Наименование файла перед сборкой дистрибутива изменять не нужно.
Также необходимо добавить манифест. Добавьте в папку build файл манифеста manifest.json. Скопируйте в него содержимое файла manifest.example.js (это заранее созданный пример манифеста). В скопированном тексте манифеста необходимо изменить следующее:
- name — название, которое будет выводиться в интерфейсе;
- apiVersion — актуальная версия API;
- description — описание.

Теперь можно запускать сборку дистрибутива: перейдите в файл package.json и запустите build:plugin.

Появится example.tar.gz — необходимый архив плагина.

Примечание — загрузка плагина на бэкенд происходит через админ-интерфейс в виде архива .tar.gz. После загрузки сервер распаковывает архив и выполняет проверку: наличие всех компонентов, корректность манифеста, целостность данных, а также отсутствие конфликтов имён с уже установленными визуализациями. Если все проверки пройдены успешно, ассеты плагина перемещаются в отдельное пространство для статических ресурсов. Здесь они обслуживаются независимо от основного приложения. Каждому плагину присваивается версия для контроля изменений, а доступ к управлению регулируется системой прав: разные пользователи могут иметь права только на загрузку плагинов или только на их активацию в продакшн-среде. Только после полного прохождения этого процесса плагин считается установленным и готовым к использованию.
Схематично процесс выглядит так:

Теперь необходимо добавить данный архив в портал, подробнее про добавление пользовательских компонентов в разделе «Компоненты Аналитического портала».

Теперь в типах отображения компонентов при редактировании отчета появится добавленный компонент, который можно использовать в отчете.






