Кастомизация
Кастомизация - это способ расширить UI возможности N2O через создание собственной темы стилей или визуальных компонентов.
Для создания кастомизации вам понадобятся знания следующих технологий:
- Sass
- [React]
Настройка окружения
Для кастомизации вам потребуется установить следующее программное обеспечение:
Создание React проекта
Перед тем как подключить кастомизацию необходимо создать React проект c N2O Framework.
Сборка React проекта выполняется менеджером пакетов yarn.
В корне N2O проекта выполните команду:
npm init react-app frontend
Эта команда создаст папку frontend, в ней создаст необходимые для начала работы файлы и папки, включая index.tsx.
Перейдите в папку /frontend
:
cd frontend
Затем установите библиотеку n2o-framework
:
yarn add n2o-framework
Далее необходимо удалить лишние файлы, созданные после инициализации. Удалите файлы App.css
, App.js
, App.test.js
, logo.svg
,
reportWebVitals.js
.
Отредактируйте файл /frontend/src/index.tsx
. Он должен выглядеть следующим образом:
import React from 'react';
import ReactDOM from 'react-dom';
import N2O from 'n2o-framework';
import createFactoryConfig from "n2o-framework/lib/core/factory/createFactoryConfig";
import authProvider from "n2o-framework/lib/core/auth/authProvider";
import 'n2o-framework/dist/n2o.css';
import './index.css';
const config = {
security: {
authProvider,
externalLoginUrl: '/'
}
};
ReactDOM.render(
<React.StrictMode>
<N2O {...createFactoryConfig(config)} />
</React.StrictMode>,
document.getElementById('root')
);
Теперь N2O React проект готов.
Для сборки проекта в папке /frontend
выполните команду:
yarn
А затем:
yarn build
В результате в папке /frontend/build
появится index.html
и другие статические ресурсы.
Чтобы подключить статические ресурсы к N2O серверу,
в файле pom.xml
в разделе <plugins>
добавьте maven-resources-plugin
:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>Copy frontend build</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/classes/public</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<directory>${project.basedir}/frontend/build</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Теперь N2O сервер будет раздавать статические ресурсы собранные в React проекте в папке /frontend/build
.
Подключение кастомизаций
Кастомизации передаются в N2O с помощью конфигурационного объекта:
Минимальный вид конфигурационного объекта, с обязательным свойством security
const config = {
// ... кастомизации
security: {
authProvider,
externalLoginUrl: './',
},
}
import React from "react";
import N2O from "n2o-framework";
import authProvider from "n2o-framework/lib/core/auth/authProvider";
import createFactoryConfig from "n2o-framework/lib/core/factory/createFactoryConfig";
const config = {
// ... кастомизации
security: {
authProvider,
externalLoginUrl: './',
},
}
ReactDOM.render(
<React.StrictMode>
<N2O {...createFactoryConfig(config)} />
</React.StrictMode>,
document.getElementById('root')
);
Конфигурационный объект содержит наборы компонентов, разбитые по типам кастомизации:
const config = {
controls,
widgets,
regions,
pages,
headers,
cells,
fieldsets,
fields,
actions,
snippets,
buttons,
templates: {
header,
footer,
sidebar,
},
security
};
Для кастомизации header
footer
sidebar
необходимо в свойство templates
конфигурационного объекта,
передать кастомные компоненты.
Пример описывающий как реализовать данную возможность:
import SimpleHeader from 'n2o-framework/lib/plugins/Header/SimpleHeader/SimpleHeader'
export function CustomHeader(config) {
return (
<SimpleHeader { ...config } />
)
}
import Footer from 'n2o-framework/lib/plugins/Footer/Footer'
export function CustomFooter(config) {
return (
<Footer { ...config } />
)
}
import SideBar from 'n2o-framework/lib/plugins/SideBar/SideBar'
export function CustomSidebar(config) {
return (
<SideBar { ...config } />
)
}
Имена переданных в N2O компонентов header
footer
sidebar
задаются с помощью атрибута src в application.xml
<application xmlns="http://n2oapp.net/framework/config/schema/application-3.0"
welcome-page-id="index">
<header src="CustomHeader" />
<sidebar src="CustomSidebar" />
<footer src="CustomFooter" />
</application>
Передача кастомных компонентов в свойство templates
конфигурационного объекта
import CustomHeader from "./components/plugins/CustomHeader";
import CustomSidebar from "./components/plugins/CustomSidebar";
import CustomFooter from "./components/plugins/CustomFooter";
const config = {
// ... кастомизации
templates: {
CustomHeader,
CustomSidebar,
CustomFooter,
},
security
}
ReactDOM.render(
<React.StrictMode>
<N2O {...createFactoryConfig(config)} />
</React.StrictMode>,
document.getElementById('root')
);
Хорошей практикой будет создать папку components
в frontend/src
для размещения в ней всех ваших компонентов.
В папке components
разделить компоненты по типам кастомизаций, например: /pages
, /widgets
, /cells
.
В каждой из этих папок будут находиться:
- папки с кастомными компонентами
- файл
index.tsx
, в котором будут экспортироваться эти компоненты
import HelloPage from './HelloPage/HelloPage.js';
export default {
HelloPage
};
В config объект передать импортированные наборы компонентов:
import pages from './components/pages';
const config = {
pages,
security
}
Переданные в N2O компоненты можно использовать в конфигурациях с помощью атрибута src
:
<?xml version='1.0' encoding='UTF-8'?>
<simple-page xmlns="http://n2oapp.net/framework/config/schema/page-4.0"
src="HelloPage">
...
</simple-page>
Отладка
Для отладки кастомизаций необходимо будет запустить приложение в режиме разработки. В режиме разработки все вносимые в проект изменения автоматически применяются и сразу отображается результат. Для этого необходимо клиентскую часть проекта запустить на локальном NodeJS сервере, а серверная часть может находиться как удаленно, так и запущена локально.
Проксирование запросов на сервер N2O осуществляется с помощью библиотеки http-proxy-middleware
.
Для подключения http-proxy-middleware
к проекту выполните команду:
yarn add http-proxy-middleware --dev
URL целевого сервера указывается в файле setupProxy.js
. Создайте его в папке
src
и укажите цель для проксирования:
const {createProxyMiddleware} = require('http-proxy-middleware');
module.exports = function (app) {
app.use(
'/n2o',
createProxyMiddleware({
// URL целевого сервера (локальный или удаленный)
target: "http://localhost:8080",
changeOrigin: true
})
);
};
Запуск приложения выполняется командой:
yarn start
Приложение откроется по адресу http://localhost:3000
.
Кастомизация стилей
Кастомизация стилей предназначена для изменения общего внешнего оформления приложения в соответствии с вашими пожеланиями. Кастомизация стилей заключается в переопределении стилей стандартных css классов и css-переменных N2O и Bootstrap на свои собственные.
Стандартные стили N2O находятся в папке frontend/node_modules/n2o-framework/src/sass
:
/n2o // папка со основными стилями N2O
/theme // папка со стилями темы N2O
bootstrap.scss // корневой файл всех стилей, импортированных из библиотеки bootstrap
n2o.scss // корневой файл всех стилей N2O
variables.scss // корневой файл всех css-переменных N2O
Сборка стилей N2O выполняется с помощью библиотеки sass
.
Для ее подключения выполните команду:
yarn add sass --dev
После этого файл index.css
, расположенный в папке src
проекта, необходимо переименовать в index.scss
.
Чтобы передать управление стилями проекту, необходимо отредактировать директивы import
в файле index.tsx
:
//import 'n2o-framework/dist/n2o.css'; // эту директиву необходимо удалить
import './index.scss'; // файл index.css необходимо переименовать в index.scss
...
Файл index.scss
является корневым файлом стилей вашего проекта, поэтому все файлы стилей должны подключаться в него.
Первым должен быть подключен корневой файл стилей N2O:
@import "n2o-framework/src/sass/n2o.scss";
...
Теперь необходимо скопировать в ваш проект файлы со стилями и css-переменными, которые вы будете переопределят ь, из frontend/node_modules/n2o-framework/src/sass
.
Хорошей практикой считается хранение файлов стилей проекта в отдельной папке, например /sass
.
Рекомендуется сохранять такие же названия папкам, которые вы будете копировать из n2o-framework.
Для подключения измененных стилей укажите относительный путь до файла с изменениями в index.scss
:
// стандартные стили N2O
@import "n2o-framework/src/sass/n2o.scss";
// файлы общих стилей вашего проекта
@import "./sass/variables.scss";
@import "./sass/theme/variables";
...
// файлы стилей компонентов вашего проекта
@import "./sass/someComponent.scss";
@import "./sass/anotherComponent.scss"
При подключении файлов стилей к проекту решающее значение имеет очередность подключения. Следует строго придерживаться следующего порядка:
- файл стилей N2O
- файлы с css-переменными вашего проекта
- файлы стилей компонентов, контролов, темы вашего проекта
Если запустить проект в режиме разработки, все изменения в файлах стилей будут подхватываться и сразу отображаться.
Кастомное действие
Кастомное действие позволяет расширить логику работы с n2o store. Для вызова с сервера, в реакт проекте не требуется дополнительных действий. Обработка кастомного действия зависит от бизнес-требования.
Если необходимо расширить n2o store новыми ключами данных, следует написать reducer.
Хорошей практикой будет создать папку reducers
в frontend/src
для размещения в ней всех ваших reducers.
Импорт в config вашего App (app/src/App.jsx
) производить из общего файла импорта index.tsx
Ключ в config должен быть customReducers
import { customReducer1 } from './reducers/custom1/store'
import { customReducer2 } from './reducers/custom2/store'
export const customReducers = { custom1: customReducer, custom2: customReducer2 }
Если нет необходимости расширять n2o store, достаточно реализовать saga effect для манипуляции на кастомным действием.
Хорошей практикой будет создать папку sagas
в frontend/src
для размещения в ней всех ваших sagas.
Импорт в config вашего App (app/src/App.jsx
) производить из общего файла импорта index.tsx
Ключ в config должен быть customSagas
import { saga } from './sagas/action1/saga1'
import { saga2 } from './sagas/action2/saga2'
export const customSagas = [
saga,
saga2,
]
Импорт в n2o config
const config = createFactoryConfig({
// ... кастомизации
customReducers,
customSagas,
})
ReactDOM.render(
<React.StrictMode>
<N2O {...config} />
</React.StrictMode>,
document.getElementById('root')
);
Для расширения существующих объектов данных из n2o store необходимо создать расширенный объект данных.
Не является безопасной практикой. Мы не можем отвечать за работоспособность функционала при изменении данных из n2o-framework store. Рекомендуется только добавление новых ключей данных, а не мутации уже существующих.
Пример. Чтобы расширить объект page.
- Выполняем импорт pageSlice из n2o-framework.
- Выполняем импорт initialState из n2o-framework.
- Создаем slice в качестве name указываем pageSlice.name
- Добавляем значение initialState
- В поле reducers необходимо сде лать спред всех редюсеров pageSlice.caseReducers.
Список reducers можно увидеть по пути n2o-framework/lib/reducers
import { pageSlice, initialState } from 'n2o-framework/lib/ducks/pages/store'
const extendedPagesSlice = createSlice({
name: pageSlice.name,
initialState,
reducers: {
...pageSlice.caseReducers,
// ... ваша логика
}
})
export const pagesReducers = extendedPagesSlice.reducer
При экспорте, в customReducers, необходи мо использовать ключ reducer из n2o-framework.
export const customReducers = { pages: pagesReducers }
Клиентские действия реализуются идентично сервер/клиент действиям.
Для конфигурации кастомного действия в xml используется элемент <action>
.
В данном теге необходимо указать Redux тип действия, а также можно настроить поведение приложения после выполнения действия.
Полезная нагрузка Redux действия конфигурируется с помощью дочернего для <action>
элемента <payload>
.
Тег <payload>
поддерживает возможность использования любых атрибутов, а также возможность преобразованием в json-объекты
атрибуты, использующие "дефис" в именовании.
<action type="n2o/actionImpl/START_INVOKE"
redirect-url="/test" redirect-target="application">
<payload dataProvider-url="n2o/data/mi2"
dataProvider-method="POST"
datasource="_main"
model="resolve"
pageId="_"
widgetId="_main"/>
</action>
"action": {
"type": "n2o/actionImpl/START_INVOKE",
"payload": {
"datasource": "_main",
"widgetId": "_main",
"model": "resolve",
"dataProvider": {
"method": "POST",
"url": "n2o/data/mi2"
},
"pageId": "_"
},
"meta": {
"success": {
"refresh": {
"datasources": [
"_main"
]
},
"redirect": {
"path": "/test",
"pathMapping": {},
"queryMapping": {},
"target": "application"
}
},
"fail": {}
}
}
Смена favicon и других статичных элементов
Чтобы поменять иконку приложения favicon, необходимо:
- Написать реализацию
StaticCustomizationController
- Указать путь расположения новой иконки, реализовав метод
faviconPath()
Пример:
@Controller
public class MyFaviconController extends StaticCustomizationController {
@Value("${n2o.favicon.path}")
private String path;
@Override
protected String faviconPath() {
return path;
}
}
Также с помощью реализации StaticCustomizationController
можно переопределить получение других статичных элементов.