Frontend. Работа с точками расширения

Общее описание

Точки расширения (User Exits, UE) представляют собой программный код на языке TypeScript, выполняемый при наступлении определенного события.

User Exits применяются при необходимости выполнения каких-либо нестандартных действий, выходящих за рамки возможностей системы. Например, если для выполнения операции вставки необходима отправка особого уведомления, содержащего аутентификационные данные для последующей авторизации в сторонней системе.

Полный список User Exits вы можете найти в модуле types в src/declareUe.ts (автогенерируемый файл). Он обновляется после каждой команды npm ci или npm run dev.

Описания точек расширения:

Динамическая загрузка точек расширения

Доступно добавление точек расширения в запущенное приложение Юниверс.

Шаг 1. Создайте файл с кастомизацией, который экспортирует настройки UE. Рекомендуется расширение файла .ts, но можно использовать и .js. Требований к имени и расположению файла нет. Пример:

export const CustomAttributeOnDataCard: UniverseUE.IUeMeta['RenderAttributeOnDataCard'] = { // UniverseUE - глобальный namespace, IUeMeta - интерфейс, описывающий все доступные UE, где ключами выступают их типы.
   moduleId: '', // Уникальный идентификатор UE (человекочитаемый или uuid - на ваш выбор)
   active: true, // Флаг, показывающий что UE активен и будет применяться
   system: false,
   resolver: () => true, // Функция, определяющая вызывать UE на исполнение или нет. В случае рендеринга атрибута имеет следующий тип - type Resolver = (attribute: IMetaAbstractAttribute, model: AbstractModel) => boolean;, где IMetaAbstractAttribute тип из SDK продукта, а AbstractModel - из общего SDK
   meta: {} // Доп параметры - например, displayName: () => string, которая определит label атрибута в карточке
   component: Component // Реализация UE - сам реакт компонент
};

Шаг 2. Создайте индексный файл, объединяющий кастомизации проекта/направления. Он должен экспортировать по умолчанию список точек расширения. Тип UE можно посмотреть в @universe-platform/user-exit в пакете (IUeModuleBase). Пример:

import {CustomAttributeOnDataCard} from '...';

export default {
userExits: [
   {
      type: 'RenderAttributeOnDataCard', // Строка, определенная типом UniverseUE.UeTypes (один из ключей интерфейса UniverseUE.IUeMeta).
      CustomAttributeOnDataCard
   },
]
}

Шаг 3. Добавьте список путей до файла(ов) с кастомизациями в файл customer.json: поле EXTERNAL_MODULES.

Шаг 4. В результате при загрузке приложения содержимое этих UE добавляется в ueModuleManager.

При работе приложения через Docker можно определить путь до каталога со списком UE на хостовой машине через переменную окружения FRONTEND_UE. Этот каталог будет смонтирован в каталог CUX в рутовом каталоге для nginx FE, то есть в EXTERNAL_MODULES пути до файлов должны будут начинаться с CUX.

Пример из docker-compose.yml:

docker-compose.yml
   volumes:
      - ${FRONTEND_UE:-/dev/null}:/usr/share/nginx/html/CUX

Пример из customer.json:

customer.json
   "EXTERNAL_MODULES": [
      "/CUX/index.es.js"
   ],

Создание собственной точки расширения

User exits должны создаваться как модули. При этом в них будут доступны некоторые externals в объекте window.

Ниже представлены рекомендации по работе с динамическими UE. Рекомендации основаны на UE кастомизации карточки записи.

Шаг 1. Создайте отдельный проект. Установите devDependencies (сейчас глобально доступны только React, Mobx, @universe-platform/uikit и @universe-platform/sdk). React, Mobx, @universe-platform/uikit установятся вместе с SDK, указывать их не нужно.

npm i @universe-platform/ui-cli @universe-platform/sdk --save-dev

Шаг 2. Исходные файлы должны располагаться в src. Обязательно нужен index.ts, в котором возвращаем user exits.

import {Component} from './Component';

export default {
   userExits: [{
      moduleId: 'testUE',
      type: 'DataCardMenuItem',
      active: true,
      system: false,
      resolver: () => true,
      meta: {},
      component: Component
   }]
}

Шаг 3. При создании компонента импортируйте пакеты через import. Средствами сборки они заменятся на const n = window.React, s = window["@unidata/uikit"].Button, i = window.Universe.i18n.

Пример src/Component.tsx:

import * as React from 'react';
import {Button} from '@unidata/uikit';
import {i18n} from '@universe-platform/sdk';

export class Component extends React.Component<any> {
   get dataRecord () {
      return this.props.dataCardStore.dataRecordStore.getDataEntity();
   }

   get metaRecord () {
      return this.props.dataCardStore.metaRecordStore.getMetaEntity();
   }

   handleDelete = (wipe: boolean) => {
      return this.props.dataCardStore.handleDelete(wipe);
   };

   override render () {

      return (
            <Button>
               {i18n.t('some new delete button')}
            </Button>
      );
   }
}

Шаг 4. Далее необходимо добавить файл tsconfig.json со следующим содержимым:

{
"extends": "./node_modules/@universe-platform/ui-cli/vite/tsconfig.json",
"include": ["src"]
}

Шаг 5. Для сборки добавьте скрипт в package.json. Полученный файл будет в каталоге dist. Его можно будет подкладывать в каталог CUX из предыдущего раздела.

{
   "scripts": {
      "build": "npx tsc && npx vite build --config node_modules/@universe-platform/ui-cli/vite/vite.external.config.ts"
   }
}