Перейти к основному содержимому

Взаимодействие компонента Gant с бэкенд-сервисами

Компонент Gant поддерживает следующие способы взаимодействия с бэкенд-сервисами:

  • REST API;
  • веб-сокеты.

REST API

По умолчанию используется взаимодействие через REST API.

В свойстве endpointData, вложенном в свойство GraphSettings, должен быть описан метод fetch по следующему образцу:

const fetch = async ({ requestType, params }) => {
return sendDataSet(requestType, params, { showWaitingContainer: false });
};

requestType описывает тип запроса и принимает значения, описанные в следующей таблице.

Контракты взаимодействия с бэкенд-сервисами

Тип запросаВыполняемое действие
getCount(): numberВозвращает количество работ
getIds(skip: number, take: number): INodeIdWithVersion[]Возвращает массив работ в диапазоне строк с идентификаторами и версиями
getData(nodes: INodeIdWithVersion[], columns: ColumnId[]): IDataResult[]Возвращает значения в указанных столбцах по указанным работам
getFilterState(nodes: INodeIdWithVersion[], filters: Filters): IFilterState[]Возвращает признак того, удовлетворяет ли работа параметрам фильтра
getGraph(nodes: INodeIdWithVersion[]): IDataResult[]Возвращает полосы диаграммы Ганта
getRelations(nodes: INodeIdWithVersion[]): IRelationsResult[]Возвращает стрелки диаграммы Ганта
getMetrics(nodes: INodeIdWithVersion[], columns: ColumnId[], scale: CalendarScale, from: string, to: string): IDataResult[]Возвращает значения в календарной сетке, сгруппированные по датам
getRowsUpdateSince(skip: number, take: number, since: number): GetRowsUpdateSinceResultВозвращает список работ (с идентификаторами и версиями), изменившихся с определенного момента

Данные для компонента Gant могут иметь объем в сотни тысяч записей в базе данных. При использовании взаимодействия с бэкенд-ервисами через REST API объем передаваемых данных ограничен. Для преодоления этого ограничения данные компоненту передаются частями размером chunkSize и отправляются на сервер в количестве не более requestsLimit запросов одновременно.

Следующий блок кода демонстрирует свойства компонента для управления передачей данных при взаимодействии через REST API с бэкенд-сервисами. В примере показаны значения по умолчанию.

chunkSize: 10000,
requestsLimit: 2,

Следующий блок кода экранной формы демонстрирует взаимодействие компонента Gant с бэкенд-сервисами через REST API.

<Container
Name="GantRest"
ContainerType="Page"
Scripts={[
async () => {
const viewModel = await sendDataSet('getViewModel');
const { mainGridId, tables, filterOperations } = viewModel.model;

const fetch = async ({ requestType, params }) => {
return sendDataSet(requestType, params, { showWaitingContainer: false });
};

const settings = {};
settings.groupingVisible = true;
settings.headers = tables[mainGridId].columns;
// максимально возможная глубина вложенности, приходит с бэкенда.
// чем она меньше - тем выше контрастность между цветами уровней
// однако можно задать индивидуальные цвета для каждого уровня
// с помощью свойств getLevelBGColor и getLevelTextColor.
// наличие этого свойства также важно для правильного выделения цветом кликнутой строки
settings.maxDeepLevel = tables[mainGridId].maxDeepLevel + 1;
settings.endpointData = { fetch };
// во viewModel должны прийти поддерживаемые бэкендом операции фильтрации,
// но можно просто передать {}, тогда будут использоваться дефолтные
// более подробное описание в контракте
settings.filterOperations = filterOperations;
// поиск пока реализован только по строковым колонкам
settings.searchEnabled = true;
// отображение контрола разворота узлов до определенного уровня
settings.wbsEnabled = true;

const graphSettings = {};
graphSettings[mainGridId] = settings;

const pallete = {};
// ширина смещения уровня в пикселях
pallete.stripeWidth = 15;
// задание индивидуальных цветов уровням
// pallete.getLevelBGColor = (level, maxLevel) => {
// const levels = {
// 0: '#BBBBBB',
// 4: 'red',
// 20: 'rgba(1, 1, 1, 0.5)',
// };
// return levels[level];
// };
// pallete.getLevelTextColor = (level, maxLevel) => level > maxLevel / 2 ? 'red' : 'black';

setState({ mainGridId, graphSettings, pallete });
},
]}
>
<Gant
Visible-var="mainGridId"
Pallete-var="pallete"
MainGridId-var="mainGridId"
GraphSettings-var="graphSettings"
/>
</Container>;

Веб-сокеты

Для переключения на взаимодействие через веб-сокеты, в свойство endpointData, вложенное в свойство GraphSettings, должен быть передан параметр networkServiceType: 'socket'.

В свойстве endpointData, вложенном в свойство GraphSettings, должен быть описан метод stream по следующему образцу:

const stream = p => {
return {
stream: connection.stream(p.requestType, p?.params || {}),
postProcess: data => data,
};
};

requestType описывает тип запроса и принимает значения, описанные в следующей таблице.

Контракты взаимодействия с бэкенд-сервисами

Тип запросаВыполняемое действие
getData(nodes: Nullable<INodeIdWithVersion[]>, columns: ColumnId[], useZip?: boolean, since?: number): SocketDataResultВозвращает значения в указанных столбцах по указанным работам
getFilterState(nodes: Nullable<INodeIdWithVersion[]>, filters: Filters): IFilterState[]Возвращает признак того, удовлетворяет ли работа параметрам фильтра

Взаимодействие с бэкенд-сервисами через веб-сокеты происходит быстрее, чем через REST API.

При использовании взаимодействия через веб-сокеты можно включить кэширование данных на клиентской стороне. Для включения кэширования используется свойство cache, вложенное в GraphSettings. Данные сохраняются в хранилище данных внутри браузера — IndexedDB. При обновлении версии компонента Gant содержимое кэша сбрасывается.

Поскольку взаимодействие через веб-сокеты является ненадежным, для контроля целостности данных компонент Gant периодически запрашивает через REST API все работы, которые изменились с момента последнего обновления кэша. С этой целью компонент Gant отправляет запрос getRowsUpdateSince (см. описание в разделе выше). В связи с большим объемом данных, например, вследствие массового импорта данных из внешней системы, данные отправляются клиенту постранично. Для управления разбивкой на страницы используются параметры skip и take запроса getRowsUpdateSince. Метод возвращает работы, у которых значение параметра since больше переданного значения, и количество таких работ.

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

Идентификатор
работы
Версия
работы
Версия моментального
снимка БД
Комментарий
111Работы 1, 2, 3 и 4 появились в БД при генерации данных.
Начальные значения версии для этих работ — 1 и значение моментального снимка БД — 1.
222Пользователь изменил работу 2, в результате чего работа 2
получила версию 2, версия моментального снимка БД приняла значение 2.
323Далее в одной транзакции пользователь изменил работы 3 и 4. Обе работы получили версию 2.
423Версия моментального снимка БД приняла значение 3.
514Далее в следующей транзакции пользователь создал работу 5.
Версия работы 5 — 1, версия моментального снимка БД приняла значение 4.

Следующий блок кода демонстрирует настройку параметров для использования метода getRowsUpdateSince с периодичностью timeoutUpdateSince.

timeoutUpdateSince: 60000,              // частота отправки запроса данных в миллисекундах
checkMissedNotificationsEnabled: true, // при установке в true этого параметра используется тип запроса getRowsUpdateSince

Следующий блок кода экранной формы демонстрирует взаимодействие компонента Gant с бэкенд-сервисами через веб-сокеты.

<Container
Name="GantSocket"
ContainerType="Page"
Scripts={[
async () => {
const viewModel = await sendDataSet('getViewModel');
const { mainGridId, tables } = viewModel.model;

const connection = createConnection({
hubUrl: '',
eventName: '',
});

const stream = p => {
return {
stream: connection.stream(p.requestType, p?.params || {}),
postProcess: data => data,
};
};

const settings = {};
settings.headers = tables[mainGridId].columns;
settings.maxDeepLevel = tables[mainGridId].maxDeepLevel + 1;
settings.endpointData = {};
settings.endpointData.stream = stream;
settings.endpointData.onEditTransactionUpdate = () => {};
settings.endpointData.networkServiceType = 'socket';
settings.filterOperations = {};
settings.wbsEnabled = true;

const graphSettings = {};
graphSettings[mainGridId] = settings;

setState({ mainGridId, graphSettings });
},
]}
>
<Gant
Visible-var="mainGridId"
Pallete={{}}
MainGridId-var="mainGridId"
GraphSettings-var="graphSettings"
/>
</Container>;