Merge branch 'refs/heads/feature/SUPPORT-8956_mfe' into SUPPORT-8943_seamlessness
# Conflicts: # pom.xml # resources/src/main/resources/business-model/Список заявок на пользователя/Обработка заявки на добавление пользователя.page # resources/src/main/resources/business-model/Список заявок на пользователя/Создание заявки на добавление пользователя.page # resources/src/main/resources/business-model/Список заявок на пользователя/Создать заявку на деактивацию.page # resources/src/main/resources/business-model/Список заявок на пользователя/Создать заявку на изменение.page # resources/src/main/resources/business-model/Список заявок на пользователя/Список заявок.page # resources/src/main/resources/business-model/Управление пользователями/Группы редактирование.page # resources/src/main/resources/business-model/Управление пользователями/Группы создание.page # resources/src/main/resources/business-model/Управление пользователями/Группы.page # resources/src/main/resources/business-model/Управление пользователями/Организации.page # resources/src/main/resources/business-model/Управление пользователями/Организация редактирование(создание).page # resources/src/main/resources/business-model/Управление пользователями/Пользователи редактирование.page # resources/src/main/resources/business-model/Управление пользователями/Пользователи создание.page # resources/src/main/resources/business-model/Управление пользователями/Пользователи.page # resources/src/main/resources/business-model/Управление пользователями/Роли редактирование (создание).page # resources/src/main/resources/business-model/Управление пользователями/Роли.page # resources/src/main/resources/business-model/Управление пользователями/Функции безопасности.page
This commit is contained in:
commit
c69b5d4c33
100 changed files with 1712 additions and 4968 deletions
1
frontend/.env
Normal file
1
frontend/.env
Normal file
|
|
@ -0,0 +1 @@
|
|||
MFE_BASE_URL=/mfe/account-applications
|
||||
32
frontend/normalize-css-path.js
Normal file
32
frontend/normalize-css-path.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
var fs = require('fs');
|
||||
var mfeBaseUrlKey = 'MFE_BASE_URL';
|
||||
var srcUrlRegex = /url\((\\?["'])?(?!data:)\S+(\\?["'])?\)/g;
|
||||
function normalizeCssPaths(params) {
|
||||
params.paths = params.paths ? params.paths : [];
|
||||
params.paths.forEach(function (path) { return normalizeCssPath(path, params.outDir); });
|
||||
}
|
||||
exports.normalizeCssPaths = normalizeCssPaths;
|
||||
function normalizeCssPath(path, outputDirectory) {
|
||||
console.log("Start processing " + path);
|
||||
var css = fs.readFileSync(path, 'utf8');
|
||||
var counter = 0;
|
||||
var processedCss = css.replace(srcUrlRegex, function (srcUrl) {
|
||||
if (srcUrl.search(outputDirectory) != -1)
|
||||
return srcUrl;
|
||||
var fileName = getFileName(srcUrl);
|
||||
var processedUrl = "url('" + outputDirectory + "/" + fileName + "')";
|
||||
counter++;
|
||||
console.log("Replaced " + srcUrl + " -> " + processedUrl);
|
||||
return processedUrl;
|
||||
});
|
||||
console.log("Replaced " + counter + " urls");
|
||||
fs.writeFileSync(path, processedCss);
|
||||
}
|
||||
function getFileName(srcUrl) {
|
||||
var url = srcUrl.substring(4, srcUrl.length - 1); // unbox 'url(...)'
|
||||
url = url.replace(/(\\?["'])/g, '');
|
||||
var urlPaths = url.split('/');
|
||||
return urlPaths[urlPaths.length - 1].split('?')[0];
|
||||
}
|
||||
33
frontend/normalize-css-path.ts
Normal file
33
frontend/normalize-css-path.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
const fs = require('fs');
|
||||
|
||||
const srcUrlRegex = /url\((\\?["'])?(?!data:)\S+(\\?["'])?\)/g;
|
||||
|
||||
export function normalizeCssPaths(params: {paths: string[], outDir: string}) {
|
||||
params.paths = params.paths ? params.paths : [];
|
||||
params.paths.forEach(path => normalizeCssPath(path, params.outDir));
|
||||
}
|
||||
|
||||
function normalizeCssPath(path: string, outputDirectory: string) {
|
||||
console.log(`Start processing ${path}`);
|
||||
const css: string = fs.readFileSync(path, 'utf8');
|
||||
let counter = 0;
|
||||
|
||||
const processedCss = css.replace(srcUrlRegex, (srcUrl: string) => {
|
||||
if (srcUrl.search(outputDirectory) != -1) return srcUrl;
|
||||
|
||||
let fileName = getFileName(srcUrl);
|
||||
let processedUrl = `url('${outputDirectory}/${fileName}')`;
|
||||
counter++;
|
||||
console.log(`Replaced ${srcUrl} -> ${processedUrl}`);
|
||||
return processedUrl;
|
||||
});
|
||||
console.log(`Replaced ${counter} urls`);
|
||||
fs.writeFileSync(path, processedCss);
|
||||
}
|
||||
|
||||
function getFileName(srcUrl: string): string {
|
||||
let url = srcUrl.substring(4, srcUrl.length - 1); // unbox 'url(...)'
|
||||
url = url.replace(/(\\?["'])/g, '');
|
||||
let urlPaths = url.split('/');
|
||||
return urlPaths[urlPaths.length - 1].split('?')[0];
|
||||
}
|
||||
32
frontend/package-lock.json
generated
32
frontend/package-lock.json
generated
|
|
@ -3276,6 +3276,38 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "16.4.7",
|
||||
"resolved": "https://repo.micord.ru/repository/npm-all/dotenv/-/dotenv-16.4.7.tgz",
|
||||
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
|
||||
"dev": true
|
||||
},
|
||||
"dotenv-defaults": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://repo.micord.ru/repository/npm-all/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz",
|
||||
"integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dotenv": "^8.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://repo.micord.ru/repository/npm-all/dotenv/-/dotenv-8.6.0.tgz",
|
||||
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"dotenv-webpack": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://repo.micord.ru/repository/npm-all/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz",
|
||||
"integrity": "sha512-owK1JcsPkIobeqjVrk6h7jPED/W6ZpdFsMPR+5ursB7/SdgDyO+VzAU+szK8C8u3qUhtENyYnj8eyXMR5kkGag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dotenv-defaults": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"downloadjs": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://repo.micord.ru/repository/npm-all/downloadjs/-/downloadjs-1.4.8.tgz",
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@
|
|||
"cross-env": "5.2.1",
|
||||
"css-loader": "6.11.0",
|
||||
"del": "2.2.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"dotenv-webpack": "^8.1.0",
|
||||
"file-loader": "6.2.0",
|
||||
"html-webpack-plugin": "5.6.0",
|
||||
"mini-css-extract-plugin": "2.9.1",
|
||||
|
|
|
|||
41
frontend/src/resources/css/font-faces.css
Normal file
41
frontend/src/resources/css/font-faces.css
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* @font-face from bootstrap-icons
|
||||
*/
|
||||
@font-face {
|
||||
font-display: block;
|
||||
font-family: "bootstrap-icons";
|
||||
src: url("../../../node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff2?24e3eb84d0bcaf83d77f904c78ac1f47") format("woff2"),
|
||||
url("../../../node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff?24e3eb84d0bcaf83d77f904c78ac1f47") format("woff");
|
||||
}
|
||||
|
||||
/*
|
||||
* @font-face from font-awesome
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
src: url('../../../node_modules/font-awesome/fonts/fontawesome-webfont.eot?v=4.7.0');
|
||||
src: url('../../../node_modules/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),
|
||||
url('../../../node_modules/font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),
|
||||
url('../../../node_modules/font-awesome/fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),
|
||||
url('../../../node_modules/font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),
|
||||
url('../../../node_modules/font-awesome/fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Golos';
|
||||
src: url('../fonts/golos-regular.ttf');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'GolosM';
|
||||
src: url('../fonts/golos-medium.ttf');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'GolosUI';
|
||||
src: url('../fonts/golos-ul-regular.ttf');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'GolosUIM';
|
||||
src: url('../fonts/golos-ul-medium.ttf');
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<div *ngIf="(currentSession | async)?.authorities.includes('USER_MANAGEMENT.USER.LIST') ||
|
||||
(currentSession | async)?.authorities.includes('USER_MANAGEMENT.GROUP.LIST') ||
|
||||
(currentSession | async)?.authorities.includes('USER_MANAGEMENT.ROLE.LIST') ||
|
||||
(currentSession | async)?.authorities.includes('USER_MANAGEMENT.ORG_UNIT.LIST') ||
|
||||
(currentSession | async)?.authorities.includes('USER_MANAGEMENT.AUTHORITY.LIST')" ngbDropdown class="nav-item" [placement]="placement">
|
||||
<button class="nav-link bi bi-gear-fill" id="adminDropdownMenu" ngbDropdownToggle title="Администрирование"></button>
|
||||
<div ngbDropdownMenu aria-labelledby="adminDropdownMenu">
|
||||
<button *ngIf="(currentSession | async)?.authorities.includes('USER_MANAGEMENT.USER.LIST')"
|
||||
routerLink="/user-management/users" ngbDropdownItem>
|
||||
Пользователи
|
||||
</button>
|
||||
<button *ngIf="(currentSession | async)?.authorities.includes('USER_MANAGEMENT.GROUP.LIST')"
|
||||
routerLink="/user-management/groups" ngbDropdownItem>
|
||||
Группы
|
||||
</button>
|
||||
<button *ngIf="(currentSession | async)?.authorities.includes('USER_MANAGEMENT.ROLE.LIST')"
|
||||
routerLink="/user-management/roles" ngbDropdownItem>
|
||||
Роли
|
||||
</button>
|
||||
<button *ngIf="(currentSession | async)?.authorities.includes('USER_MANAGEMENT.ORG_UNIT.LIST')"
|
||||
routerLink="/user-management/org-units" ngbDropdownItem>
|
||||
Организации
|
||||
</button>
|
||||
<button *ngIf="(currentSession | async)?.authorities.includes('USER_MANAGEMENT.AUTHORITY.LIST')"
|
||||
routerLink="/user-management/authorities" ngbDropdownItem>
|
||||
Безопасность действий
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
<nav class="header" *ngIf="currentSession | async as session" id="webbpm-header">
|
||||
<nav class="header" id="webbpm-header">
|
||||
<div class="header-logo">
|
||||
<div class="logo"><a routerLink="/"></a></div>
|
||||
<div class="main-page">ЦЕНТРАЛИЗОВАННОЕ УПРАВЛЕНИЕ УЧЕТНЫМИ ЗАПИСЯМИ</div>
|
||||
</div>
|
||||
<div class="header-menu">
|
||||
<admin-menu [placement]="'bottom'"></admin-menu>
|
||||
<div ngbDropdown class="logout" log-out></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
<div class="confirm">
|
||||
<div class="form-logo">
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div>
|
||||
<h2>Подтверждение почты</h2>
|
||||
|
||||
<div *ngIf="verificationStatus.toString() === 'VERIFYING'">
|
||||
Подтверждение...
|
||||
</div>
|
||||
<div *ngIf="verificationStatus.toString() === 'VERIFIED'">
|
||||
<div class="alert alert-success">
|
||||
Адрес электронной почты успешно подтвержден
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="verificationStatus.toString() === 'FAILED'">
|
||||
<div class="alert alert-danger">{{ errorMessage }}</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="(currentSession | async) == null">
|
||||
<a href="#/login"><span class="fa fa-lock"></span>Войти</a><br/>
|
||||
<a href="#/registration">Зарегистрироваться</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<button class="nav-link bi bi-person-fill" ngbDropdownToggle title="Пользователь"></button>
|
||||
<div ngbDropdownMenu *ngIf="currentSession | async as session">
|
||||
<div class="user-info">
|
||||
<div class="user-fio">{{session.fullUserName}}</div>
|
||||
<div class="user-login">{{session.username}}</div>
|
||||
<div class="user-department">{{getOrgUnitName()}}</div>
|
||||
</div>
|
||||
<button ngbDropdownItem *ngIf="isLogoutButtonVisible()" (click)="logout()">Выход</button>
|
||||
</div>
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
<div class="form-signin">
|
||||
<form #formComponent="ngForm">
|
||||
<div class="alert alert-success" [hidden]="!confirmationSent">На ваш почтовый адрес было отправлено письмо. Подтвердите почту, чтобы войти в систему
|
||||
</div>
|
||||
<div class="alert alert-danger" [hidden]="!errorMessage">{{errorMessage}}</div>
|
||||
|
||||
<div class="logo">
|
||||
<h2>ЦЕНТРАЛИЗОВАННОЕ УПРАВЛЕНИЕ<br />УЧЕТНЫМИ ЗАПИСЯМИ</h2>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-group">
|
||||
<input type="text" name="username" class="form-control" placeholder=" " required autofocus [(ngModel)]="username" maxlength="100">
|
||||
<label>Логин</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-group">
|
||||
<input
|
||||
[type]="passwordType ? 'text' : 'password'"
|
||||
name="password"
|
||||
class="form-control field-password-view"
|
||||
placeholder=" " required
|
||||
[(ngModel)]="password"
|
||||
maxlength="100"
|
||||
>
|
||||
<label>Пароль</label>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">
|
||||
<i
|
||||
(click)="togglePasswordType()"
|
||||
class="fa"
|
||||
[ngClass]="{
|
||||
'fa-eye': passwordType,
|
||||
'fa-eye-slash': !passwordType
|
||||
}"
|
||||
></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="msg-text"><a href="#/reset-password">Восстановить пароль</a></div>-->
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<!--<esia-login-button></esia-login-button>-->
|
||||
<button type="submit" class="btn btn-primary" (click)="formComponent.form.valid && login()">Войти</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
<div class="form-signup">
|
||||
<div class="form-logo">
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="form-new-password">
|
||||
<form #formComponent="ngForm">
|
||||
<div [hidden]="!errorMessage" class="alert alert-danger">{{ errorMessage }}</div>
|
||||
<p class="has-account">Вспомнили пароль?
|
||||
<a href="#/login"><span class="fa fa-lock"></span>Войти</a></p>
|
||||
|
||||
<p class="has-account">Задайте новый пароль</p>
|
||||
|
||||
<div class="row">
|
||||
<label>Пароль</label>
|
||||
<div class="input-group">
|
||||
<input
|
||||
#passwordInput="ngModel"
|
||||
[(ngModel)]="password"
|
||||
[type]="passwordType ? 'text' : 'password'"
|
||||
class="form-control"
|
||||
maxlength="32"
|
||||
minlength="6"
|
||||
name="password"
|
||||
pattern="^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$"
|
||||
required
|
||||
(change)="validPasswords()"
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">
|
||||
<i
|
||||
(click)="togglePasswordType()"
|
||||
class="fa"
|
||||
[ngClass]="{
|
||||
'fa-eye': passwordType,
|
||||
'fa-eye-slash': !passwordType
|
||||
}"
|
||||
></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="passwordInput.invalid && (passwordInput.dirty || passwordInput.touched)">
|
||||
<div *ngIf="passwordInput.errors.required" class="msg-alert">Поле обязательно
|
||||
</div>
|
||||
<div *ngIf="passwordInput.errors.minlength" class="msg-alert">Пароль должен
|
||||
содержать как минимум 6 символов
|
||||
</div>
|
||||
<div *ngIf="passwordInput.errors.pattern" class="msg-alert">Пароль должен
|
||||
содержать заглавные и прописные буквы и как минимум 1 цифру
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Подтверждение пароля</label>
|
||||
<div class="input-group">
|
||||
<input
|
||||
#confirmPasswordInput="ngModel"
|
||||
[(ngModel)]="confirmPassword"
|
||||
[type]="confirmPasswordType ? 'text' : 'password'"
|
||||
class="form-control"
|
||||
maxlength="32"
|
||||
minlength="6"
|
||||
name="confirmPassword"
|
||||
pattern="^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$"
|
||||
required
|
||||
(change)="validPasswords()"
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">
|
||||
<i
|
||||
(click)="toggleConfirmPasswordType()"
|
||||
class="fa"
|
||||
[ngClass]="{
|
||||
'fa-eye': confirmPasswordType,
|
||||
'fa-eye-slash': !confirmPasswordType
|
||||
}"
|
||||
></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="confirmPasswordInput.invalid && (confirmPasswordInput.dirty || confirmPasswordInput.touched)">
|
||||
<div *ngIf="confirmPasswordInput.errors.required" class="msg-alert">Поле обязательно
|
||||
</div>
|
||||
<div *ngIf="confirmPasswordInput.errors.minlength" class="msg-alert">Пароль должен
|
||||
содержать как минимум 6 символов
|
||||
</div>
|
||||
<div *ngIf="confirmPasswordInput.errors.pattern" class="msg-alert">Пароль должен
|
||||
содержать заглавные и прописные буквы и как минимум 1 цифру
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reset-password-btn-box">
|
||||
<button
|
||||
(click)="formComponent.form.valid && validPasswords() && changePassword()"
|
||||
[disabled]="!formComponent.form.valid && !validPasswords()"
|
||||
class="btn btn-primary"
|
||||
type="submit"
|
||||
>
|
||||
Изменить пароль
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
<div class="form-signup">
|
||||
<div class="form-logo">
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="form-register">
|
||||
<form #formComponent="ngForm">
|
||||
<div [hidden]="!errorMessage" class="alert alert-danger">{{ errorMessage }}</div>
|
||||
<h2>Регистрация</h2>
|
||||
<p class="has-account">Уже зарегистрированы?
|
||||
<a href="#/login"><span class="fa fa-lock"></span>Войти</a></p>
|
||||
|
||||
<div class="row">
|
||||
<label>Имя</label>
|
||||
<input
|
||||
#name="ngModel"
|
||||
[(ngModel)]="username"
|
||||
class="form-control"
|
||||
maxlength="100"
|
||||
name="username"
|
||||
required
|
||||
type="text"
|
||||
>
|
||||
<div *ngIf="name.invalid && (name.dirty || name.touched)">
|
||||
<div *ngIf="name.errors.required" class="msg-alert">Поле обязательно</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Адрес эл. почты</label>
|
||||
<input
|
||||
#emailInput="ngModel"
|
||||
[(ngModel)]="email"
|
||||
class="form-control"
|
||||
email
|
||||
maxlength="100"
|
||||
name="email"
|
||||
required
|
||||
type="email"
|
||||
>
|
||||
<div *ngIf="emailInput.invalid && (emailInput.dirty || emailInput.touched)">
|
||||
<div *ngIf="emailInput.errors.required" class="msg-alert">Поле обязательно</div>
|
||||
<div *ngIf="emailInput.errors.email" class="msg-alert">Неверный формат адреса
|
||||
эл. почты
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Номер телефона</label>
|
||||
<international-phone-number
|
||||
#phoneInput="ngModel"
|
||||
[(ngModel)]="phoneNumber"
|
||||
[defaultCountry]="'ru'"
|
||||
[pattern]="'^\\+(?!7 ?\\d{11})[0-9 ]+$'"
|
||||
maxlength="20"
|
||||
minlength="8"
|
||||
name="phoneNumber"
|
||||
placeholder="+79991112233"
|
||||
(focusout)="phoneInputFocusOut()"
|
||||
required
|
||||
></international-phone-number>
|
||||
<div *ngIf="phoneInput.invalid && (phoneInput.dirty || phoneIsTouched)">
|
||||
<div *ngIf="phone.selectedCountry">
|
||||
<div *ngIf="phoneHasOnlyDialCode()" class="msg-alert">Поле обязательно</div>
|
||||
<div *ngIf="!phoneHasOnlyDialCode()" class="msg-alert">Введите корректный номер</div>
|
||||
</div>
|
||||
<div *ngIf="!phone.selectedCountry">
|
||||
<div *ngIf="phoneInput.errors.required" class="msg-alert">Поле обязательно</div>
|
||||
<div *ngIf="!phoneInput.errors.required" class="msg-alert">Введите код страны</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Пароль</label>
|
||||
<div class="input-group">
|
||||
<input
|
||||
#passwordInput="ngModel"
|
||||
[(ngModel)]="password"
|
||||
[type]="fieldType ? 'text' : 'password'"
|
||||
class="form-control"
|
||||
maxlength="32"
|
||||
minlength="8"
|
||||
name="password"
|
||||
[pattern]="passwordPattern"
|
||||
required
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">
|
||||
<i
|
||||
(click)="toggleFieldType()"
|
||||
class="fa"
|
||||
[ngClass]="{
|
||||
'fa-eye': fieldType,
|
||||
'fa-eye-slash': !fieldType
|
||||
}"
|
||||
></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="passwordInput.invalid && (passwordInput.dirty || passwordInput.touched)">
|
||||
<div *ngIf="passwordInput.errors.required" class="msg-alert">Поле обязательно
|
||||
</div>
|
||||
<div *ngIf="passwordInput.errors.minlength" class="msg-alert">Пароль должен
|
||||
содержать как минимум 8 символов
|
||||
</div>
|
||||
<div *ngIf="passwordInput.errors.pattern" class="msg-alert" [innerText]="passwordPatternErrorMessage">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="register-btn-box">
|
||||
<button
|
||||
(click)="formComponent.form.valid && register()"
|
||||
[disabled]="!formComponent.form.valid"
|
||||
class="btn btn-primary"
|
||||
type="submit"
|
||||
>
|
||||
Зарегистрироваться
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="consent" [innerHTML]="consent" class="consent"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
<div class="form-signup">
|
||||
<div class="form-logo">
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="form-reset-password">
|
||||
<form #formComponent="ngForm">
|
||||
<div [hidden]="!errorMessage" class="alert alert-danger">{{ errorMessage }}</div>
|
||||
<p class="has-account">Вспомнили пароль?
|
||||
<a href="#/login"><span class="fa fa-lock"></span>Войти</a></p>
|
||||
|
||||
<p class="has-account">Укажите адрес эл. почты, который был указан при регистрации,
|
||||
на него пришлем временный пароль. Пароль сможете поменять в личном кабинете.
|
||||
</p>
|
||||
|
||||
<div class="row">
|
||||
<input
|
||||
#emailInput="ngModel"
|
||||
[(ngModel)]="email"
|
||||
class="form-control"
|
||||
email
|
||||
maxlength="100"
|
||||
name="email"
|
||||
required
|
||||
type="email"
|
||||
>
|
||||
<label>Адрес эл. почты</label>
|
||||
<div *ngIf="emailInput.invalid && (emailInput.dirty || emailInput.touched)" class="msg-text">
|
||||
<div *ngIf="emailInput.errors.required" class="msg-alert">Поле обязательно</div>
|
||||
<div *ngIf="emailInput.errors.email" class="msg-alert">Неверный формат адреса эл. почты
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<button
|
||||
(click)="formComponent.form.valid && resetPassword()"
|
||||
[disabled]="!formComponent.form.valid"
|
||||
class="btn btn-primary"
|
||||
type="submit"
|
||||
>
|
||||
Восстановить
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
39
frontend/src/resources/template/webbpm/jwt-form.html
Normal file
39
frontend/src/resources/template/webbpm/jwt-form.html
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<div class="form-signin">
|
||||
<form #formComponent="ngForm">
|
||||
<div class="row">
|
||||
<label>Имя</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="name" class="form-control" placeholder="Имя" required autofocus
|
||||
[(ngModel)]="name">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Название подразделения</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="realm" class="form-control" placeholder="Название подразделения" required
|
||||
[(ngModel)]="realm">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Роль</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="role" class="form-control" placeholder="Роль" required
|
||||
[(ngModel)]="role">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Domain id</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="domain_id" class="form-control" placeholder="Id подразделения" required
|
||||
[(ngModel)]="domainId">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="login-btn-box">
|
||||
<button type="submit" class="btn btn-primary" (click)="enter()">Войти</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
14
frontend/src/resources/template/webbpm/mfe-webbpm.html
Normal file
14
frontend/src/resources/template/webbpm/mfe-webbpm.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<div webbpm class="webbpm account-applications">
|
||||
<div class="wrapper">
|
||||
<app-header *ngIf="headerVisible">
|
||||
</app-header>
|
||||
|
||||
<div class="container">
|
||||
<div class="container-inside" id="webbpm-angular-application-container">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
<app-footer *ngIf="footerVisible">
|
||||
</app-footer>
|
||||
</div>
|
||||
</div>
|
||||
1
frontend/src/resources/template/webbpm/mfe-wrapper.html
Normal file
1
frontend/src/resources/template/webbpm/mfe-wrapper.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<mfe-webbpm style="all: initial; display: block; height: 100vh"></mfe-webbpm>
|
||||
17
frontend/src/ts/account_applications/ErvuCheckUserRole.ts
Normal file
17
frontend/src/ts/account_applications/ErvuCheckUserRole.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import {AnalyticalScope, Behavior, Source, Visible} from "@webbpm/base-package";
|
||||
import {AuthorizationService} from "../modules/app/service/authorization.service";
|
||||
|
||||
@AnalyticalScope(Behavior)
|
||||
export class ErvuCheckUserRole extends Behavior{
|
||||
private authService: AuthorizationService;
|
||||
|
||||
public initialize(): void {
|
||||
super.initialize();
|
||||
this.authService = this.injector.get(AuthorizationService);
|
||||
}
|
||||
|
||||
@Visible()
|
||||
public hasRole(@Source("roles") role: string): boolean {
|
||||
return this.authService.hasRole(role);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import {AnalyticalScope, Behavior, TextField} from "@webbpm/base-package";
|
||||
import {AuthorizationService} from "../../modules/app/service/authorization.service";
|
||||
|
||||
@AnalyticalScope("TextField")
|
||||
export class SetCurrentRecruitmentIdAsDefValue extends Behavior {
|
||||
private textField: TextField;
|
||||
private authService: AuthorizationService;
|
||||
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.textField = this.getScript('component.ControlWithValue');
|
||||
this.authService = this.injector.get(AuthorizationService);
|
||||
}
|
||||
|
||||
start(): void {
|
||||
super.start();
|
||||
|
||||
if (this.textField && this.textField.isPristine() && this.authService &&
|
||||
this.authService.getCurrentSession()) {
|
||||
this.textField.setValue(this.authService.getDomainId());
|
||||
this.getContext().getChangeDetector().detectChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import {AnalyticalScope, Behavior, SessionStore, TextField} from "@webbpm/base-package";
|
||||
|
||||
@AnalyticalScope("TextField")
|
||||
export class SetCurrentUserIdAsDefValue extends Behavior {
|
||||
private textField: TextField;
|
||||
private sessionStore: SessionStore;
|
||||
|
||||
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.textField = this.getScript('component.ControlWithValue');
|
||||
this.sessionStore = this.injector.get(SessionStore);
|
||||
}
|
||||
|
||||
start(): void {
|
||||
super.start();
|
||||
|
||||
if (this.textField && this.textField.isPristine() && this.sessionStore &&
|
||||
this.sessionStore.getSession()) {
|
||||
this.textField.setValue(this.sessionStore.getSession().userAccountId);
|
||||
this.getContext().getChangeDetector().detectChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
74
frontend/src/ts/mfe-app-tools.ts
Normal file
74
frontend/src/ts/mfe-app-tools.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import {platformBrowserDynamic} from "@angular/platform-browser-dynamic";
|
||||
import {MfeConfigurationProvider} from "./modules/mfe/provider/mfe-configuration.provider";
|
||||
import {NgModuleRef} from "@angular/core";
|
||||
|
||||
let childEventHandlerFromContainer = null;
|
||||
|
||||
export type ChildEventType = 'navigate' | 'token-request'
|
||||
export type ParentEventType = 'navigate';
|
||||
|
||||
export function fireMfeEventToContainer(eventType: ChildEventType, eventData: any): Promise<any> {
|
||||
if (typeof childEventHandlerFromContainer === 'function') {
|
||||
return childEventHandlerFromContainer(eventType, eventData);
|
||||
}
|
||||
else {
|
||||
throw new Error(
|
||||
'Event fired from child MFE to container before being bootstrapped as MFE App',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function bootstrapMfeApp(createApp: () => Promise<NgModuleRef<unknown> | void>) {
|
||||
function mount(
|
||||
element: HTMLElement,
|
||||
settings: {
|
||||
standalone: boolean,
|
||||
useShadowDom?: boolean,
|
||||
containerBaseUrl?: string,
|
||||
componentBaseUrl?: string,
|
||||
startUrl: string,
|
||||
childEventHandler?: any,
|
||||
params?: any
|
||||
} = {
|
||||
standalone: false,
|
||||
startUrl: '/mfe/account-applications'
|
||||
},
|
||||
) {
|
||||
let containerBaseUrl = settings.containerBaseUrl || ''; // префикс ресурса
|
||||
let startUrl = settings.startUrl || ''; // ресурс хост-приложения
|
||||
MfeConfigurationProvider.setPageBaseUrl(joinPath(containerBaseUrl, startUrl));
|
||||
|
||||
element.appendChild(createContainerForBootstrap())
|
||||
|
||||
childEventHandlerFromContainer = settings.childEventHandler;
|
||||
|
||||
createApp();
|
||||
return {
|
||||
parentEventHandler(eventType: ParentEventType, url: string) {
|
||||
},
|
||||
unmount() {
|
||||
console.log("Unmounting account-applications application");
|
||||
platformBrowserDynamic().destroy();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
mount,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function createContainerForBootstrap(): HTMLElement {
|
||||
let mfeBootstrapContainer = document.createElement('div');
|
||||
mfeBootstrapContainer.setAttribute(MfeConfigurationProvider.BASE_COMPONENT_ATTRIBUTE, '');
|
||||
return mfeBootstrapContainer;
|
||||
}
|
||||
|
||||
export function joinPath(...paths: string[]): string {
|
||||
return '/' + paths
|
||||
.filter(path => path)
|
||||
.map(path => path.endsWith('/') ? path.substring(0, path.length - 1) : path)
|
||||
.map(path => path.startsWith('/') ? path.substring(1, path.length) : path)
|
||||
.join('/')
|
||||
}
|
||||
18
frontend/src/ts/mfe-main.aot.ts
Normal file
18
frontend/src/ts/mfe-main.aot.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import 'zone.js/dist/zone';
|
||||
|
||||
import {enableProdMode} from "@angular/core";
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import {bootstrapMfeApp} from './mfe-app-tools';
|
||||
// @ts-ignore
|
||||
import {MfeWebbpmModuleNgFactory} from "./modules/mfe/mfe-webbpm.module.ngfactory";
|
||||
|
||||
window['dev_mode'] = false;
|
||||
enableProdMode();
|
||||
|
||||
const mount = bootstrapMfeApp(() => {
|
||||
return platformBrowserDynamic()
|
||||
.bootstrapModuleFactory(MfeWebbpmModuleNgFactory)
|
||||
.catch((err) => console.error(err));
|
||||
}).mount;
|
||||
|
||||
export {mount};
|
||||
|
|
@ -1,70 +1,39 @@
|
|||
import {NgModule} from "@angular/core";
|
||||
import {RouterModule, Routes} from "@angular/router";
|
||||
import {AccessDeniedComponent} from "./component/access-denied.component";
|
||||
import {LoginComponent} from "./component/login.component";
|
||||
import {AuthenticationGuard, ConfirmExitGuard, SignedInGuard} from "@webbpm/base-package";
|
||||
import {RegisterComponent} from "./component/register.component";
|
||||
import {ConfirmUserEmailComponent} from "./component/confirm-user-email.component";
|
||||
import {ResetPasswordComponent} from "./component/reset-password.component";
|
||||
import {NewPasswordComponent} from "./component/new-password.component";
|
||||
import {ConfirmExitGuard} from "@webbpm/base-package";
|
||||
import {RolesGuard} from "./guard/RolesGuard";
|
||||
|
||||
|
||||
const appRoutes: Routes = [
|
||||
{
|
||||
path: 'login',
|
||||
component: LoginComponent,
|
||||
canActivate: [SignedInGuard]
|
||||
},
|
||||
{
|
||||
path: 'home',
|
||||
loadChildren: 'generated-sources/page-home.module#PagehomeModule',
|
||||
canActivate: [AuthenticationGuard, ConfirmExitGuard]
|
||||
canActivate: [ConfirmExitGuard, RolesGuard]
|
||||
},
|
||||
{
|
||||
path: 'app_list',
|
||||
loadChildren: 'generated-sources/page-app_list.module#Pageapp_listModule',
|
||||
canActivate: [AuthenticationGuard, ConfirmExitGuard]
|
||||
canActivate: [ConfirmExitGuard, RolesGuard]
|
||||
},
|
||||
{
|
||||
path: 'add_user_application',
|
||||
loadChildren: 'generated-sources/page-add_user_application.module#Pageadd_user_applicationModule',
|
||||
canActivate: [AuthenticationGuard, ConfirmExitGuard]
|
||||
canActivate: [ConfirmExitGuard, RolesGuard]
|
||||
},
|
||||
{
|
||||
path: 'edit_user_application',
|
||||
loadChildren: 'generated-sources/page-edit_user_application.module#Pageedit_user_applicationModule',
|
||||
canActivate: [AuthenticationGuard, ConfirmExitGuard]
|
||||
canActivate: [ConfirmExitGuard, RolesGuard]
|
||||
},
|
||||
{
|
||||
path: 'block_user_application',
|
||||
loadChildren: 'generated-sources/page-block_user_application.module#Pageblock_user_applicationModule',
|
||||
canActivate: [AuthenticationGuard, ConfirmExitGuard]
|
||||
canActivate: [ConfirmExitGuard, RolesGuard]
|
||||
},
|
||||
{
|
||||
path: 'process_application/:id',
|
||||
loadChildren: 'generated-sources/page-process_application.module#Pageprocess_applicationModule',
|
||||
canActivate: [AuthenticationGuard, ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'access-denied',
|
||||
component: AccessDeniedComponent,
|
||||
canActivate: [AuthenticationGuard, ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'registration',
|
||||
component: RegisterComponent,
|
||||
canActivate: [SignedInGuard]
|
||||
},
|
||||
{
|
||||
path: 'confirm',
|
||||
component: ConfirmUserEmailComponent
|
||||
},
|
||||
{
|
||||
path: 'reset-password',
|
||||
component: ResetPasswordComponent
|
||||
},
|
||||
{
|
||||
path: 'new-password',
|
||||
component: NewPasswordComponent
|
||||
canActivate: [ConfirmExitGuard, RolesGuard]
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -11,23 +11,16 @@ import {
|
|||
ProgressIndicationService,
|
||||
SecurityModule
|
||||
} from "@webbpm/base-package";
|
||||
import {AdminMenuComponent} from "./component/admin-menu.component";
|
||||
import {AppHeaderComponent} from "./component/app-header.component";
|
||||
import {AppFooterComponent} from "./component/app-footer.component";
|
||||
import {LogOutComponent} from "./component/logout.component";
|
||||
import {LoginComponent} from "./component/login.component";
|
||||
import {AccessDeniedComponent} from "./component/access-denied.component";
|
||||
import {ApplicationVersionComponent} from "./component/application-version.component";
|
||||
import {RouterModule} from "@angular/router";
|
||||
import {RegisterComponent} from "./component/register.component";
|
||||
import {ConfirmUserEmailComponent} from "./component/confirm-user-email.component";
|
||||
import {InternationalPhoneNumberModule} from "ngx-international-phone-number";
|
||||
import {ResetPasswordComponent} from "./component/reset-password.component";
|
||||
import {NewPasswordComponent} from "./component/new-password.component";
|
||||
import {AppProgressIndicationComponent} from "./component/app-progress-indication.component";
|
||||
import {AppProgressIndicationService} from "./service/app-progress-indication.service";
|
||||
import {VBoxLoadValues} from "../../account_applications/component/container/VBoxLoadValues";
|
||||
import {ErvuAccountTextFieldGridEditor} from "../../account_applications/component/editablegrid/editors/ErvuAccountTextFieldGridEditor";
|
||||
import {TokenInterceptor} from "./interceptor/token.interceptor.service";
|
||||
import {DropdownTreeViewComponent}from "../../account_applications/component/field/DropdownTreeViewComponent";
|
||||
import {DropdownTreeviewSelectComponent} from "../../account_applications/component/external/ngx-treeview/dropdown-treeview-select/dropdown-treeview-select.component";
|
||||
import {TreeviewModule} from "ngx-treeview";
|
||||
|
|
@ -36,15 +29,7 @@ registerLocaleData(localeRu);
|
|||
export const DIRECTIVES = [
|
||||
forwardRef(() => AppHeaderComponent),
|
||||
forwardRef(() => AppFooterComponent),
|
||||
forwardRef(() => AdminMenuComponent),
|
||||
forwardRef(() => ApplicationVersionComponent),
|
||||
forwardRef(() => LogOutComponent),
|
||||
forwardRef(() => LoginComponent),
|
||||
forwardRef(() => AccessDeniedComponent),
|
||||
forwardRef(() => RegisterComponent),
|
||||
forwardRef(() => ConfirmUserEmailComponent),
|
||||
forwardRef(() => ResetPasswordComponent),
|
||||
forwardRef(() => NewPasswordComponent),
|
||||
forwardRef(() => AppProgressIndicationComponent),
|
||||
forwardRef(() => VBoxLoadValues),
|
||||
forwardRef(() => DropdownTreeViewComponent),
|
||||
|
|
@ -73,7 +58,8 @@ export const DIRECTIVES = [
|
|||
DIRECTIVES
|
||||
],
|
||||
providers: [
|
||||
{ provide: ProgressIndicationService, useClass: AppProgressIndicationService }
|
||||
TokenInterceptor,
|
||||
{provide: ProgressIndicationService, useClass: AppProgressIndicationService }
|
||||
],
|
||||
bootstrap: [],
|
||||
entryComponents: [AppProgressIndicationComponent]
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
import {ChangeDetectionStrategy, Component, Input} from "@angular/core";
|
||||
import {UserService, Session} from "@webbpm/base-package";
|
||||
import {NgbDropdownConfig, Placement} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {Observable} from "rxjs";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'admin-menu',
|
||||
templateUrl: '../../../../../src/resources/template/app/component/admin_menu.html',
|
||||
providers: [NgbDropdownConfig],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AdminMenuComponent {
|
||||
|
||||
@Input()
|
||||
public placement: Placement = 'bottom';
|
||||
public currentSession: Observable<Session>;
|
||||
|
||||
constructor(protected userService: UserService, public config: NgbDropdownConfig) {
|
||||
this.config.placement = this.placement;
|
||||
this.currentSession = this.userService.getCurrentSession();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
import {ChangeDetectionStrategy, Component} from "@angular/core";
|
||||
import {Router} from "@angular/router";
|
||||
import {UserService, Session} from "@webbpm/base-package";
|
||||
import {Observable} from "rxjs";
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from "@angular/core";
|
||||
import {AuthorizationService} from "../service/authorization.service";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
|
|
@ -11,10 +9,16 @@ import {Observable} from "rxjs";
|
|||
})
|
||||
export class AppHeaderComponent {
|
||||
|
||||
public currentSession: Observable<Session>;
|
||||
name: string;
|
||||
realm: string;
|
||||
|
||||
constructor(protected userService: UserService,
|
||||
protected router: Router) {
|
||||
this.currentSession = this.userService.getCurrentSession();
|
||||
constructor(protected authService: AuthorizationService,
|
||||
protected cd: ChangeDetectorRef) {
|
||||
authService.onSessionUpdate
|
||||
.subscribe(session => {
|
||||
this.name = session.name;
|
||||
this.realm = session.realm;
|
||||
cd.markForCheck()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from "@angular/core";
|
||||
import {Session, UserService} from "@webbpm/base-package";
|
||||
import {Observable} from "rxjs";
|
||||
|
||||
enum VerificationStatus {
|
||||
VERIFYING = "VERIFYING",
|
||||
VERIFIED = "VERIFIED",
|
||||
FAILED = "FAILED"
|
||||
}
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: "confirm",
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
templateUrl: "../../../../../src/resources/template/app/component/confirm-user-email.html"
|
||||
})
|
||||
export class ConfirmUserEmailComponent {
|
||||
public verificationStatus = VerificationStatus.VERIFYING;
|
||||
public currentSession: Observable<Session>;
|
||||
|
||||
@Input()
|
||||
public errorMessage: string;
|
||||
|
||||
constructor(private router: Router, private userService: UserService,
|
||||
private route: ActivatedRoute, private cd: ChangeDetectorRef) {
|
||||
this.currentSession = this.userService.getCurrentSession();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const link: string = this.route.snapshot.queryParamMap.get("link");
|
||||
// remove link from url to prevent http referer leakage
|
||||
this.router.navigate([], { relativeTo: this.route, replaceUrl: true });
|
||||
this.userService.confirm(
|
||||
link,
|
||||
(reason) => {
|
||||
this.verificationStatus = VerificationStatus.FAILED;
|
||||
if (reason.status === 404) {
|
||||
this.errorMessage = 'Ссылка недействительна. Требуется повторная регистрация.';
|
||||
}
|
||||
else {
|
||||
this.errorMessage = 'Произошла ошибка, обратитесь в службу технической поддержки!';
|
||||
}
|
||||
this.cd.markForCheck();
|
||||
})
|
||||
.then(() => {
|
||||
this.verificationStatus = VerificationStatus.VERIFIED;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import {Component, Input} from "@angular/core";
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import {UserService, Credentials} from "@webbpm/base-package";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: "login",
|
||||
templateUrl: "../../../../../src/resources/template/app/component/login.html"
|
||||
})
|
||||
export class LoginComponent {
|
||||
|
||||
@Input()
|
||||
public username: string;
|
||||
|
||||
@Input()
|
||||
public password: string;
|
||||
public passwordType: boolean;
|
||||
|
||||
@Input()
|
||||
public errorMessage: string;
|
||||
|
||||
@Input()
|
||||
public confirmationSent: boolean;
|
||||
|
||||
constructor(private router: Router, private userService: UserService,
|
||||
private route: ActivatedRoute) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.confirmationSent = this.route.snapshot.queryParamMap.get('confirmationSent') === 'true';
|
||||
this.router.navigate([], { relativeTo: this.route, replaceUrl: true });
|
||||
}
|
||||
|
||||
public login(): void {
|
||||
let credentials: Credentials = new Credentials();
|
||||
credentials.username = this.username;
|
||||
credentials.password = this.password;
|
||||
|
||||
this.userService.login(credentials, "Password")
|
||||
.then(() => this.router.navigateByUrl("/"),
|
||||
(reason: any) => {
|
||||
switch (reason.status) {
|
||||
case 401: {
|
||||
this.errorMessage = "Неправильный логин или пароль";
|
||||
break;
|
||||
}
|
||||
case 404: {
|
||||
this.errorMessage = "Приложение стартует. Пожалуйста, подождите...";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.errorMessage =
|
||||
"Произошла неизвестная ошибка, обратитесь в службу технической поддержки!";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public goToRegister(): void {
|
||||
this.router.navigateByUrl("/register");
|
||||
}
|
||||
|
||||
togglePasswordType(): void {
|
||||
this.passwordType = !this.passwordType;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
import {Component} from "@angular/core";
|
||||
import {UserService, Session, AuthenticationMethodService} from "@webbpm/base-package";
|
||||
import {Observable} from "rxjs";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: "[log-out]",
|
||||
templateUrl: "../../../../../src/resources/template/app/component/log_out.html"
|
||||
})
|
||||
export class LogOutComponent {
|
||||
|
||||
public currentSession: Observable<Session>;
|
||||
|
||||
constructor(private userService: UserService, private authenticationMethodService: AuthenticationMethodService) {
|
||||
this.currentSession = userService.getCurrentSession();
|
||||
}
|
||||
|
||||
public logout(): void {
|
||||
this.userService.logout();
|
||||
}
|
||||
|
||||
public getCurrentUserName(): string {
|
||||
return this.userService.getCurrentUserName();
|
||||
}
|
||||
|
||||
public getFullUserName(): string {
|
||||
return this.userService.getFullUserName();
|
||||
}
|
||||
|
||||
public isLogoutButtonVisible(): boolean {
|
||||
return this.authenticationMethodService.isFormAuth();
|
||||
}
|
||||
|
||||
public getOrgUnitName(): string {
|
||||
return this.userService.getOrgUnitName();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import {Component, Input} from "@angular/core";
|
||||
import {Session, UserPasswordResetRequestDto, UserService} from "@webbpm/base-package";
|
||||
import {Observable} from "rxjs";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: "newPassword",
|
||||
templateUrl: "../../../../../src/resources/template/app/component/new_password.html"
|
||||
})
|
||||
export class NewPasswordComponent {
|
||||
public currentSession: Observable<Session>;
|
||||
|
||||
private token: string;
|
||||
|
||||
@Input()
|
||||
public password: string;
|
||||
public passwordType: boolean;
|
||||
|
||||
@Input()
|
||||
public confirmPassword: string;
|
||||
public confirmPasswordType: boolean;
|
||||
|
||||
@Input()
|
||||
public errorMessage: string;
|
||||
|
||||
constructor(private router: Router, private userService: UserService,
|
||||
private route: ActivatedRoute) {
|
||||
this.currentSession = this.userService.getCurrentSession();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.token = this.route.snapshot.queryParamMap.get("token");
|
||||
|
||||
this.router.navigate([], {relativeTo: this.route, replaceUrl: true});
|
||||
|
||||
if (this.token == undefined || this.token === '') {
|
||||
this.errorMessage = 'Ссылка недействительна. Требуется повторить восстановление пароля.';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public changePassword(): void {
|
||||
let dto: UserPasswordResetRequestDto = new UserPasswordResetRequestDto();
|
||||
dto.password = this.password;
|
||||
dto.passwordConfirm = this.confirmPassword;
|
||||
this.userService.changePassword(dto, this.token)
|
||||
.then(() => this.router.navigateByUrl("/"),
|
||||
() => {
|
||||
this.errorMessage =
|
||||
'Произошла неизвестная ошибка, обратитесь в службу технической поддержки!';
|
||||
});
|
||||
}
|
||||
|
||||
togglePasswordType(): void {
|
||||
this.passwordType = !this.passwordType;
|
||||
}
|
||||
|
||||
toggleConfirmPasswordType(): void {
|
||||
this.confirmPasswordType = !this.confirmPasswordType;
|
||||
}
|
||||
|
||||
validPasswords(): boolean {
|
||||
if (this.password === undefined || this.confirmPassword === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let eq = this.password === this.confirmPassword;
|
||||
if (!eq) {
|
||||
this.errorMessage = 'Введенные пароли не совпадают. Убедитесь, что данные, ' +
|
||||
'введенные в поле "Подтверждение пароля", совпадают с теми, ' +
|
||||
'которые указаны в поле "Пароль".';
|
||||
}
|
||||
else {
|
||||
this.errorMessage = '';
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
import {Component, Input, ViewChild} from "@angular/core";
|
||||
import {AppConfigService, UserDto, UserService} from "@webbpm/base-package";
|
||||
import {Router} from "@angular/router";
|
||||
import {PhoneNumberComponent} from "ngx-international-phone-number";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: "register",
|
||||
templateUrl: "../../../../../src/resources/template/app/component/register.html"
|
||||
})
|
||||
export class RegisterComponent {
|
||||
|
||||
public passwordPattern: string;
|
||||
public passwordPatternErrorMessage: string;
|
||||
public errorMessage: string;
|
||||
|
||||
@Input()
|
||||
public username: string;
|
||||
|
||||
@Input()
|
||||
public email: string;
|
||||
@ViewChild(PhoneNumberComponent)
|
||||
public phone: PhoneNumberComponent;
|
||||
public phoneNumber: string;
|
||||
|
||||
public phoneIsTouched: boolean = false;
|
||||
@Input()
|
||||
public password: string;
|
||||
|
||||
public fieldType: boolean;
|
||||
|
||||
@Input()
|
||||
public consent: string;
|
||||
|
||||
constructor(private router: Router, private userService: UserService,private appConfigService: AppConfigService) {
|
||||
this.passwordPattern = appConfigService.getParamValue("password_pattern");
|
||||
this.passwordPatternErrorMessage = appConfigService.getParamValue("password_pattern_error");
|
||||
}
|
||||
|
||||
public register(): void {
|
||||
let user: UserDto = new UserDto();
|
||||
user.username = this.username;
|
||||
user.email = this.email;
|
||||
user.name = this.username;
|
||||
user.phone = this.phone.value;
|
||||
user.password = this.password;
|
||||
|
||||
this.userService.register(user)
|
||||
.then(() => this.router.navigateByUrl("/login?confirmationSent=true"),
|
||||
(reason: any) => {
|
||||
if (reason.status === 409) {
|
||||
this.errorMessage = 'Пользователь с данным почтовым адресом уже существует';
|
||||
}
|
||||
else {
|
||||
this.errorMessage = 'Произошла неизвестная ошибка, обратитесь в службу технической поддержки!';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toggleFieldType(): void {
|
||||
this.fieldType = !this.fieldType;
|
||||
}
|
||||
|
||||
phoneHasOnlyDialCode(): boolean {
|
||||
return this.phone.phoneNumber.trim() === this.phone.getSelectedCountryDialCode().trim()
|
||||
}
|
||||
|
||||
phoneInputFocusOut(): void {
|
||||
this.phoneIsTouched = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
import {Component, Input} from "@angular/core";
|
||||
import {UserService} from "@webbpm/base-package";
|
||||
import {Router} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: "resetPassword",
|
||||
templateUrl: "../../../../../src/resources/template/app/component/reset_password.html"
|
||||
})
|
||||
export class ResetPasswordComponent {
|
||||
|
||||
@Input()
|
||||
public email: string;
|
||||
|
||||
@Input()
|
||||
public errorMessage: string;
|
||||
|
||||
constructor(private router: Router, private userService: UserService) {
|
||||
}
|
||||
|
||||
resetPassword(): void {
|
||||
|
||||
this.userService.resetPassword(this.email)
|
||||
.then(() => this.router.navigateByUrl("/"),
|
||||
(reason: any) => {
|
||||
this.errorMessage =
|
||||
'Произошла неизвестная ошибка, обратитесь в службу технической поддержки!';
|
||||
});
|
||||
}
|
||||
}
|
||||
47
frontend/src/ts/modules/app/guard/RolesGuard.ts
Normal file
47
frontend/src/ts/modules/app/guard/RolesGuard.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
CanActivate,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
UrlTree
|
||||
} from "@angular/router";
|
||||
import {Injectable} from "@angular/core";
|
||||
import {AuthorizationService} from "../service/authorization.service";
|
||||
import {TokenProvider} from "../provider/token.provider";
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class RolesGuard implements CanActivate{
|
||||
|
||||
protected readonly allowedRoles: string[] = [];
|
||||
|
||||
constructor(protected authService: AuthorizationService,
|
||||
protected tokenProvider: TokenProvider,
|
||||
protected router: Router) {
|
||||
}
|
||||
|
||||
async canActivate(
|
||||
route: ActivatedRouteSnapshot, state: RouterStateSnapshot
|
||||
): Promise<boolean | UrlTree> {
|
||||
if (!await this.tokenProvider.getToken()) {
|
||||
return this.getUrlOnFailure()
|
||||
}
|
||||
|
||||
if (!this.authService.isAuthorized()) {
|
||||
return this.authService.getCurrentSession()
|
||||
.then(() => this.checkRoles() ? true : this.getUrlOnFailure())
|
||||
.catch(() => this.getUrlOnFailure());
|
||||
}
|
||||
else {
|
||||
return this.checkRoles();
|
||||
}
|
||||
}
|
||||
|
||||
protected getUrlOnFailure(): UrlTree {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected checkRoles(): boolean {
|
||||
return this.allowedRoles.length === 0
|
||||
|| this.authService.hasAnyRole(this.allowedRoles);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from "@angular/common/http";
|
||||
import {from, Observable} from "rxjs";
|
||||
import {TokenProvider} from "../provider/token.provider";
|
||||
import {Injectable} from "@angular/core";
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class TokenInterceptor implements HttpInterceptor{
|
||||
constructor(protected tokenProvider: TokenProvider) { }
|
||||
|
||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
return from(this.handle(request, next))
|
||||
}
|
||||
|
||||
private async handle(request: HttpRequest<any>, next: HttpHandler): Promise<HttpEvent<any>> {
|
||||
const token = await this.tokenProvider.getToken();
|
||||
request = request.clone({
|
||||
setHeaders: {Authorization: `Bearer ${token}`}
|
||||
});
|
||||
return next.handle(request).toPromise();
|
||||
}
|
||||
}
|
||||
3
frontend/src/ts/modules/app/provider/token.provider.ts
Normal file
3
frontend/src/ts/modules/app/provider/token.provider.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export class TokenProvider {
|
||||
public getToken(): Promise<string> { return null }
|
||||
}
|
||||
|
|
@ -10,16 +10,16 @@ export class AppProgressIndicationService {
|
|||
event.stopPropagation();
|
||||
};
|
||||
|
||||
private counter: number = 0;
|
||||
private focused: any;
|
||||
private ngbModalRef: NgbModalRef;
|
||||
private options: NgbModalOptions = {
|
||||
protected counter: number = 0;
|
||||
protected focused: any;
|
||||
protected ngbModalRef: NgbModalRef;
|
||||
protected options: NgbModalOptions = {
|
||||
backdrop: 'static',
|
||||
keyboard: false,
|
||||
windowClass: 'modal-center loader'
|
||||
};
|
||||
|
||||
constructor(private ngbModal: NgbModal) {
|
||||
constructor(protected ngbModal: NgbModal) {
|
||||
}
|
||||
|
||||
public showProgressBar(): boolean {
|
||||
|
|
@ -58,11 +58,11 @@ export class AppProgressIndicationService {
|
|||
}
|
||||
}
|
||||
|
||||
private showProgressIndicator() {
|
||||
protected showProgressIndicator() {
|
||||
this.ngbModalRef = this.ngbModal.open(AppProgressIndicationComponent, this.options);
|
||||
}
|
||||
|
||||
private hideProgressIndicator() {
|
||||
protected hideProgressIndicator() {
|
||||
this.ngbModalRef.dismiss('cancel');
|
||||
this.ngbModalRef = null;
|
||||
}
|
||||
|
|
|
|||
64
frontend/src/ts/modules/app/service/authorization.service.ts
Normal file
64
frontend/src/ts/modules/app/service/authorization.service.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {Subject} from "rxjs";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
|
||||
export interface UserSession {
|
||||
userId: string,
|
||||
name: string,
|
||||
realm: string,
|
||||
domainId: string,
|
||||
roles: string[]
|
||||
}
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class AuthorizationService {
|
||||
|
||||
private session: UserSession;
|
||||
|
||||
public onSessionUpdate: Subject<UserSession> = new Subject<UserSession>();
|
||||
|
||||
constructor(protected httpClient: HttpClient) {}
|
||||
|
||||
public getCurrentSession(): Promise<any> {
|
||||
if (this.session) return new Promise(resolve => resolve(this.session))
|
||||
return this.httpClient.get('session')
|
||||
.toPromise()
|
||||
.then((session: UserSession) => {
|
||||
this.session = session;
|
||||
this.onSessionUpdate.next(session);
|
||||
return session;
|
||||
})
|
||||
}
|
||||
|
||||
isAuthorized(): boolean {
|
||||
return !!this.session;
|
||||
}
|
||||
|
||||
hasAnyRole(roles: string[]): boolean {
|
||||
return this.isAuthorized() && roles.some(role => this.getRoles().includes(role));
|
||||
}
|
||||
|
||||
hasRole(role: string): boolean {
|
||||
return this.isAuthorized() && this.getRoles().includes(role);
|
||||
}
|
||||
|
||||
getUserId(): string{
|
||||
return this.isAuthorized() ? this.session.userId: null;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.isAuthorized() ? this.session.name : null;
|
||||
}
|
||||
|
||||
getRealm(): string {
|
||||
return this.isAuthorized() ? this.session.realm : null;
|
||||
}
|
||||
|
||||
getDomainId(): string {
|
||||
return this.isAuthorized() ? this.session.domainId : null;
|
||||
}
|
||||
|
||||
getRoles(): string[] {
|
||||
return this.isAuthorized() ? this.session.roles : null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import {Component, ViewEncapsulation} from "@angular/core";
|
||||
import {
|
||||
Event,
|
||||
NavigationCancel,
|
||||
NavigationEnd,
|
||||
NavigationError,
|
||||
NavigationStart,
|
||||
Router
|
||||
} from "@angular/router";
|
||||
import {ProgressIndicationService} from "@webbpm/base-package";
|
||||
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
encapsulation: ViewEncapsulation.ShadowDom,
|
||||
selector: 'mfe-webbpm',
|
||||
templateUrl: './../../../../../src/resources/template/webbpm/mfe-webbpm.html',
|
||||
styleUrls: ['./../../../../../src/resources/css/style.css'],
|
||||
})
|
||||
export class MfeWebbpmComponent {
|
||||
public headerVisible: boolean = true;
|
||||
public footerVisible: boolean = true;
|
||||
|
||||
constructor(private router: Router,
|
||||
private progressIndicationService: ProgressIndicationService) {
|
||||
router.events.subscribe((event: Event) => {
|
||||
if (event instanceof NavigationStart) {
|
||||
progressIndicationService.showProgressBar();
|
||||
}
|
||||
else if (event instanceof NavigationEnd
|
||||
|| event instanceof NavigationError
|
||||
|| event instanceof NavigationCancel) {
|
||||
progressIndicationService.hideProgressBar();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import {Component} from "@angular/core";
|
||||
import {MfeConfigurationProvider} from "../provider/mfe-configuration.provider";
|
||||
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: `[${MfeConfigurationProvider.BASE_COMPONENT_ATTRIBUTE}]`,
|
||||
templateUrl: './../../../../../src/resources/template/webbpm/mfe-wrapper.html',
|
||||
styleUrls: ['./../../../../../src/resources/css/font-faces.css']
|
||||
})
|
||||
export class MfeWrapperComponent {
|
||||
|
||||
}
|
||||
10
frontend/src/ts/modules/mfe/guard/MfeRolesGuard.ts
Normal file
10
frontend/src/ts/modules/mfe/guard/MfeRolesGuard.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import {RolesGuard} from "../../app/guard/RolesGuard";
|
||||
import {UrlTree} from "@angular/router";
|
||||
import {Injectable} from "@angular/core";
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class MfeRolesGuard extends RolesGuard {
|
||||
protected getUrlOnFailure(): UrlTree {
|
||||
return this.router.createUrlTree(['access-denied']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import {HTTP_INTERCEPTORS} from "@angular/common/http";
|
||||
import {
|
||||
FormDirtyInterceptor,
|
||||
HttpSecurityErrorInterceptor
|
||||
} from "@webbpm/base-package";
|
||||
import {MfeHttpBackendInterceptor} from "./mfe-http-backend-interceptor";
|
||||
import {TokenInterceptor} from "../../app/interceptor/token.interceptor.service";
|
||||
|
||||
|
||||
export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [
|
||||
{provide: HTTP_INTERCEPTORS, useClass: MfeHttpBackendInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityErrorInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true}
|
||||
];
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from "@angular/common/http";
|
||||
import {
|
||||
AppConfigService,
|
||||
ApplicationSettingsProvider,
|
||||
AppVersionService,
|
||||
TokenHeaderUtil
|
||||
} from "@webbpm/base-package";
|
||||
import {Observable} from "rxjs";
|
||||
import {MfeConfigurationProvider} from "../provider/mfe-configuration.provider";
|
||||
import {joinPath} from "../../../mfe-app-tools";
|
||||
|
||||
|
||||
export class MfeHttpBackendInterceptor implements HttpInterceptor {
|
||||
private static readonly CONTENT_TYPE_HEADER = 'Content-Type';
|
||||
private static readonly ENABLE_VERSION_IN_URL: string = "enable.version.in.url";
|
||||
private static readonly BACKEND_URL: string = "backend.url";
|
||||
private static readonly BACKEND_CONTEXT: string = "backend.context";
|
||||
|
||||
constructor(private appConfigService: AppConfigService,
|
||||
private appVersionService: AppVersionService) {
|
||||
}
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
req = TokenHeaderUtil.addHeader(
|
||||
req, MfeHttpBackendInterceptor.CONTENT_TYPE_HEADER, 'application/json;charset=UTF-8'
|
||||
);
|
||||
|
||||
let overrideObj
|
||||
|
||||
if (!req.url.startsWith(ApplicationSettingsProvider.RESOURCES_PATH)
|
||||
&& !req.url.startsWith('http:') && !req.url.startsWith('https:')) {
|
||||
|
||||
let appVersionInUrl = this.getVersion();
|
||||
let backendUrl = this.appConfigService.getParamValue(MfeHttpBackendInterceptor.BACKEND_URL);
|
||||
let backendContext = this.appConfigService.getParamValue(
|
||||
MfeHttpBackendInterceptor.BACKEND_CONTEXT);
|
||||
|
||||
let url;
|
||||
|
||||
if (backendUrl) {
|
||||
url = backendUrl;
|
||||
}
|
||||
else if (backendContext) {
|
||||
url = joinPath(
|
||||
MfeConfigurationProvider.MFE_BASE_URL,
|
||||
backendContext
|
||||
);
|
||||
}
|
||||
else {
|
||||
url = ApplicationSettingsProvider.BACKEND_URL;
|
||||
}
|
||||
|
||||
overrideObj = {url: `${url}${appVersionInUrl}/${req.url}`};
|
||||
}
|
||||
return next.handle(req.clone(overrideObj));
|
||||
}
|
||||
|
||||
private getVersion(): string {
|
||||
return this.appConfigService.getParamValue(MfeHttpBackendInterceptor.ENABLE_VERSION_IN_URL) ==
|
||||
"true" ? "-" + this.appVersionService.getAppVersion() : "";
|
||||
}
|
||||
}
|
||||
38
frontend/src/ts/modules/mfe/mfe-webbpm-routing.module.ts
Normal file
38
frontend/src/ts/modules/mfe/mfe-webbpm-routing.module.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import {ConfirmExitGuard} from "@webbpm/base-package";
|
||||
import {RolesGuard} from "../app/guard/RolesGuard";
|
||||
import {RouterModule, Routes} from "@angular/router";
|
||||
import {AccessDeniedComponent} from "../app/component/access-denied.component";
|
||||
import {NgModule} from "@angular/core";
|
||||
import {APP_BASE_HREF} from "@angular/common";
|
||||
import {MfeConfigurationProvider} from "./provider/mfe-configuration.provider";
|
||||
|
||||
const webbpmRoutes: Routes = [
|
||||
{
|
||||
path: 'access-denied',
|
||||
component: AccessDeniedComponent,
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
loadChildren: 'generated-sources/page-home.module#PagehomeModule',
|
||||
canActivate: [ConfirmExitGuard, RolesGuard],
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: '',
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
{provide: APP_BASE_HREF, useFactory: () => MfeConfigurationProvider.getPageBaseUrl()}
|
||||
],
|
||||
imports: [RouterModule.forRoot(webbpmRoutes, {
|
||||
useHash: false,
|
||||
onSameUrlNavigation: "reload"
|
||||
})],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class MfeWebbpmRoutingModule {
|
||||
|
||||
}
|
||||
69
frontend/src/ts/modules/mfe/mfe-webbpm.module.ts
Normal file
69
frontend/src/ts/modules/mfe/mfe-webbpm.module.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||
import {BrowserModule} from "@angular/platform-browser";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {NgbModule} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {ToastNoAnimationModule} from "ngx-toastr";
|
||||
import {AgGridModule} from "ag-grid-angular";
|
||||
import {AppRoutingModule} from "../app/app-routing.module";
|
||||
import {
|
||||
AppConfigService,
|
||||
AppVersionService,
|
||||
BpmnModule,
|
||||
ComponentsModule,
|
||||
CoreModule, ProgressIndicationService
|
||||
} from "@webbpm/base-package";
|
||||
import {AppModule} from "../app/app.module";
|
||||
import {MfeWebbpmRoutingModule} from "./mfe-webbpm-routing.module";
|
||||
import {ErrorHandler, NgModule} from "@angular/core";
|
||||
import {MfeWrapperComponent} from "./component/mfe-wrapper.component";
|
||||
import {MfeWebbpmComponent} from "./component/mfe-webbpm.component";
|
||||
import {AccessDeniedComponent} from "../app/component/access-denied.component";
|
||||
import {MfeAppVersionService} from "./service/mfe-app-version.service";
|
||||
import {MfeAppConfigService} from "./service/mfe-app-config.service";
|
||||
import {GlobalErrorHandler} from "../webbpm/handler/global-error.handler.prod";
|
||||
import {MfeProgressIndicationService} from "./service/mfe-progress-indication.service";
|
||||
import {MfeRolesGuard} from "./guard/MfeRolesGuard";
|
||||
import {RolesGuard} from "../app/guard/RolesGuard";
|
||||
import {TokenProvider} from "../app/provider/token.provider";
|
||||
import {MfeTokenProvider} from "./provider/mfe-token.provider";
|
||||
import {DEFAULT_HTTP_INTERCEPTOR_PROVIDERS} from "./interceptor/mfe-default-interceptors.prod";
|
||||
|
||||
|
||||
let IMPORTS = [
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
NgbModule,
|
||||
ToastNoAnimationModule.forRoot(),
|
||||
AgGridModule,
|
||||
AppRoutingModule,
|
||||
BpmnModule,
|
||||
CoreModule,
|
||||
ComponentsModule,
|
||||
AppModule,
|
||||
MfeWebbpmRoutingModule
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: IMPORTS,
|
||||
declarations: [
|
||||
MfeWrapperComponent,
|
||||
MfeWebbpmComponent,
|
||||
AccessDeniedComponent
|
||||
],
|
||||
exports: [],
|
||||
providers: [
|
||||
{provide: AppVersionService, useClass: MfeAppVersionService},
|
||||
{provide: AppConfigService, useClass: MfeAppConfigService},
|
||||
{provide: ErrorHandler, useClass: GlobalErrorHandler},
|
||||
{provide: ProgressIndicationService, useClass: MfeProgressIndicationService},
|
||||
{provide: RolesGuard, useClass: MfeRolesGuard},
|
||||
{provide: TokenProvider, useClass: MfeTokenProvider},
|
||||
DEFAULT_HTTP_INTERCEPTOR_PROVIDERS
|
||||
],
|
||||
bootstrap: [
|
||||
MfeWrapperComponent
|
||||
]
|
||||
})
|
||||
export class MfeWebbpmModule {
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
export class MfeConfigurationProvider {
|
||||
private static config; // way to avoid webpack optimization
|
||||
public static MFE_BASE_URL = process.env.MFE_BASE_URL || '';
|
||||
public static BASE_COMPONENT_ATTRIBUTE = 'mfe-webbpm-account-applications';
|
||||
|
||||
public static getPageBaseUrl(): string {
|
||||
return this.config.PAGE_BASE_URL
|
||||
}
|
||||
|
||||
public static setPageBaseUrl(pageBaseUrl: string) {
|
||||
if (!this.config) this.config = {};
|
||||
this.config.PAGE_BASE_URL = pageBaseUrl;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import {TokenProvider} from "../../app/provider/token.provider";
|
||||
import {fireMfeEventToContainer} from "../../../mfe-app-tools";
|
||||
|
||||
|
||||
export class MfeTokenProvider extends TokenProvider {
|
||||
getToken(): Promise<string> {
|
||||
return fireMfeEventToContainer('token-request', {});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {AppConfigService, ApplicationSettingsProvider} from "@webbpm/base-package";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {MfeConfigurationProvider} from "../provider/mfe-configuration.provider";
|
||||
import {joinPath} from "../../../mfe-app-tools";
|
||||
|
||||
|
||||
@Injectable({providedIn:'root'})
|
||||
export class MfeAppConfigService extends AppConfigService {
|
||||
|
||||
load(): Promise<any> {
|
||||
let http: HttpClient = this['http'];
|
||||
let url = joinPath(
|
||||
MfeConfigurationProvider.MFE_BASE_URL,
|
||||
ApplicationSettingsProvider.RESOURCES_PATH,
|
||||
'app-config.json'
|
||||
)
|
||||
return http
|
||||
.get(url)
|
||||
.toPromise()
|
||||
.then(configData => {
|
||||
this['mapParam'] = configData;
|
||||
})
|
||||
.catch((error: any): any => {
|
||||
console.error('Account Applications configuration file "app-config.json" could not be read');
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {ApplicationSettingsProvider, AppVersionService} from "@webbpm/base-package";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {MfeConfigurationProvider} from "../provider/mfe-configuration.provider";
|
||||
import {joinPath} from "../../../mfe-app-tools";
|
||||
|
||||
|
||||
@Injectable({providedIn:'root'})
|
||||
export class MfeAppVersionService extends AppVersionService {
|
||||
|
||||
load(): Promise<any> {
|
||||
let http: HttpClient = this['http'];
|
||||
let url = joinPath(
|
||||
MfeConfigurationProvider.MFE_BASE_URL,
|
||||
ApplicationSettingsProvider.RESOURCES_PATH,
|
||||
'app.version'
|
||||
)
|
||||
return http
|
||||
.get(url, {responseType: 'text'})
|
||||
.toPromise()
|
||||
.then(version => {
|
||||
this['appVersion'] = version;
|
||||
console.log(`Account Applications application version = ${version}`);
|
||||
})
|
||||
.catch((error: any): any => {
|
||||
console.error('Account Applications file "app.version" could not be read');
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {AppProgressIndicationService} from "../../app/service/app-progress-indication.service";
|
||||
import {
|
||||
AppProgressIndicationComponent
|
||||
} from "../../app/component/app-progress-indication.component";
|
||||
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class MfeProgressIndicationService extends AppProgressIndicationService {
|
||||
|
||||
protected showProgressIndicator() {
|
||||
const options = {...this.options};
|
||||
options.container = this.getContainerForProgressIndication();
|
||||
this.ngbModalRef = this.ngbModal.open(AppProgressIndicationComponent, options);
|
||||
}
|
||||
|
||||
getContainerForProgressIndication(): HTMLElement {
|
||||
return document.querySelector('mfe-webbpm')
|
||||
.shadowRoot.querySelector('[webbpm]');
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,12 @@ import {PreviewContainerComponent} from "./component/preview-container.component
|
|||
import {NgbModule} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {ToastNoAnimationModule} from "ngx-toastr";
|
||||
import {AppModule} from "../app/app.module";
|
||||
import {ComponentsModule, CoreModule, SecurityModule} from "@webbpm/base-package";
|
||||
import {
|
||||
ComponentsModule,
|
||||
CoreModule,
|
||||
SecurityModule,
|
||||
TaskParamsProvider
|
||||
} from "@webbpm/base-package";
|
||||
import {HTTP_INTERCEPTORS} from "@angular/common/http";
|
||||
import {HttpPreviewInterceptor} from "./service/http-preview-interceptor.service";
|
||||
|
||||
|
|
@ -37,6 +42,7 @@ let IMPORTS = [
|
|||
],
|
||||
exports: [],
|
||||
providers: [
|
||||
TaskParamsProvider,
|
||||
HTTP_INTERCEPTOR_PROVIDERS
|
||||
],
|
||||
bootstrap: [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
import {Component} from "@angular/core";
|
||||
import {Router} from "@angular/router";
|
||||
import {WebbpmTokenProvider} from "../provider/webbpm-token-provider";
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'token-form',
|
||||
templateUrl: '../../../../../src/resources/template/webbpm/jwt-form.html'
|
||||
})
|
||||
export class TokenFormComponent {
|
||||
|
||||
name: string = '';
|
||||
realm: string = '';
|
||||
domainId: string = '';
|
||||
role: string = '';
|
||||
|
||||
private readonly encodedHeader = this.encodeBase64Url(JSON.stringify({
|
||||
kid: "69d4a060-4053-4056-ae69-5e9bcf41125f",
|
||||
typ: "JWT",
|
||||
alg: "RS512"
|
||||
}));
|
||||
|
||||
constructor(private router: Router) {
|
||||
}
|
||||
|
||||
public enter() {
|
||||
localStorage.setItem(WebbpmTokenProvider.ACCESS_TOKEN_STORAGE_KEY, this.generateToken());
|
||||
this.router.navigateByUrl('');
|
||||
}
|
||||
|
||||
private generateToken(): string {
|
||||
let claims = {
|
||||
name: this.name,
|
||||
realm: this.realm,
|
||||
domain_id: this.domainId,
|
||||
roles: [this.role]
|
||||
};
|
||||
return `${this.encodedHeader}.${this.encodeBase64Url(JSON.stringify(claims))}.`
|
||||
}
|
||||
|
||||
private encodeBase64Url(input: string): string {
|
||||
let bytes = new TextEncoder().encode(input);
|
||||
const byteArray = Array.from(bytes);
|
||||
const binString = String.fromCharCode(...byteArray);
|
||||
return btoa(binString).replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/, '');
|
||||
}
|
||||
}
|
||||
11
frontend/src/ts/modules/webbpm/guard/WebbpmRolesGuard.ts
Normal file
11
frontend/src/ts/modules/webbpm/guard/WebbpmRolesGuard.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {RolesGuard} from "../../app/guard/RolesGuard";
|
||||
import {UrlTree} from "@angular/router";
|
||||
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class WebbpmRolesGuard extends RolesGuard {
|
||||
protected getUrlOnFailure(): UrlTree {
|
||||
return this.router.createUrlTree(['token-form']);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,9 +4,11 @@ import {
|
|||
HttpSecurityErrorInterceptor,
|
||||
HttpSecurityInterceptor
|
||||
} from "@webbpm/base-package";
|
||||
import {TokenInterceptor} from "../../app/interceptor/token.interceptor.service";
|
||||
|
||||
export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [
|
||||
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityErrorInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true}
|
||||
{provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import {HTTP_INTERCEPTORS} from "@angular/common/http";
|
||||
import {FormDirtyInterceptor, HttpSecurityInterceptor} from "@webbpm/base-package";
|
||||
import {DevHttpSecurityErrorInterceptor} from "./http-security-error-interceptor.dev";
|
||||
import {TokenInterceptor} from "../../app/interceptor/token.interceptor.service";
|
||||
|
||||
export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [
|
||||
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: DevHttpSecurityErrorInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true}
|
||||
{provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true},
|
||||
{provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
import {TokenProvider} from "../../app/provider/token.provider";
|
||||
|
||||
export class WebbpmTokenProvider implements TokenProvider {
|
||||
|
||||
public static readonly ACCESS_TOKEN_STORAGE_KEY = 'accessToken'
|
||||
|
||||
getToken(): Promise<string> {
|
||||
return new Promise(resolve => {
|
||||
resolve(localStorage.getItem(WebbpmTokenProvider.ACCESS_TOKEN_STORAGE_KEY));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
import {RouterModule, Routes} from "@angular/router";
|
||||
import {NgModule} from "@angular/core";
|
||||
import {
|
||||
AuthenticationGuard,
|
||||
ConfirmExitGuard
|
||||
} from "@webbpm/base-package";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'user-management',
|
||||
canActivate: [AuthenticationGuard],
|
||||
children: [
|
||||
{
|
||||
path: 'users',
|
||||
loadChildren: 'generated-sources/page-user-management-users.module#PageusermanagementusersModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'users/new',
|
||||
loadChildren: 'generated-sources/page-user-management-user-create.module#PageusermanagementusercreateModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'users/:id',
|
||||
loadChildren: 'generated-sources/page-user-management-user-edit.module#PageusermanagementusereditModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'org-units',
|
||||
loadChildren: 'generated-sources/page-user-management-org-units.module#PageusermanagementorgunitsModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'org-units/new',
|
||||
loadChildren: 'generated-sources/page-user-management-org-unit.module#PageusermanagementorgunitModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'org-units/:id',
|
||||
loadChildren: 'generated-sources/page-user-management-org-unit.module#PageusermanagementorgunitModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'roles',
|
||||
loadChildren: 'generated-sources/page-user-management-roles.module#PageusermanagementrolesModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'roles/new',
|
||||
loadChildren: 'generated-sources/page-user-management-role.module#PageusermanagementroleModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'roles/:id',
|
||||
loadChildren: 'generated-sources/page-user-management-role.module#PageusermanagementroleModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'groups',
|
||||
loadChildren: 'generated-sources/page-user-management-groups.module#PageusermanagementgroupsModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'groups/new',
|
||||
loadChildren: 'generated-sources/page-user-management-group-create.module#PageusermanagementgroupcreateModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'groups/:id',
|
||||
loadChildren: 'generated-sources/page-user-management-group-edit.module#PageusermanagementgroupeditModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
},
|
||||
{
|
||||
path: 'authorities',
|
||||
loadChildren: 'generated-sources/page-user-management-authorities.module#PageusermanagementauthoritiesModule',
|
||||
canActivate: [ConfirmExitGuard]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class UserManagementRoutingModule {
|
||||
|
||||
}
|
||||
|
|
@ -1,15 +1,20 @@
|
|||
import {NgModule} from "@angular/core";
|
||||
import {RouterModule, Routes} from "@angular/router";
|
||||
import {
|
||||
AuthenticationGuard,
|
||||
ConfirmExitGuard
|
||||
} from "@webbpm/base-package";
|
||||
import {TokenFormComponent} from "./component/token-form.component";
|
||||
import {RolesGuard} from "../app/guard/RolesGuard";
|
||||
|
||||
const webbpmRoutes: Routes = [
|
||||
{
|
||||
path: 'token-form',
|
||||
component: TokenFormComponent
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
loadChildren: 'generated-sources/page-home.module#PagehomeModule',
|
||||
canActivate: [AuthenticationGuard, ConfirmExitGuard],
|
||||
canActivate: [ConfirmExitGuard, RolesGuard],
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,12 +13,15 @@ import {
|
|||
BpmnModule,
|
||||
ComponentsModule,
|
||||
CoreModule,
|
||||
SecurityModule,
|
||||
} from "@webbpm/base-package";
|
||||
import {AppRoutingModule} from "../app/app-routing.module";
|
||||
import {UserManagementRoutingModule} from "./user-management-routing.module";
|
||||
import {GlobalErrorHandler} from "./handler/global-error.handler.prod";
|
||||
import {DEFAULT_HTTP_INTERCEPTOR_PROVIDERS} from "./interceptor/default-interceptors.prod";
|
||||
import {TokenFormComponent} from "./component/token-form.component";
|
||||
import {WebbpmTokenProvider} from "./provider/webbpm-token-provider";
|
||||
import {RolesGuard} from "../app/guard/RolesGuard";
|
||||
import {TokenProvider} from "../app/provider/token.provider";
|
||||
import {WebbpmRolesGuard} from "./guard/WebbpmRolesGuard";
|
||||
|
||||
let IMPORTS = [
|
||||
BrowserAnimationsModule,
|
||||
|
|
@ -28,11 +31,9 @@ let IMPORTS = [
|
|||
ToastNoAnimationModule.forRoot(),
|
||||
AgGridModule,
|
||||
AppRoutingModule,
|
||||
UserManagementRoutingModule,
|
||||
BpmnModule,
|
||||
CoreModule,
|
||||
ComponentsModule,
|
||||
SecurityModule,
|
||||
AppModule,
|
||||
WebbpmRoutingModule
|
||||
];
|
||||
|
|
@ -41,11 +42,14 @@ let IMPORTS = [
|
|||
imports: IMPORTS,
|
||||
declarations: [
|
||||
WebbpmComponent,
|
||||
HomeComponent
|
||||
HomeComponent,
|
||||
TokenFormComponent
|
||||
],
|
||||
exports: [],
|
||||
providers: [
|
||||
{provide: ErrorHandler, useClass: GlobalErrorHandler},
|
||||
{provide: TokenProvider, useClass: WebbpmTokenProvider},
|
||||
{provide: RolesGuard, useClass: WebbpmRolesGuard},
|
||||
DEFAULT_HTTP_INTERCEPTOR_PROVIDERS
|
||||
],
|
||||
bootstrap: [
|
||||
|
|
|
|||
|
|
@ -5,11 +5,19 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const Dotenv = require('dotenv-webpack');
|
||||
const {config} = require('dotenv')
|
||||
const {
|
||||
container: {ModuleFederationPlugin}
|
||||
} = webpack;
|
||||
const {normalizeCssPaths} = require("./normalize-css-path");
|
||||
|
||||
function _path(p) {
|
||||
return path.join(__dirname, p);
|
||||
}
|
||||
|
||||
config();
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
entry: {
|
||||
|
|
@ -90,6 +98,14 @@ module.exports = {
|
|||
},
|
||||
|
||||
plugins: [
|
||||
new Dotenv(),
|
||||
() => normalizeCssPaths({
|
||||
paths: [
|
||||
'./build/resources/css/font-faces.css.shim.ngstyle.js',
|
||||
'./build/resources/css/style.css.ngstyle.js'
|
||||
],
|
||||
outDir: `${process.env.MFE_BASE_URL || ''}/src/resources`,
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'index.webpack.html',
|
||||
filename: 'index.html',
|
||||
|
|
@ -111,6 +127,13 @@ module.exports = {
|
|||
jQuery: "jquery",
|
||||
"window.jQuery": "jquery",
|
||||
Popper: ['popper.js', 'default']
|
||||
}),
|
||||
new ModuleFederationPlugin({
|
||||
name: 'account_applications',
|
||||
filename: 'remoteEntry.js',
|
||||
exposes: {
|
||||
"./account-applications": "./build/scripts/mfe-main.aot",
|
||||
},
|
||||
})
|
||||
],
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue