Core package of kaiju.components;
- Table (DONE)
- Header (DONE)
- Buttons (DONE)
- Notifications (DONE)
- SearchComponent and SearchBox (DONE)
- Select\MultiSelect Component
- Tabs (DONE)
- WindowActionComponent
- Checkbox and Radio
- Modals
- BaseStorage (DONE)
option | type | description | default | required |
---|---|---|---|---|
request |
json | method и params grid-метода | - | yes |
rowCallback |
function | функция возвращающая id строчки на click | false | No |
autoRefresh |
integer | включает обновление данных каждые n секунд | "Количество" | No |
ActionsComponent |
component | компонент правой ячейки записи: удаление, редактирование и тд | "Количество" | No |
labelCount |
string | лейбл счетчика около пагинации | "Количество" | No |
disableCount |
bool | убрать счетчик около пагинации | false | No |
disablePagination |
bool | убрать пагинацию | false | No |
checkable |
bool | включает режим чекбоксов | false | No |
checkCallback |
bool | колбек на | false | No |
accordion |
bool | разделение таблицы на группы | false | No |
cellConstructors |
json | # TODO: | false | No |
fieldConstructors |
json | # TODO: | false | No |
TODO: count, checkedIds, rowStore, all actions
tableStore.actions.isFetching
- идёт ли запрос на бек в текущий момент времени
this.props.tableStore.actions.fetchByPage()
- получить страницу.
Можно передать номер страницы, по-умолчанию получает первую.
import React from "react";
import TableComponent from "@kaiju.ui/components/src/Tables/TableComponent";
import {Provider} from "mobx-react";
import {TableStore} from "@kaiju.ui/components/src/Tables/stores";
class SomeComp extends React.Component {
constructor(props) {
super(props)
this.tableStore = new TableStore({
request: {
method: "Product.grid", // метод отвечающий за построение таблицы
params: { // параметры
engine: this.engineId,
}
},
rowCallback: (rowStore) => {
this.props.routerStore.router.navigate(ROUTES.invoiceEdit, {id: rowStore.id})
}
});
}
render() {
return (
<Provider tableStore={this.tableStore}>
<TableComponent/>
</Provider>
)
}
}
Пример с table actions component:
import {TableStore} from "@kaiju.ui/components/src/Tables/stores";
import TableComponent from "Tables/TableComponent";
import React from "react";
import {Provider} from "mobx-react";
import ROUTES from "smtg"
import ActionsComponent, {DeleteAction} from "@kaiju.ui/components/src/Tables/actions";
@inject("routerStore")
@inject("userStore")
class TableActionsComponent extends React.Component {
delete() {
Axios.post(ROUTES.rpc,
{
"method": `${this.props.serviceName}.delete`,
"params": {
engine: this.props.routerStore.route.params["engineId"],
key: this.props.rowStore.id,
}
}
).then(response => {
if (response.data.result) {
this.props.tableStore.actions.fetchByPage()
} else {
utils.handleNotifyExceptions(response)
}
}).catch(response => {
this.isFetching = false;
utils.handleNotifyExceptions(response)
})
}
getLabel() {
let {label = {}} = toJS(this.props.rowStore.row);
return label.value || this.props.rowStore.id
}
render() {
let showDelete = !this.props.rowStore.isSystem
&& !this.props.rowStore.isDefault
&& this.props.userStore.hasPerm("system");
return (
<ActionsComponent>
{
showDelete && (
<DeleteAction
idLabel={this.getLabel()}
actionLabel={utils.getTranslation("Message.delete")}
deleteCallback={() => this.delete()}/>
)
}
</ActionsComponent>
)
}
}
class Page extends React.Component {
constructor(props) {
super(props);
this.tableStore = new TableStore({
labelCount: "Инвойсы", // лейбл около пагинации, по дефолту выводится "Количество: n"
checkable: true, // включает функционал чекБоксов
checkMulti: false, // можно ли зачекать много сразу или только один
disableCount: true, // убрать отображение каунтера
disablePagination: true, // убрать отображение пагинации
autoRefresh: 5, // (секунды) автообновление,
request: {
// запрос грид с параметрами
method: "RusInvoice.grid",
params: {},
errorCallback: (responseData) => {
}
},
// конструктор ячеек
cellConstructors: {
error: flagCell
},
// конструктор филдов
fieldConstructors: {
error_bit: flagCell
},
// callback на чек
checkCallback: (ids) => {
console.log(ids)
},
// callback на клик по строчке таблицы
rowCallback: (rowStore) => {
this.props.routerStore.router.navigate(ROUTES.rusInvoiceEdit, {id: rowStore.id})
},
ActionsComponent: TableActionsComponent // компонент действий
});
}
render() {
return (
<Provider tableStore={this.tableStore}>
<TableComponent/>
</Provider>
)
}
}
import SearchComponent, {SearchBox} from "@kaiju.ui/components/src/SearchComponent"
this.searchConf = {
suggestionConf: {
key: "q",
request: {
method: "Query.suggest",
params: {
business_unit: this.pageStore.mainFilters.business_unit || null,
}
},
Component: Suggestions
},
disabled: this.pageStore.isFetching,
callback: (query) => {
this.pageStore.onQueryChange(query)
}
};
<SearchComponent {...this.searchConf}/>
<SearchBox
placeholder: "Поиск по идентификатору"
callback={query => console.log("query", query)/>
Simple button components:
- Button - simple button
- ButtonSuccess - success-style button
- ButtonDefault - default-style button
More complex buttons:
- ButtonDropdown
- DoubleButtonDropdown
option | type | description | default | required |
---|---|---|---|---|
onClick or callback
|
function | the width of the carousel container. | undefined | Yes |
icon |
string | icon near the button | none | No |
label |
string | label of button | none | No |
className |
string | custom css class. | none | No |
children |
components | inner components | - | No |
disabled |
bool | disable button clicks while requests | false | No |
style |
css json | add custom style | - | No |
Options of parameter 'conf':
option | type | description | default | required |
---|---|---|---|---|
mainButtonConf |
json of Button config | simple button conf | - | Yes |
dropDownConfs or items
|
array of button confs | [{label: ..., callback: ...} | none | No |
import React from "react";
import ROUTES from "RoutingNames";
import {
Button,
ButtonSuccess,
ButtonDefault,
ButtonDropdown,
DoubleButtonDropdown
} from "@kaiju.ui/components/src/Buttons";
class ExampleComp extends React.Component {
constructor(props) {
super(props);
this.buttonConf = {
label: utils.getTranslation("Button.create"),
icon: "icon-plus",
onClick: () => {
this.props.routerStore.navigate(ROUTES.declarationAdd);
}
};
}
render() {
return (
<React.Fragment>
// just point props directly into components
<ButtonSuccess
label={"Открыть отчет"}
onClick={() => this.openReport()}
/>
// all props from conf
<ButtonDefault {...this.buttonConf}/>
</React.Fragment>
)
}
}
class ExampleCompComplexBtns extends React.Component {
constructor(props) {
super(props);
this.buttonDropdownConf = {
mainButtonConf: {
label: "Сохранить",
// diff between dropdown conf and double button dropdown:
// in double button you can path onclick event
onClick: () => {
this.declarationStore.save();
}
},
dropDownConfs: [
{
label: "Report #1",
callback: () => this.openReport()
},
{
label: "Report #2",
callback: () => {
this.showDeleteWindow = true
}
},
]
};
this.dropDownConf = {
mainButtonConf: {
label: "Настройки", // only label
},
items: [
{
label: "Report #1",
callback: () => {
console.log("test")
}
},
{
label: "Report #2",
callback: () => {
console.log("test")
}
},
]
};
}
render() {
return (
<React.Fragment>
<ButtonDropdown conf={this.buttonDropdownConf}/>
<DoubleButtonDropdown conf={...this.dropDownConf}/>
</React.Fragment>
)
}
}
Хедер на странице
options of parameter 'conf':
option | type | description | default | required |
---|---|---|---|---|
dropdownConf or doubleButtonConf or buttonConf
|
button conf json | версия кнопки справа вверху | - | No |
settings |
callback click function | иконка настройки | - | No |
label |
string | лейбл | - | No |
searchCallback or searchConf
|
function or search conf | настройки поиска или функция на получение и обработку нового query | - | No |
breadcrumbs |
breadcrumbs conf | хлебные крошки | - | No |
className |
string | custom className | - | No |
Пример:
import Header from "@kaiju.ui/components/src/Header/base";
// с лейблом:
<Header
breadcrumbs={this.breadcrumbs}
className={"test-class-name"}
label={"Грузы"}
/>
// c поисковой строкой:
<Header
breadcrumbs={breadcrumbs}
buttonConf={buttonConf}
searchConf={searchConf}
/>
Формат хлебных крошек:
this.breadcrumbs = [
{
label: "Page #1",
path: "Link to page for router5js"
},
{
label: "Page #2",
},
];
Тот же хедер, но способный с помощью mobx изменять своё состояние
option | type | description | default | required |
---|---|---|---|---|
isChanged |
bool | показывает надпись "есть несохраненные изменения" | - | No |
isFetching |
bool | блокирует кнопки | - | No |
example:
import {observer} from "mobx-react";
import ROUTES from "RoutingNames";
import DynamicHeader from "@kaiju.ui/components/src/Header";
DynamicHeader = observer(() => {
this.breadcrumbs = [
{
label: "Декларации таможни",
path: ROUTES.declarationAll
},
{
label: "Редактирование",
},
];
let {mainFormStore, invoicesFormStore} = this.declarationStore;
return (
<DynamicHeader
breadcrumbs={this.breadcrumbs}
doubleButtonConf={this.buttonDropdownConf}
isChanged={mainFormStore.isChanged || invoicesFormStore.isChanged}
isFetching={mainFormStore.isFetching || invoicesFormStore.isFetching}
label={mainFormStore.label}
/>
)
});
Notify alert in the right bottom of the screen:
- notifyError - red error alert
- notifySuccess - green success alert
option | type | description | default | required |
---|---|---|---|---|
title |
string | - | no | |
message |
string | text message настройки | - | no |
delay |
integer | time delay | error - 3000, success - 1000 msec | no |
import {notifyError, notifySuccess} from "@kaiju.ui/components/src/notifications";
notifyError("error", undefined, 300)
notifyError(null, "some message", 300)
notifySuccess("Done")
Lib docs link --> ReactTabs
Все эти опции используются для того, чтобы сохранить состояне в session storage.
option | type | description | default | required |
---|---|---|---|---|
defaultIndex |
integer | номер какой вкладки показывать по-умолчанию | 0 | no |
onSelect |
function | получить новый индекс и сохранить его куда-нибудь | - | no |
Simple example:
import React from "react";
import {Tab, TabList, TabPanel, Tabs} from "@kaiju.ui/components/src/Tabs";
import Form from "@kaiju.ui/forms/src/Form";
export default class AttributeAddPage extends React.Component {
render() {
let {formStore} = this.formHandleStore;
return (
<React.Fragment>
<Tabs className="page-content-body pl-5 pr-5"
defaultIndex={BaseStorage.getItem(this.props.route.name, 0)}
onSelect={(index) => BaseStorage.setItem(this.props.route.name, index)}>
<TabList>
<Tab>{utils.getTranslation("Tab.properties")}</Tab>
</TabList>
<TabPanel>
{
this.formHandleStore.dataInitialized &&
<div className={this.formHandleStore.isFetching ? "disabled-form mt-5" : " mt-5"}>
<Form key={formStore.key}
store={formStore}
groupFiltering/>
</div>
}
</TabPanel>
</Tabs>
</React.Fragment>
)
}
}
Dynamicly add tab:
import React from "react";
import ROUTES from "RoutingNames";
import {Tab, TabList, TabPanel, Tabs} from "@kaiju.ui/components/src/Tabs";
import Form from "@kaiju.ui/forms/src/Form";
import {observer} from "mobx-react";
import {observable} from "mobx";
import Axios from "axios";
@observer
export default class AttributeEditPage extends React.Component {
@observable has_options = false;
constructor(props) {
super(props);
// pass
}
componentDidMount() {
this.checkIfOptionsEnabled()
}
checkIfOptionsEnabled() {
// make request
Axios.post(ROUTES.rpc,
{
method: `${this.serviceName}.get`,
params: {
engine: this.engineId,
key: this.attributeKey,
grouping: false
}
}
).then(response => {
let result = response.data.result;
// if attr has option mobX will rerender Tabs
if (result) {
this.has_options = result.kind === 'string'
} else {
utils.handleNotifyExceptions(response)
}
}).catch(response => {
utils.handleNotifyExceptions(response)
})
};
renderOptionsTable() {
// pass
}
render() {
let {formStore} = this.formHandleStore;
const tabs = [
<Tab key={utils.uuid4()}>{utils.getTranslation("Tab.properties")}</Tab>
];
const tabPanels = [
<TabPanel key={utils.uuid4()}>
{
this.formHandleStore.dataInitialized &&
<div className={this.formHandleStore.isFetching ? "disabled-form mt-5" : " mt-5"}>
<Form key={formStore.key}
store={formStore}
groupFiltering/>
</div>
}
</TabPanel>
];
if (this.has_options) {
tabs.push(<Tab key={utils.uuid4()}>{utils.getTranslation("Label.options")}</Tab>);
tabPanels.push(<TabPanel key={utils.uuid4()}>{this.renderOptionsTable()}</TabPanel>)
}
return (
<React.Fragment>
<Tabs className="attr-tabs__content_body pl-5 pr-5">
<TabList>{tabs}</TabList>
{tabPanels}
</Tabs>
</React.Fragment>
)
}
}
Обертка от sessionStorage, чтобы хранить данные пользователя при сессии
BaseStorage.getItem("key")
BaseStorage.setItem("key", "some_value")
BaseStorage.setItem("key", {"count": 1})