10 Модули bi-internal
Это набор именованных модулей, в которые собираются различные сервисы, контроллеры и компоненты, которые экспортирует веб-клиент, чтобы ваш кастомный компонент мог использовать нативные методы для реализации какого-либо функционала.
Существует публичный проект на Github:
https://github.com/luxms/bi-internal
В нем содержится типизация и базовые комментарии к каждому модулю семейства bi-internal
.
Данный проект периодически актуализируется по мере наших сил, но к сожалению, он всегда будет отставать от того, что есть в наличии в текущей версии веб-клиента.
Перечень экспортируемых модулей семейства bi-internal
:
bi-internal/core
bi-internal/types
bi-internal/face
bi-internal/root
bi-internal/services
bi-internal/ds-helpers
bi-internal/ui
bi-internal/utils
Рассмотрим каждый подробнее:
bi-internal/core
Модуль содержит в себе базовые классы и компоненты, ключевые для веб-клиента.
Модуль частично описан на Github
В клиенте этот модуль выглядит так:
const core = require('@luxms/bi-core');
module.exports = core;
сам bi-core индекс-файл
export * from './singleton';
export * from './Retainable';
export * from './Observable';
export * from './BaseService';
export * from './UrlState/UrlState';
export * from './extractErrorMessage';
export { AppConfig } from './AppConfig';
export { AuthenticationService, IAuthentication } from './AuthenticationService';
export { BaseEntitiesService, IBaseEntities } from './services/BaseEntitiesService';
export * from './RtService';
import * as repo from './repositories';
import * as srv from './services';
export { repo, srv };
Модуль описан на Github, но дам ряд комментариев:
Observable, Retainable, BaseService
- вводит описание Observable и базового класса, работающего на нем. Все Observable-сервисы (ОС) есть наследники BaseService
.
AppConfig
- сервис ОС, синглтон, который хранит конфигурацию инстанса, пришедшую из файла настроек settings.js
(/opt/luxmsbi/web/settings/settings.js
на сервере по умолчанию). Есть информация о текущей локализации, фичах, темах (одно из мест, где можно хранить информацию о них), опции и базовые настройки для карт на leaflet
(сервер для тайлов, например).
UrlState
- сервис ОС, синглтон, хранящий модель и методы работы с урлом приложения. Позволяет делать навигацию, хранить в модели отображаемые в урле и скрытые параметры или данные. Критичен для работы над презентациями. Каждая модель такого инстанса, чтобы вы в ней не сохранили перед добавлением страницы в перезентацию восстановит состояние, которое было на момент добавления, на сервере и отрисует ее в виде картинки для .pdf
или .pptx
AuthenticationService
- сервис ОС, синглтон, который в модели хранит информацию о текущем залогиненном пользователе. Его id, роль, юзернейм, почту, конфигурацию и статус аутентификации.
Содержит методы для авторизации и деавторизации. А также методы работы с двухфакторной авторизацией
repo
- хранилище репозиториев. Это паттерны, реализующие способы выполнить запросы за различными сущностями, в зависимости от контекста и без оглядки на то, как такой запрос реализуется в клиенте.
srv
- хранилище сервисов, позволяющих загрузить сущности (энтити), в зависимости от контекста, без знания API. Кубы, дименшны, локации, метрики, периоды, дешлеты, дешборды и другое.
Пример подключения элементов модуля core
в конкретном компоненте:
import {UrlState, BaseService, AppConfig, AuthenticationService, repo, srv} from 'bi-internal/core';
bi-internal/types
Модуль, хранящий описание интерфейсов различных энтити, но не связанных с кубами.
Модуль частично описан на Github
в клиенте этот модуль выглядит так:
const types = require('../../services/ds/types');
module.exports = types;
Сам файл types
:
import { data_engine } from '../../data-manip/data-manip';
import { IDisposable, IObservable, IUrl } from '@luxms/bi-core';
import {
IColorResolver,
IEntity,
IGeo,
ILocation,
ILocationArea,
ILocationCard,
ILocationsHelper,
IMapFill,
IMetric,
IMetricsHelper,
IOptionsProvider,
IPeriod,
IPeriodInfo,
IPeriodsHelper,
IPreset,
IRange,
IStoplightsProvider,
ISubspace,
ISubspacePtr,
ITitleResolver,
IUnit,
IVizel,
IVizelConfigDisplay,
IVizelController, IVizelProperties,
responses,
tables
} from '../../defs/bi';
export interface IVizelConfig extends IColorResolver, ITitleResolver, IOptionsProvider, IStoplightsProvider {
dataset: IDatasetModel;
getDataset(): IDatasetModel;
getProperty(key): any;
setProperty(key: string, value: any): void;
getLegendItem(e: IEntity, idx?: number): tables.ILegendItem;
serialize(): tables.IRawVizelConfig;
clone(): IVizelConfig;
getDisplay(vizelType?: string): IVizelConfigDisplay;
getRange(): IRange;
disableRange(): void;
getUrl(): string;
getBgImage(): string;
dataSource?: tables.IDataSource;
getVizelType(): string;
setVizelType(vizelType: string): void;
setTitle(title: string): void;
getSubspacePtr(): ISubspacePtr;
controller: IVizelController;
title?: string;
description?: string;
display?: tables.IVizelConfigDisplay;
legend?: { [id: string]: tables.ILegendItem; };
badValueColor?: string;
goodValueColor?: string;
normsMainColor?: string;
onClickDataPoint?: string | any;
onClick?: string | any;
cardId?: string;
externalUrl?: IUrl;
dashboardId?: number | string;
dashId?: number | string;
normStrategy?: string;
context?: any;
titleContext?: string[];
colorResolver?: IColorResolver;
titleResolver?: ITitleResolver;
// deprecated
chartStyle: string;
showLegend: boolean;
visualMap?: any;
getRaw(): tables.IRawVizelConfig;
}
export interface IDashlet extends IEntity {
id: string;
title: string;
layout: string; // V|H|''
children: IDashlet[];
getDataset(): IDatasetModel;
getDashboard(): IDashboard;
getFrame(): tables.IConfigFrame;
getDescription(): string;
getRawVizelConfig(): tables.IRawVizelConfig;
isContainer(): boolean;
isRoot(): boolean;
}
export interface IDashletsHelper {
dashboards: IDashboard[];
dashboardTopics: tables.IDashboardTopic[];
getDashboard(id: string): IDashboard;
getDash(id: string): IDashlet;
getDashes(): IDashlet[];
}
export interface IDashboard extends IEntity {
id: string;
title: string;
topic_id: number;
stateColor: string;
getRootDashes(): IDashlet[];
getDashes(): IDashlet[];
}
export interface IConfigHelper {
hasValue(key: string): boolean;
getValue(key: string, defaultValue?: string): string;
getStringValue(key: string, defaultValue?: string): string;
getIntValue(key: string, defaultValue?: number): number;
getFloatValue(key: string, defaultValue?: number): number;
getBoolValue(key: string, defaultValue?: any): boolean;
getEnumValue(key: string, values: string[], defaultValue?: string): string;
getStringArray(key: string, defaultValue?: string[]): string[];
getIntArray(key: string, defaultValue?: number[]): number[];
getEnterUrl(datasetKey: string): IUrl;
}
export interface IDatasetModel {
id: number;
guid: string;
// deprecated
// schemaName: string;
schema_name: string;
title: string;
description: string;
units: IUnit[];
metrics: IMetric[];
rootMetrics: IMetric[];
presets: IPreset[];
locationCards: ILocationCard[];
locationAreas: ILocationArea[];
locations: ILocation[];
rootLocations: ILocation[];
periods: IPeriod[];
dashlets: tables.IDashletsItem[];
defaultMetrics: IMetric[];
defaultLocations: ILocation[];
defaultPeriods: IPeriod[];
metricsHelper: IMetricsHelper;
locationsHelper: ILocationsHelper;
periodsHelper: IPeriodsHelper;
dashletsHelper: IDashletsHelper;
getDataProvider(): data_engine.IDataProvider;
getConfigHelper(): IConfigHelper;
getEnterUrl(): IUrl;
createVizelConfig(d: tables.IRawVizelConfig, view_class?: string): IVizelConfig;
getDatasetTitleTemplate(route: string): string;
getBiQuery(): any;
// makes lookup in table config and in lang
getConfigParameter(key: string, defaultValue?: string): string;
update(datasetDescription: responses.IDatasetDescription, storage: responses.ITables): void;
getSerial(): moment.Moment;
M: (id: string) => IMetric;
L: (id: string | number) => ILocation;
P: (id: string) => IPeriod;
getPeriodInfoByRange(startId: string, endId: string, type?: number): IPeriodInfo;
}
export interface IDatasetServiceModel {
loading: boolean;
error: string;
dataset: IDatasetModel;
}
export interface IAxesOrder extends Array<string> {
xs?: string;
ys?: string;
zs?: string;
aas?: string;
abs?: string;
// etc...
}
export interface IDsState {
loading?: boolean | number;
error?: string;
//
autoscale: boolean;
chartType: string;
dash: IDashlet;
dboard: IDashboard;
geo: IGeo;
locations: ILocation[];
formulaLocations: ILocation[];
axesOrder: IAxesOrder;
mapfill: IMapFill;
metrics: IMetric[];
periodInfo: IPeriodInfo;
periods: IPeriod[];
preset: IPreset;
route: string;
mapMetricsPanelVisible: boolean;
datasetTitle: string;
datasetDescriptionHTML: string;
dataset: IDatasetModel;
customConfig: any;
}
export interface IDsStateService {
getModel(): IDsState;
getDataset(): IDatasetModel;
getMaxParametersNumber(): number;
getMaxLocationsNumber(): number;
setMetrics(ms: IMetric[]): void;
setPreset(p: IPreset): void;
setPeriods(start: IPeriod, end: IPeriod, type: number);
setFormulaLocations(ls: ILocation[]): void;
setGeo(g: IGeo): void;
setDboard(dboard: IDashboard): void;
setDash(dash: IDashlet): void;
setAxesOrder(ao: IAxesOrder): void;
setAutoscale(autoscale: boolean): void;
setMapfill(mf: IMapFill): void;
setChartType(chartType: string): void;
setCustomConfig(config: any): void;
toggleParameter(p: IMetric): void;
removeMetric(p: IMetric): void;
toggleFormulaLocation(l: ILocation): void;
removeFormulaLocation(l: ILocation): void;
goToPlots(): void;
setMapMetricsPanelVisible(mapMetricsPanelVisible: boolean): void;
subscribe(items: string, callback: any): IDisposable;
subscribeUpdates(listener: (model: IDsState) => void): IDisposable;
subscribeUpdatesAndNotify(listener: (model: IDsState) => void): IDisposable;
unsubscribe(listener: (model: IDsState) => void): void;
retain(): IDsStateService;
release(): boolean;
}
// constructor props
export interface IVizelProps {
readonly dp: data_engine.IDataProvider;
readonly cfg: IVizelConfig;
readonly subspace: ISubspace;
readonly schema_name: string;
listener?: any;
showLegend?: boolean;
onVizelPropertiesChanged?: (properties: IVizelProperties, vizel: any) => void;
properties?: IVizelProperties;
renderError?: (error: string) => any;
renderLoading?: (loading: boolean) => any;
}
export interface IVizelClass {
new(props: IVizelProps): IVizel;
}
export enum LoadingStatus {
UNDEFINED,
LOADING_FIRST_TIME,
LOADING,
NO_DATA,
HAS_DATA,
}
export interface IModuleOptions {
useSinglePeriod?: boolean;
metricsPanel?: boolean;
locationsPanel?: boolean;
periodsPanel?: boolean;
}
Пример использования в компоненте:
import {IVizelConfig, IVizelProps, IDashboard} from 'bi-internal/types';
bi-internal/face
Это модуль хранит библиотеку готовых UI-компонентов из storybook
вспомогательного модуля @luxms/bi-face
В клиенте этот модуль выглядит так:
const face = require('@luxms/bi-face');
module.exports = face;
Индексный файл таков
import Calendar from "./Calendar";
export { Calendar };
import DatePicker from "./DatePicker";
export { DatePicker };
import * as icons from "./icons";
export { icons };
import TreeComponent from "./TreeComponent";
export { TreeComponent };
import AccountTool from "./AccountTool";
export { AccountTool };
import AppLogo from "./AppLogo";
export { AppLogo };
import Button from "./Button";
export { Button };
import Confirm from "./Confirm";
export { Confirm };
import DataGrid from "./DataGrid";
export { DataGrid };
import Dropdown from "./Dropdown";
export { Dropdown };
import DropLabelList from "./DataGrid/DropLabelList";
export { DropLabelList };
import GeometryObserver from "./util/GeometryObserver";
export { GeometryObserver };
import Header from "./Header";
export { Header };
import Login from "./Login";
import LoginDemo from "./Login/LoginDemo";
export { Login, LoginDemo };
import Form from "./Form";
export { Form };
import themes from "./store/themes";
export { themes };
import Menu from "./Menu";
export { Menu };
import Strap from "./Strap";
export { Strap };
import TextEditor from "./TextEditor";
export { TextEditor };
import Tag from './Tag';
export { Tag };
import Breadcrumb from './Breadcrumb';
export { Breadcrumb };
Модуль частично описан на Github, несколько комментариев:
icons
- дает полный перечень иконок, используемых в данном проекте
GeometryObserver
- модуль позволяет назначить обработчик события ресайза какого-либо элемента на странице.
Пример использования в компоненте
import React from 'react';
import {GeometryObserver} from 'bi-internal/face';
class MyComponent extends React.Component {
private _setupContainerRef = (el: any) => {
if (this._container) return;
this._container = el;
GeometryObserver.getInstance().addSubscription(this._container, this.resize); // подписка на ресайз
}
public resize = () => {
// действия на resize
}
public componentWillUnmount() {
GeometryObserver.getInstance().removeSubscription(this._container, this.resize);
}
public render() {
return (<div ref={this._setupContainerRef}>test</div>)
}
}
export default MyComponent;
Пример создания логики дропдауна
import React from 'react';
import {Dropdown} from 'bi-internal/face';
class MyComponent extends React.Component {
public state = {
menuVisible: false,
userIcon: ''
}
public render() {
const {menuVisible, userIcon} = this.state;
return (
<Dropdown.Trigger offset={[2, 0]}
menu={<SomeComponent/>}
trigger="mouseenter click"
placement="bottom-end"
visible={menuVisible}
onClick={() => this.setState({menuVisible: !menuVisible})}
onClickOutside={() => this.setState({menuVisible: false})}>
<div data-test-id="profileMenu"
className={cn('ProfileTrigger', {defined: !!userIcon})}>{userIcon ? AvatarIcons[userIcon] :
<div>click me to dropdown</div>
</Dropdown.Trigger>
);
}
export default MyComponent;
При клике или наведении на div
с текстом появится компонент <SomeComponent/>
в нижнем правом углу элемента. При клике вне дропдауна - компонент <SomeComponent/>
скроется
bi-internal/root
Модуль, который хранит компоненты, необходимые для отрисовки стартовой страницы (та, на которую вы по умолчанию попадаете при входе и видите список разделов BI)
Модуль частично описан на Github
В клиенте этот модуль выглядит так:
import {Root} from '../../views/Root/Root';
import {RootContent} from '../../views/Root/RootContent';
import {RootMenu} from '../../views/Root/RootMenu';
import {RootHeader} from '../../views/Root/RootHeader';
import {RootSearch} from '../../views/Root/RootSearch';
import Provider from '../../views/Root/Provider';
import {BreadcrumbControl} from '../../views/Root/BreadcrumbControl';
import {DatasetsListView} from '../../views/Root/DatasetsListView';
import {DatasetsListView1} from '../../views/Root/DatasetsListView1';
export {Root, RootContent, RootMenu, RootHeader, RootSearch, Provider, BreadcrumbControl, DatasetsListView, DatasetsListView1};
Модуль описан на Github, несколько комментариев:
Root
- общий компонент, полностью рендерящий внешний вид и поведение страницы разделов.
состоит из меню слева (RootMenu
), шапки RootHeader
(с хлебными крошками BreadcrumbControl
) и основного компонента с контентом текущего раздела RootContent
.
Пример использования в компоненте Root.tsx
:
import React from 'react';
import './Root.scss';
import {Strap} from 'bi-internal/face';
import {RootContent, RootHeader, RootMenu} from 'bi-internal/root';
export class Root extends React.Component<any> {
public render() {
const {activeTabIndex, activeChildIndex, tabs} = this.props;
return (
<section className="Root view roots custom">
<Strap>
<RootMenu activeTabIndex={activeTabIndex} activeChildIndex={activeChildIndex} tabs={tabs}/>
<Strap.Body>
<RootHeader/>
<RootContent {...this.props}/>
</Strap.Body>
</Strap>
</section>
);
}
}
export default Root;
bi-internal/services
Модуль, хранящий самые важные сервисы, необходимые в кастомной разработке.
Модуль частично описан на Github.
В клиенте описывается так:
import DatasetService from "../../services/ds/DatasetService";
import CurrentDsStateService from "../../services/ds/CurrentDsStateService";
import DsStateService from "../../services/ds/DsStateService";
import {ProviderService} from "../../services/ProviderService";
import {DashboardByTopicsService, IRawDashboardTopicMode} from "../../services/ds/DashboardByTopicsService";
import {IDatasetsListModel, IDatasetsListItem} from "../../services/DatasetsListService";
import {DatasetsListService} from "../../services/DatasetsListService";
import { DatasetsListIcon } from '../../views/Root/DatasetsListView';
import { DatasetsListView1 } from '../../views/Root/DatasetsListView1';
import {getShell, shell} from "../../views/Shell";
import {IVizelConfig, IVizelProps} from '../../services/ds/types';
import {useService, useServiceItself} from "../../views/useService";
import {OpenModalVC} from "../../view-controllers/OpenModalVC";
import {PluginsManager} from "../../plugins/plugins-manager";
import {KoobDataService} from "../../services/koob/KoobDataService";
import { ISummaryModel, SummaryService } from '../../services/SummaryService';
import {KoobService} from "../../services/koob/KoobService";
import {KoobFiltersService} from "../../services/koob/KoobFiltersService";
import {ISearchVM, SearchVC} from '../../view-controllers/SearchVC';
import {Vizel} from "../../views/components/Vizel";
import * as service from "../../services/service";
import {IShellVM} from '../../view-controllers/ShellVC';
import {IDsShellVM, DsShellVC} from '../../view-controllers/DsShellVC';
import {DsShell} from "../../views/DsShell/DsShell";
import {createSubspaceGenerator} from "../../services/ds/createSubspaceGenerator";
import {ThemeVC} from "../../view-controllers/ThemeVC";
import {DatasetsByTopicsService, ITopic} from "../../../srx/services/DatasetsByTopicsService";
import {TransactionEntitiesService} from "../../services/TransactionEntitiesService";
import ResourceByNameService from '../../services/ResourceByNameService';
import {ResourcesOfDatasetsTreeService} from '../../services/ResourceLocatorService';
import {KoobDimensionsMemberService} from '../../services/koob/KoobDimensionsMemberService'
import CanIService from "../../services/CanIService";
export {
CanIService, /* проверяет наличие прав на те или иные действия для текущей роли */
CurrentDsStateService,
DatasetService, // загружает модель указанного датасета
DatasetsListService, // загружает модели доступных датасетов с рядом методов
IDatasetsListModel,
IDatasetsListItem,
DashboardByTopicsService, // загружает группы дешбордов с дешбордами в них
IRawDashboardTopicMode,
DatasetsListIcon,
DatasetsListView1,
IVizelConfig,
IVizelProps,
Vizel,
DsStateService, /* сервис для загрузки информации о текущем состоянии атласа. Какие дешборды есть, какие дешлеты есть, конфиг текущего дешборда */
KoobDataService, // сервис для загрузки данных из куба. реализует методы koobDataRequest3, koobCountRequest3
KoobFiltersService, // сервис, управляющий текущими фильтрами на кубы
ProviderService,
PluginsManager, // Загрузит все доступные плагины (разделы на главной странице)
ISummaryModel, SummaryService,
getShell // вернет корневой компонент, родительский для всех компонентов на странице,
useService, // хук реакта, загружает модель указанного сервиса
useServiceItself, // хук реакта, загружает инстанс указанного сервиса (модель и методы)
ISearchVM,
SearchVC, // сервис для реализации поиска по чему угодно
IShellVM,
IDsShellVM,
DsShellVC,
ThemeVC, // сервис работы с темами
DsShell, // основной компонент хранящий все, что есть на странице с дешбордами
createSubspaceGenerator, // функция, которая создает объект subspace
DatasetsByTopicsService, // загружает группы датасетов и датасеты в них
ITopic,
TransactionEntitiesService,
OpenModalVC,
ResourceByNameService, // сервис ищущий указанный файл по иерархии атласов
ResourcesOfDatasetsTreeService, // сервис ищущий указанный файл по иерархии атласов
KoobDimensionsMemberService // загружает значения дименшна из словаря
};
Пример реального компонента с использованием модуля
import React, {useEffect, useState} from 'react'
import './MainPageRangeRow.scss'
import Select from '../elements/Select/Select'
import Option from '../elements/Select/Option'
import MoreButton from "../elements/ui/MoreButton"
import Range from '../elements/ui/Range'
import {UrlState} from "bi-internal/core";
import {KoobDataService, KoobService,
useService, useServiceItself, KoobFiltersService} from "bi-internal/services";
import {$eid} from "bi-internal/utils";
const { koobDataRequest3 }:any = KoobDataService;
/**
Принимает:
customClass - доп.классы для MainPageRangeRow,
name - название строки,
selectItems - список селекта,
selectVal - селект по умолчанию,
url - url по которому нужно перейти при клике на Подробнее
*/
const MainPageRangeRow = (props) => {
const url = UrlState.getInstance();
const [unitId, SetSelectedUnitId] = useState(url.getModel()?.f?.unit_id ? url.getModel()?.f?.unit_id[1] : props.units?.[0].id || 0);
const [data, setData] = useState([]);
const koob = useService<KoobService>(KoobService, props.koob);
const koobFiltersService:any = useServiceItself<KoobFiltersService>(KoobFiltersService);
const koobFilters = koobFiltersService.getModel();
useEffect(() => {
let filters = {...url.getModel().f};
filters.do_code = ['!=', 0];
filters[props.nameDim] = [props.filtersId == 0 ? '!=' : '=', props.filtersId];
filters[props.nameChildDim] = ['=', 0];
filters.unit_id = ['=', unitId];
filters.mr_code = ['=', 0];
filters.process_code = ['=', 0];
for(let key in filters) {
if(key != 'process_code' && key != 'do_code' && key != 'dt' && key != 'mr_code' && key != 'mnt_period' && key != 'unit_id' && key != props.nameDim && key != props.nameChildDim) delete filters[key]
}
const dimensions = props.filtersId == 0 ? ['do_name:name', 'do_code:id'] : ['do_name:name', 'do_code:id', 'value'];
const measures = props.filtersId == 0 ? ['sum(value):value'] : [];
koobDataRequest3(props.koob, dimensions, measures, filters,
{schema_name: UrlState.getModel().segmentId},
'getData').then(data => {
setData(data);
})
}, [url.getModel(), unitId])
const column = $eid(koob.dimensions, 'do_code');
const activeItemId = koobFilters.pendingFilters.do_code?.[1] ?? koobFilters.filters.do_code?.[1] ?? (column ? column.config?.defaultValue : 5);
if (koob.error || koobFilters.error || koob.loading || koobFilters.loading) return null;
return (
<div className={'MainPageRangeRow' + " " + props.customClass}>
<div className="MainPageRangeRow__Name">
{props.name}
<div className="MainPageRangeRow__WrapperMore">
<MoreButton classes={'MainPageRangeRow__More'} onClick={e => props.moreButton(props.nav, {[props.nameDim]: ['=', props.filtersId]})} />
</div>
</div>
<div className="MainPageRangeRow__WrapperSelect">
<Select
className="MeasureSelect__Select MainPageRangeRow__Select"
optionListClassName="MeasureSelect__List AppScroll"
optionListOffset={[0, 10]}
width={120}
value={unitId}
onChange={SetSelectedUnitId}
>
{props.units.length > 0 && props.units?.map(item =>
<Option key={item.id} value={item.id}>{item.name}</Option>
)}
</Select>
</div>
<div className="MainPageRangeRow__WrapperRange">
<Range data={data} activeId={activeItemId}/>
</div>
</div>
)
}
export default MainPageRangeRow;
bi-internal/ds-helpers
Дополнительный модуль со вспомогательными интерфейсами, методами и переменными для работы с МЛП сущностями, дешлетами, дешбордами.
Модуль описан на Github.
Пример импорта в компоненте
import {VizelConfig, VizelConfigDisplay, Dashlet, Dashboard} from 'bi-internal/ds-helpers';
bi-internal/ui
Модуль, хранит как явные UI компоненты, так и вспомогательные модули, нужные для их создания.
Модуль частично описан на Github
в клиенте этот модуль выглядит так:
import {BIIcon} from "../../views/components/BIIcon/BIIcon";
import {VizelFromCfg} from '../../views/components/Vizel/VizelFromCfg'
import {ExpandableSearch} from "../../views/components/ExpandableSearch/ExpandableSearch";
import {WpLoadingIcon} from "../../views/components";
import {DlgShareWithUser} from "../../views/dialogs/DlgShareWithUser/DlgShareWithUser";
import {AlertsVC} from "../../view-controllers/AlertsVC";
import {EditMenuItem} from "../../views/dd-menu";
import {PopupVC} from "../../view-controllers/dialogs/PopupVC";
import {ModalContainer, modalContainer} from '../../views/modal-container';
import {openModal} from '../../view-controllers/OpenModalVC';
import VirtualList from "../../views/components/VirtualList/VirtualList";
import {DrilldownMenu} from '../../views/dd-menu';
import ContextMenu from "../../views/components/ContextMenu/ContextMenu";
import {MainToolbarVC, IMainToolbarVM} from "../../view-controllers/panels/MainToolbarVC";
import {MainToolbar, MainToolbar__EditModeButton, HrefButton, MainToolbar__DataBoringButton, MainToolbar__ThemeSwitchButton} from '../../views/panels/MainToolbar/MainToolbar';
import ActionList from "../../../srx/components/action/ActionList";
import DlgAbout from "../../views/Root/ProfileComponents/DlgAbout";
import {OptionsProvider} from "../../config/OptionsProvider";
import EditModeVC, {IEditModeModel} from "../../view-controllers/EditModeVC";
import SVGIcon from "../../views/components/SVGIcon";
import {DASHBOARD_ICONS} from "../../const/DashboardIcons";
import BaseVizelEcharts from "../../views/vizels/BaseVizelEcharts";
import EPlot from "../../views/vizels/eplot";
import EditModeEnabler from "../../views/helpers/EditModeEnabler";
import L10n from "../../views/components/L10n/L10n";
import L10nVC from "../../view-controllers/L10nVC";
import AppPane, {Menu, MenuState} from "../../views/components/AppPane/AppPane";
import JsonSchemaForm from "../../views/components/JSONSchema/JsonSchemaForm";
import SimpleTable from "../../views/components/SimpleTable/SimpleTable";
import {VizelYVC} from '../../view-controllers/vizels/VizelYVC';
import {VizelXVC} from '../../view-controllers/vizels/VizelXVC';
import {VizelXYVC} from '../../view-controllers/vizels/VizelXYVC';
import {VizelGaugeVC} from '../../view-controllers/vizels/VizelGaugeVC';
import {VizelPivotMLP} from '../../view-controllers/vizels/VizelPivotMLP';
import {VizelControllerVector} from '../../view-controllers/vizels/VizelControllerVector';
import {BaseVizelVC} from '../../view-controllers/vizels/BaseVizelVC';
import * as VizelKoobControl from "../../views/vizels/VizelKoobControl";
import IfICan from '../../views/helpers/IfICan';
import Search from '../../views/components/Form/Search/Search';
import SelectSortBy from '../../views/components/Form/SelectSortBy/SelectSortBy';
import OnlyWhenVisible from '../../views/helpers/OnlyWhenVisible';
import ConfirmWindow from '../../views/components/ConfirmWindow/ConfirmWindow';
import RootLogo from '../../views/Root/RootLogo';
import {DsShellHeader} from "../../views/DsShell/DsShellHeader";
import Select from '../../views/components/Form/Select/Select'
import {DatasetsListIcon} from '../../views/Root/DatasetsListView1'
export {
VizelFromCfg,
IfICan,
BIIcon,
ExpandableSearch,
WpLoadingIcon,
DlgShareWithUser,
ModalContainer,
modalContainer,
AlertsVC,
EditMenuItem,
PopupVC,
openModal,
VirtualList,
DrilldownMenu,
ContextMenu,
IMainToolbarVM,
MainToolbarVC,
MainToolbar,
MainToolbar__EditModeButton, HrefButton, MainToolbar__DataBoringButton, MainToolbar__ThemeSwitchButton,
ActionList,
DlgAbout,
OptionsProvider,
EditModeVC,
IEditModeModel,
SVGIcon,
SimpleTable,
DASHBOARD_ICONS,
BaseVizelEcharts,
EPlot,
EditModeEnabler,
L10n,
L10nVC,
AppPane,
Menu,
MenuState,
JsonSchemaForm,
VizelYVC,
VizelXVC,
VizelXYVC,
VizelGaugeVC,
VizelPivotMLP,
VizelControllerVector,
BaseVizelVC,
VizelKoobControl,
Search,
SelectSortBy,
OnlyWhenVisible,
ConfirmWindow,
RootLogo,
DsShellHeader,
Select
};
Частично описан на Github, ряд комментариев:
IfICan
- React-компонент для оборачивания функционала по правам. Проверит один или более claim и покажет дочерние элементы. Клеймы могут быть как “все сразу” (eachOf), “один из” (oneOf) и “указанный” (one)
<IfICan eachOf={['U adm.topics', 'U adm.dataset_topics_maps']}>
{/* Мы можем редактировать топики */}
<SomeComponent/>
</IfICan>
SomeComponent
появится только если оба указанных клейма вернут true
VizelFromCfg
- позволит создать визель на основе schema_name
атласа и конфига дешлета rawCfg
.
<VizelFromCfg schema_name={"ds_51"} view_class={"'1II.bar'}
rawCfg={{
koob: 'luxmsbi._orders_full_2',
style: {
measures: {
profit: {
color: '#4AB6E8',
title: 'Прибыль',
},
},
},
xAxis: 'cust_companyname',
yAxis: 'measures',
filters: {
orderdate: true,
categoryname: [
'=',
'Женская обувь',
],
cust_country: [
'=',
'США',
],
},
measures: [
'profit',
],
hierarchy: [],
dimensions: [
'cust_companyname',
],
}} />
И вы получите готовую визуализацию типа “Горизонтальные столбики”, которую можете встроить в свой контейнер.
BIIcon
- компонент, принимающий icon
,onPress
, который отрисует иконку из BI, лежащую по адресу assets/icons/${icon}.svg
.
modalContainer
- инстанс класса ModalContainer, который может открыть вам модальное окно в стандартном режиме: то есть как если бы вы открыли встроенный drillDown
Это можно сделать через
modalContainer.push({
rawCfg: {/* Тут конфиг дешлета с обязательным указанием ключа view_class */},
schema_name: "ds_51"
}, "Название моего окна или html строкой")
openModal
- async
метод, который может отобразить попап с любым реакт-компонентом, который вы ему передадите. Принимает сам реакт компонент и объект опций
interface IOpenModalVMOpt {
readonly cancelWrapper?: boolean; // default = true, закрытие модального окна по клику на wrapper
readonly cancelEsc?: boolean; // default = true, кнопка esc не работает на закрытие
readonly hiddenWrapper?: boolean; // default = false, наличие wrapper'a
readonly style?: { [id: string]: string | number };
readonly className?: string;
// ... todo дальнейшее расширение
}
openModal(
<DeleteCube item={item}/>, {
cancelWrapper: true,
className: 'Action active',
style: {
'justify-content': 'center',
'width': '25rem',
'height': 'min-content',
'min-height': 'auto',
'padding': '1rem',
}
})
.then(() => {/* do smth */})
AlertsVC
- сервис ОС, синглтон, отвечающий за пуш уведомления о статусе действия. Отображается всплывающим коротким сообщением разных цветов (от контекста уведомления зависит)
pushNewsAlert, pushInfoAlert, pushSuccessAlert, pushDangerAlert, pushWarningAlert
- методы этого сервиса, отображающие контекстные уведомления. Принимают описание, название, таймаут
AlertsVC.getInstance().pushSuccessAlert('Расписание успешно создано');
VirtualList
- Компонент для отрисовки списка, который хранит только элементы, укладывающиеся в доступный вьюпорт. При скролле догружает список, выгружая ранний. Мастхев для больших данных чтобы рендер реакта не убил страницу.
const members = [{/*...*/}, {/*...*/}];
private _renderMember = (item: repo.adm.IRawUser, idx: number): JSX.Element => {
return (
<div key={item.id} className="MyClass--Item">
<div>{item.name}</div>
</div>
);
}
public render() {
return (
<VirtualList
className="MyClass"
items={members}
renderItem={(item) => this._renderMember(item)}
/>
)
}
VizelYVC,VizelXVC,VizelXYVC,VizelGaugeVC, VizelPivotMLP,VizelControllerVector
- классы-сервисы ОС, наследующиеся от BaseVizelVC
и позводяющие инициализировать встроенные визуализации для дешлетов, при их переопределении.
BaseVizelEcharts
- компонент, являющийся базовым родителем для всех коробочных визуализаций, которые работают на ECharts. Описывает абстрактные методы и их логику использования для получения итогового компонента с использованием Echarts и реакций на основные события.
EPlot
- более продвинутый наследник BaseVizelEcharts
, который полностью описывает типы line
, scatter
, area
и является стартовым конфигом для ряда других встроенных визуализаций.
Достаточно создать React компонент, унаследовавшийся от данного компонента и переопределить функцию _getEchartsConfig(vm)
, которая принимает объект с информацией о сериях и категориях, взятых из конфига дешлета, в котором данный компонент работает.
Вернуть функция должна объект конфига ECharts по аналогии с тем, как это выглядит в объекте option
тут
bi-internal/utils
Модуль содержит в себе ряд вспомогательных функций или утилит, библиотек, которые используются чаще других и могут пригодиться в кастомной разработке.
Модуль частично описан на Github
В клиенте этот модуль выглядит так:
const utils = require('../../utils/utils');
const utilsEcharts = require('../../utils/utilsEchars');
const {$eid, $eidx, $esid} = require('../imdas/list');
const cUtils = require('../../views/vizels/utility/c-utils');
const formatNumberWithString = require('@luxms/format-number-with-string');
import {mouseWatcher} from '../../libs/MouseWatcher';
import LoadFromResources from "../../views/components/LoadFromResources";
const skin = require('../../skins/skin.json');
import {parse as wktParse} from "wellknown";
import {lpeRun} from '../../utils/lpeRun';
import L from 'leaflet';
const getBuildVersion = () => process.env.VERSION;
const getBuildDate = () => process.env.DATE;
module.exports = {
...utils,
...utilsEcharts,
...cUtils,
L, wktParse,
$eid, $eidx, $esid,
formatNumberWithString,
mouseWatcher,
skin,
lpeRun,
getBuildVersion,
getBuildDate,
LoadFromResources
};
Пакеты c-utils
, utils
, MouseWatcher
описаны в проекте на Github, с той разницей ,что utilsEcharts
- это ряд функций из utils
, посвященных работе с цветом и градиентом в синтаксисе библиотеке Apache Echarts.
formatNumberWithString
- функция, способная гибко форматировать числа, пришедшие как строка по указанному формату.
Страница одноименной библиотеки: https://github.com/luxms/format-number-with-string
$eid, $eidx, $esid
- функции из пакета list
для получения энтити по id (в зависимости от контекста это м.б. дименшн, межа, метрика, локация, период), его индекса в списке и списка энтити по списку id.
LoadFromResources
- React
-компонент, который является оберткой над компонентом MyComponent
из веб-клиента и проверяет наличие одноименного файла MyComponent.js
в ресурсах согласно иерархии атласов (т.е. в ds_res
, родительском атласе и текущем) И принимает те же props
, что и сам компонент-ребенок, но с полем path="MyComponent.js"
. Если такой компонент найден (и даже не в единственном экземпляре) - будет использоваться тот, кто ниже всех в иерархии атласов. Именно этот компонент оборачивает ключевые компоненты, доступные к переопределению в ресурсах в коде веб-клиента
skin
- JSON-файл с настройками, влияющими на отображение (устаревший способ кастомизации функционала)
L, parse
- Библиотека leaflet
и ее парсер wkt
для создания компонентов, реализующих слои на карте
lpeRun
- модуль, а также одноименная функция, позволяющий парсить строки с lpe-выражением. Подробнее тут LPE.
Удобен для задавания выражения, которое будет парсить параметр из конфига дешлета, исходя из переданного контекста, и влияние таким образом на поведение компонента.
Первым аргументом функции является строка c lpe:
внутри, вторым - объект контекста, где по факту должны быть описаны все переменные или функции, которые используются в данном выражении из первого аргумента.
getBuildVersion, getBuildDate
- отдают версию клиента и дату сборки.
Пример подключения элементов модуля в конкретном компоненте:
import {formatNumberWithString, coloring, bi} from 'bi-internal/utils';