@kuzntsv/uikit 1.0.12 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/kuzntsv-uikit-interceptors.mjs +0 -2
- package/fesm2022/kuzntsv-uikit-interceptors.mjs.map +1 -1
- package/fesm2022/kuzntsv-uikit-ui.mjs +170 -75
- package/fesm2022/kuzntsv-uikit-ui.mjs.map +1 -1
- package/fesm2022/kuzntsv-uikit.mjs +108 -99
- package/fesm2022/kuzntsv-uikit.mjs.map +1 -1
- package/package.json +1 -1
- package/types/kuzntsv-uikit-ui.d.ts +79 -29
- package/types/kuzntsv-uikit.d.ts +64 -30
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { inject, InjectionToken, makeEnvironmentProviders } from '@angular/core';
|
|
2
2
|
import { UIKIT_CONFIG, API_NAME, BYPASS_AUTH, UIKIT_NOTIFICATION_TOKEN, AuthEventService, REQUEST_TIMEOUT } from '@kuzntsv/uikit';
|
|
3
3
|
import { HttpErrorResponse } from '@angular/common/http';
|
|
4
|
-
import { Router } from '@angular/router';
|
|
5
4
|
import { throwError, catchError, TimeoutError } from 'rxjs';
|
|
6
5
|
import { timeout } from 'rxjs/operators';
|
|
7
6
|
|
|
@@ -28,7 +27,6 @@ const apiPrefixInterceptor = (req, next) => {
|
|
|
28
27
|
|
|
29
28
|
const coreAuthInterceptor = (req, next) => {
|
|
30
29
|
const config = inject(UIKIT_CONFIG);
|
|
31
|
-
const router = inject(Router);
|
|
32
30
|
const isAuthDisabled = !!config.auth.disabled;
|
|
33
31
|
if (isAuthDisabled) {
|
|
34
32
|
return next(req); // авторизация полностью отключена
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kuzntsv-uikit-interceptors.mjs","sources":["../../interceptors/src/api-prefix.interceptor.ts","../../interceptors/src/auth.interceptor.ts","../../interceptors/src/error.interceptor.ts","../../interceptors/src/timeout.interceptor.ts","../../interceptors/src/providers.ts","../../interceptors/src/public-api.ts","../../interceptors/src/kuzntsv-uikit-interceptors.ts"],"sourcesContent":["import { HttpInterceptorFn } from '@angular/common/http';\r\nimport { inject } from '@angular/core';\r\nimport { API_NAME, UIKIT_CONFIG } from '@kuzntsv/uikit';\r\n\r\nexport const apiPrefixInterceptor: HttpInterceptorFn = (req, next) => {\r\n // Если запрос уже абсолютный (начинается с http/https), игнорируем его\r\n if (req.url.startsWith('http://') || req.url.startsWith('https://')) {\r\n return next(req);\r\n }\r\n\r\n const config = inject(UIKIT_CONFIG);\r\n\r\n // Читаем, какой API запросил сервис (например, 'analytics')\r\n const apiKeys = req.context.get(API_NAME);\r\n\r\n // Ищем адрес в конфиге. Если не нашли такой ключ, берем 'default'\r\n const targetBaseUrl = config.apiUrls[apiKeys] || config.apiUrls['default'];\r\n\r\n if (!targetBaseUrl) {\r\n // Если даже default не настроен, пропускаем как есть\r\n return next(req);\r\n }\r\n\r\n // Нормализуем слеши при склеивании\r\n const baseUrl = targetBaseUrl.replace(/\\/$/, '');\r\n const url = req.url.startsWith('/') ? req.url : `/${req.url}`;\r\n\r\n const clonedReq = req.clone({ url: `${baseUrl}${url}` });\r\n return next(clonedReq);\r\n};\r\n","import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http';\r\nimport { inject } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { BYPASS_AUTH, UIKIT_CONFIG } from '@kuzntsv/uikit';\r\nimport { EMPTY, throwError } from 'rxjs';\r\n\r\nexport const coreAuthInterceptor: HttpInterceptorFn = (req, next) => {\r\n const config = inject(UIKIT_CONFIG);\r\n const router = inject(Router);\r\n\r\n const isAuthDisabled = !!config.auth.disabled;\r\n if (isAuthDisabled) {\r\n return next(req); // авторизация полностью отключена\r\n }\r\n\r\n // 0. маркер пропуска авторизации\r\n if (req.context.get(BYPASS_AUTH) === true) {\r\n return next(req); // Пропускаем проверку токенов для этого запроса\r\n }\r\n\r\n // 1. Проверяем, является ли URL публичным (не требующим авторизации)\r\n const isPublic = config.auth.publicUrls.some((url) => req.url.includes(url));\r\n if (isPublic) {\r\n return next(req);\r\n }\r\n\r\n // 2. Если в заголовках уже есть Authorization (например, передан вручную), отправляем как есть\r\n if (req.headers.has('Authorization')) {\r\n return next(req);\r\n }\r\n\r\n // 3. Пытаемся достать токен из LocalStorage по ключу из конфигурации\r\n const storageValue = localStorage.getItem(config.auth.userStorageKey);\r\n const user = storageValue ? JSON.parse(storageValue) : null;\r\n\r\n if (user && user.token) {\r\n // 4. Если токен есть, клонируем запрос и добавляем заголовок Bearer\r\n const authReq = req.clone({\r\n headers: req.headers\r\n .set('Authorization', `Bearer ${user.token}`)\r\n .set('User-Id', String(user.id))\r\n .set('Human-Id', String(user.idHuman)),\r\n });\r\n return next(authReq);\r\n }\r\n\r\n // 5. Если токена нет и запрос приватный — прерываем и редиректим на страницу логина\r\n // router.navigate([config.auth.loginRoute]);\r\n // 5. Если токена нет и запрос приватный — не редиректим вручную!\r\n // Просто кидаем 401 ошибку. Она сама прилетит в coreErrorInterceptor.\r\n return throwError(\r\n () =>\r\n new HttpErrorResponse({\r\n status: 401,\r\n statusText: 'Unauthorized',\r\n url: req.url,\r\n error: { message:'Запрос отменен: пользователь не авторизован' },\r\n }),\r\n );\r\n};\r\n","import { HttpInterceptorFn } from '@angular/common/http';\r\nimport { inject } from '@angular/core';\r\nimport { catchError, throwError, TimeoutError } from 'rxjs';\r\nimport { UIKIT_NOTIFICATION_TOKEN, AuthEventService } from '@kuzntsv/uikit';\r\n\r\n\r\n// Состояние для управления очередью запросов во время рефреша\r\nlet isRefreshing = false; // флаг того, что обновление уже идет\r\n// для ожидания токена\r\n// const refreshTokenSubject: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null);\r\n\r\nexport const coreErrorInterceptor: HttpInterceptorFn = (req, next) => {\r\n const notification = inject(UIKIT_NOTIFICATION_TOKEN, { optional: true });\r\n // const authService = inject(LibraryAuthService);\r\n // const config = inject(UIKIT_CONFIG);\r\n\r\n const eventService = inject(AuthEventService);\r\n\r\n return next(req).pipe(\r\n catchError((error: any) => { // Меняем тип на any, так как RxJS TimeoutError — это не HttpErrorResponse\r\n let errorMsg = 'Произошла непредвиденная ошибка';\r\n // Проверяем, что это ошибка 401 и запрос не шел на сам эндпоинт рефреша\r\n // const isRefreshRequest = req.url.includes(config.auth.refreshEndpoint);\r\n\r\n // 1. Проверяем, не является ли ошибка таймаутом RxJS\r\n if (error instanceof TimeoutError) {\r\n errorMsg = 'Время ожидания ответа от сервера истекло. Попробуйте позже.';\r\n notification?.error(errorMsg);\r\n return throwError(() => new Error(errorMsg));\r\n }\r\n\r\n switch (error.status) {\r\n case 0:\r\n errorMsg = 'Сервер не доступен';\r\n break;\r\n case 401:\r\n // if (!isRefreshRequest) {\r\n // // return handle401Error(req, next, authService, config);\r\n // }\r\n // else {\r\n eventService.notify401(); // Просто кидаем событие в шину\r\n errorMsg = 'Сессия истекла. Войдите заново.';\r\n // }\r\n break;\r\n case 403:\r\n errorMsg = 'Недостаточно прав для выполнения действия.';\r\n break;\r\n case 404:\r\n errorMsg = 'Ресурс не найден'; \r\n \r\n break;\r\n case 500:\r\n errorMsg = 'Ошибка сервера. Попробуйте позже.'; \r\n break;\r\n default:\r\n // Для 400 и прочих берем сообщение с бэка или дефолтное\r\n errorMsg = error.error?.message || error.message || errorMsg;\r\n break;\r\n }\r\n notification?.error(errorMsg);\r\n \r\n // Возвращаем исходную ошибку, чтобы вызывающий сервис/компонент \r\n // мог прочитать error.status или error.error при необходимости,\r\n // но при этом подменяем или дополняем сообщение.\r\n return throwError(() => error);\r\n })\r\n );\r\n};\r\n\r\n\r\n// // Функция управления очередью и вызова Refresh Token\r\n// function handle401Error(\r\n// req: HttpRequest<unknown>,\r\n// next: HttpHandlerFn,\r\n// authService: LibraryAuthService,\r\n// config: UikitConfig\r\n// ): Observable<any> {\r\n \r\n// if (!isRefreshing) {\r\n// isRefreshing = true;\r\n// refreshTokenSubject.next(null); // Сбрасываем старый токен в потоке ожидания\r\n\r\n// return authService.refreshToken().pipe(\r\n// switchMap((response) => {\r\n// isRefreshing = false;\r\n// refreshTokenSubject.next(response.accessToken); // Разблокируем стоящие в очереди запросы\r\n \r\n// // Повторяем текущий упавший запрос с НОВЫМ токеном\r\n// return next(injectNewToken(req, response.accessToken, config));\r\n// }),\r\n// catchError((refreshError) => {\r\n// isRefreshing = false;\r\n// return throwError(() => refreshError);\r\n// })\r\n// );\r\n// } else {\r\n// // Если обновление уже запущено другим запросом, текущий запрос \"встает в очередь\"\r\n// // и ждет, пока в refreshTokenSubject появится новое строковое значение токена\r\n// return refreshTokenSubject.pipe(\r\n// filter(token => token !== null),\r\n// take(1), // Берем только первое валидное значение и отписываемся\r\n// switchMap(newToken => {\r\n// // Повторяем запрос с обновленным токеном\r\n// return next(injectNewToken(req, newToken!, config));\r\n// })\r\n// );\r\n// }\r\n// }\r\n\r\n// // Хелпер для подстановки свежего токена в заголовки повторяемого запроса\r\n// function injectNewToken(req: HttpRequest<unknown>, token: string, config: any): HttpRequest<unknown> {\r\n// return req.clone({\r\n// headers: req.headers.set('Authorization', `Bearer ${token}`)\r\n// });\r\n// }","import { HttpInterceptorFn } from '@angular/common/http';\r\nimport { timeout } from 'rxjs/operators';\r\nimport { REQUEST_TIMEOUT } from '@kuzntsv/uikit';\r\n\r\nexport const timeoutInterceptor: HttpInterceptorFn = (req, next) => {\r\n const defaultTimeout = req.context.get(REQUEST_TIMEOUT);\r\n\r\n return next(req).pipe(\r\n timeout(defaultTimeout)\r\n );\r\n};","import { InjectionToken, makeEnvironmentProviders, EnvironmentProviders } from '@angular/core';\r\nimport { HttpInterceptorFn } from '@angular/common/http';\r\nimport { UIKIT_CONFIG, UikitConfig } from '@kuzntsv/uikit';\r\n\r\nimport { UikitInterceptors } from './public-api';\r\n\r\n// Это кастомный Multi-InjectionToken, в который мы прячем интерцепторы библиотеки\r\nexport const UIKIT_INTERCEPTORS = new InjectionToken<HttpInterceptorFn[]>('UikitInterceptors');\r\n\r\nexport function provideUikit(config: UikitConfig): EnvironmentProviders {\r\n return makeEnvironmentProviders([\r\n { provide: UIKIT_CONFIG, useValue: config },\r\n \r\n // Регистрируем интерцептор внутри нашего собственного токена\r\n { provide: UIKIT_INTERCEPTORS, useValue: UikitInterceptors, multi: true }\r\n ]);\r\n};\r\n\r\n","import { apiPrefixInterceptor } from \"./api-prefix.interceptor\";\r\nimport { coreAuthInterceptor } from \"./auth.interceptor\";\r\nimport { coreErrorInterceptor } from \"./error.interceptor\";\r\nimport { timeoutInterceptor } from \"./timeout.interceptor\";\r\n\r\n// Экспортируем готовый пирог для приложений\r\n// Порядок интерцепторов очень важен. Сначала должен отработать интерцептор авторизации \r\n// (чтобы проверить оригинальный относительный URL и прикрепить токен), \r\n// а затем интерцептор подстановки Base URL (превращающий путь в абсолютный).\r\nexport const UikitInterceptors = [\r\n coreErrorInterceptor, // 1. Ловит абсолютно ВСЕ ошибки: и сетевые, и таймауты, и искусственные 401\r\n apiPrefixInterceptor, // 2. Сначала превращаем URL в абсолютный (https://...)\r\n coreAuthInterceptor, // 3. Теперь проверяем publicUrls по полному пути и подставляем токен\r\n timeoutInterceptor // 4. Ближе всего к сети — контролирует время выполнения самого запроса\r\n];\r\n\r\nexport * from './providers';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;AAIO,MAAM,oBAAoB,GAAsB,CAAC,GAAG,EAAE,IAAI,KAAI;;AAEnE,IAAA,IAAI,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;AACnE,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB;AAEA,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC;;IAGnC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;;AAGzC,IAAA,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;IAE1E,IAAI,CAAC,aAAa,EAAE;;AAElB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB;;IAGA,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;IAChD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAA,CAAE;AAE7D,IAAA,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAA,EAAG,OAAO,CAAA,EAAG,GAAG,CAAA,CAAE,EAAE,CAAC;AACxD,IAAA,OAAO,IAAI,CAAC,SAAS,CAAC;AACxB,CAAC;;ACvBM,MAAM,mBAAmB,GAAsB,CAAC,GAAG,EAAE,IAAI,KAAI;AAClE,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC;AACnC,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAE7B,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ;IAC7C,IAAI,cAAc,EAAE;AAClB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB;;IAGA,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE;AACzC,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB;;IAGA,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC5E,IAAI,QAAQ,EAAE;AACZ,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB;;IAGA,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE;AACpC,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB;;AAGA,IAAA,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;AACrE,IAAA,MAAM,IAAI,GAAG,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,IAAI;AAE3D,IAAA,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE;;AAEtB,QAAA,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC;YACxB,OAAO,EAAE,GAAG,CAAC;iBACV,GAAG,CAAC,eAAe,EAAE,CAAA,OAAA,EAAU,IAAI,CAAC,KAAK,EAAE;iBAC3C,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;iBAC9B,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACzC,SAAA,CAAC;AACF,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB;;;;;AAMA,IAAA,OAAO,UAAU,CACf,MACE,IAAI,iBAAiB,CAAC;AACpB,QAAA,MAAM,EAAE,GAAG;AACX,QAAA,UAAU,EAAE,cAAc;QAC1B,GAAG,EAAE,GAAG,CAAC,GAAG;AACZ,QAAA,KAAK,EAAE,EAAE,OAAO,EAAC,6CAA6C,EAAE;AACjE,KAAA,CAAC,CACL;AACH,CAAC;;ACrDD;AACA,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB;AACA;AAEO,MAAM,oBAAoB,GAAsB,CAAC,GAAG,EAAE,IAAI,KAAI;AACnE,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,wBAAwB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;;AAIzE,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAE7C,IAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CACnB,UAAU,CAAC,CAAC,KAAU,KAAI;QACxB,IAAI,QAAQ,GAAG,iCAAiC;;;;AAKhD,QAAA,IAAI,KAAK,YAAY,YAAY,EAAE;YACjC,QAAQ,GAAG,6DAA6D;AACxE,YAAA,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC;YAC7B,OAAO,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC9C;AAEA,QAAA,QAAQ,KAAK,CAAC,MAAM;AAClB,YAAA,KAAK,CAAC;gBACJ,QAAQ,GAAG,oBAAoB;gBAC/B;AACF,YAAA,KAAK,GAAG;;;;;AAKJ,gBAAA,YAAY,CAAC,SAAS,EAAE,CAAC;gBACzB,QAAQ,GAAG,iCAAiC;;gBAE9C;AACF,YAAA,KAAK,GAAG;gBACN,QAAQ,GAAG,4CAA4C;gBACvD;AACF,YAAA,KAAK,GAAG;gBACN,QAAQ,GAAG,kBAAkB;gBAE7B;AACF,YAAA,KAAK,GAAG;gBACN,QAAQ,GAAG,mCAAmC;gBAC9C;AACF,YAAA;;AAEE,gBAAA,QAAQ,GAAG,KAAK,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,QAAQ;gBAC5D;;AAEJ,QAAA,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC;;;;AAK7B,QAAA,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC;IAChC,CAAC,CAAC,CACH;AACH,CAAC;AAGD;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;AC9GO,MAAM,kBAAkB,GAAsB,CAAC,GAAG,EAAE,IAAI,KAAI;IACjE,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AAEvD,IAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CACnB,OAAO,CAAC,cAAc,CAAC,CACxB;AACH,CAAC;;ACJD;MACa,kBAAkB,GAAG,IAAI,cAAc,CAAsB,mBAAmB;AAEvF,SAAU,YAAY,CAAC,MAAmB,EAAA;AAC9C,IAAA,OAAO,wBAAwB,CAAC;AAC9B,QAAA,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE;;QAG3C,EAAE,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,KAAK,EAAE,IAAI;AACxE,KAAA,CAAC;AACJ;AAAC;;ACXD;AACA;AACA;AACA;AACO,MAAM,iBAAiB,GAAG;AAC/B,IAAA,oBAAoB;AACpB,IAAA,oBAAoB;AACpB,IAAA,mBAAmB;AACnB,IAAA,kBAAkB;;;ACbpB;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"kuzntsv-uikit-interceptors.mjs","sources":["../../interceptors/src/api-prefix.interceptor.ts","../../interceptors/src/auth.interceptor.ts","../../interceptors/src/error.interceptor.ts","../../interceptors/src/timeout.interceptor.ts","../../interceptors/src/providers.ts","../../interceptors/src/public-api.ts","../../interceptors/src/kuzntsv-uikit-interceptors.ts"],"sourcesContent":["import { HttpInterceptorFn } from '@angular/common/http';\r\nimport { inject } from '@angular/core';\r\nimport { API_NAME, UIKIT_CONFIG } from '@kuzntsv/uikit';\r\n\r\nexport const apiPrefixInterceptor: HttpInterceptorFn = (req, next) => {\r\n // Если запрос уже абсолютный (начинается с http/https), игнорируем его\r\n if (req.url.startsWith('http://') || req.url.startsWith('https://')) {\r\n return next(req);\r\n }\r\n\r\n const config = inject(UIKIT_CONFIG);\r\n\r\n // Читаем, какой API запросил сервис (например, 'analytics')\r\n const apiKeys = req.context.get(API_NAME);\r\n\r\n // Ищем адрес в конфиге. Если не нашли такой ключ, берем 'default'\r\n const targetBaseUrl = config.apiUrls[apiKeys] || config.apiUrls['default'];\r\n\r\n if (!targetBaseUrl) {\r\n // Если даже default не настроен, пропускаем как есть\r\n return next(req);\r\n }\r\n\r\n // Нормализуем слеши при склеивании\r\n const baseUrl = targetBaseUrl.replace(/\\/$/, '');\r\n const url = req.url.startsWith('/') ? req.url : `/${req.url}`;\r\n\r\n const clonedReq = req.clone({ url: `${baseUrl}${url}` });\r\n return next(clonedReq);\r\n};\r\n","import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http';\r\nimport { inject } from '@angular/core';\r\nimport { BYPASS_AUTH, UIKIT_CONFIG } from '@kuzntsv/uikit';\r\nimport { throwError } from 'rxjs';\r\n\r\nexport const coreAuthInterceptor: HttpInterceptorFn = (req, next) => {\r\n const config = inject(UIKIT_CONFIG);\r\n\r\n const isAuthDisabled = !!config.auth.disabled;\r\n if (isAuthDisabled) {\r\n return next(req); // авторизация полностью отключена\r\n }\r\n\r\n // 0. маркер пропуска авторизации\r\n if (req.context.get(BYPASS_AUTH) === true) {\r\n return next(req); // Пропускаем проверку токенов для этого запроса\r\n }\r\n\r\n // 1. Проверяем, является ли URL публичным (не требующим авторизации)\r\n const isPublic = config.auth.publicUrls.some((url) => req.url.includes(url));\r\n if (isPublic) {\r\n return next(req);\r\n }\r\n\r\n // 2. Если в заголовках уже есть Authorization (например, передан вручную), отправляем как есть\r\n if (req.headers.has('Authorization')) {\r\n return next(req);\r\n }\r\n\r\n // 3. Пытаемся достать токен из LocalStorage по ключу из конфигурации\r\n const storageValue = localStorage.getItem(config.auth.userStorageKey);\r\n const user = storageValue ? JSON.parse(storageValue) : null;\r\n\r\n if (user && user.token) {\r\n // 4. Если токен есть, клонируем запрос и добавляем заголовок Bearer\r\n const authReq = req.clone({\r\n headers: req.headers\r\n .set('Authorization', `Bearer ${user.token}`)\r\n .set('User-Id', String(user.id))\r\n .set('Human-Id', String(user.idHuman)),\r\n });\r\n return next(authReq);\r\n }\r\n\r\n // 5. Если токена нет и запрос приватный — прерываем и редиректим на страницу логина\r\n // router.navigate([config.auth.loginRoute]);\r\n // 5. Если токена нет и запрос приватный — не редиректим вручную!\r\n // Просто кидаем 401 ошибку. Она сама прилетит в coreErrorInterceptor.\r\n return throwError(\r\n () =>\r\n new HttpErrorResponse({\r\n status: 401,\r\n statusText: 'Unauthorized',\r\n url: req.url,\r\n error: { message:'Запрос отменен: пользователь не авторизован' },\r\n }),\r\n );\r\n};\r\n","import { HttpInterceptorFn } from '@angular/common/http';\r\nimport { inject } from '@angular/core';\r\nimport { catchError, throwError, TimeoutError } from 'rxjs';\r\nimport { UIKIT_NOTIFICATION_TOKEN, AuthEventService } from '@kuzntsv/uikit';\r\n\r\n\r\n// Состояние для управления очередью запросов во время рефреша\r\nlet isRefreshing = false; // флаг того, что обновление уже идет\r\n// для ожидания токена\r\n// const refreshTokenSubject: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null);\r\n\r\nexport const coreErrorInterceptor: HttpInterceptorFn = (req, next) => {\r\n const notification = inject(UIKIT_NOTIFICATION_TOKEN, { optional: true });\r\n // const authService = inject(LibraryAuthService);\r\n // const config = inject(UIKIT_CONFIG);\r\n\r\n const eventService = inject(AuthEventService);\r\n\r\n return next(req).pipe(\r\n catchError((error: any) => { // Меняем тип на any, так как RxJS TimeoutError — это не HttpErrorResponse\r\n let errorMsg = 'Произошла непредвиденная ошибка';\r\n // Проверяем, что это ошибка 401 и запрос не шел на сам эндпоинт рефреша\r\n // const isRefreshRequest = req.url.includes(config.auth.refreshEndpoint);\r\n\r\n // 1. Проверяем, не является ли ошибка таймаутом RxJS\r\n if (error instanceof TimeoutError) {\r\n errorMsg = 'Время ожидания ответа от сервера истекло. Попробуйте позже.';\r\n notification?.error(errorMsg);\r\n return throwError(() => new Error(errorMsg));\r\n }\r\n\r\n switch (error.status) {\r\n case 0:\r\n errorMsg = 'Сервер не доступен';\r\n break;\r\n case 401:\r\n // if (!isRefreshRequest) {\r\n // // return handle401Error(req, next, authService, config);\r\n // }\r\n // else {\r\n eventService.notify401(); // Просто кидаем событие в шину\r\n errorMsg = 'Сессия истекла. Войдите заново.';\r\n // }\r\n break;\r\n case 403:\r\n errorMsg = 'Недостаточно прав для выполнения действия.';\r\n break;\r\n case 404:\r\n errorMsg = 'Ресурс не найден'; \r\n \r\n break;\r\n case 500:\r\n errorMsg = 'Ошибка сервера. Попробуйте позже.'; \r\n break;\r\n default:\r\n // Для 400 и прочих берем сообщение с бэка или дефолтное\r\n errorMsg = error.error?.message || error.message || errorMsg;\r\n break;\r\n }\r\n notification?.error(errorMsg);\r\n \r\n // Возвращаем исходную ошибку, чтобы вызывающий сервис/компонент \r\n // мог прочитать error.status или error.error при необходимости,\r\n // но при этом подменяем или дополняем сообщение.\r\n return throwError(() => error);\r\n })\r\n );\r\n};\r\n\r\n\r\n// // Функция управления очередью и вызова Refresh Token\r\n// function handle401Error(\r\n// req: HttpRequest<unknown>,\r\n// next: HttpHandlerFn,\r\n// authService: LibraryAuthService,\r\n// config: UikitConfig\r\n// ): Observable<any> {\r\n \r\n// if (!isRefreshing) {\r\n// isRefreshing = true;\r\n// refreshTokenSubject.next(null); // Сбрасываем старый токен в потоке ожидания\r\n\r\n// return authService.refreshToken().pipe(\r\n// switchMap((response) => {\r\n// isRefreshing = false;\r\n// refreshTokenSubject.next(response.accessToken); // Разблокируем стоящие в очереди запросы\r\n \r\n// // Повторяем текущий упавший запрос с НОВЫМ токеном\r\n// return next(injectNewToken(req, response.accessToken, config));\r\n// }),\r\n// catchError((refreshError) => {\r\n// isRefreshing = false;\r\n// return throwError(() => refreshError);\r\n// })\r\n// );\r\n// } else {\r\n// // Если обновление уже запущено другим запросом, текущий запрос \"встает в очередь\"\r\n// // и ждет, пока в refreshTokenSubject появится новое строковое значение токена\r\n// return refreshTokenSubject.pipe(\r\n// filter(token => token !== null),\r\n// take(1), // Берем только первое валидное значение и отписываемся\r\n// switchMap(newToken => {\r\n// // Повторяем запрос с обновленным токеном\r\n// return next(injectNewToken(req, newToken!, config));\r\n// })\r\n// );\r\n// }\r\n// }\r\n\r\n// // Хелпер для подстановки свежего токена в заголовки повторяемого запроса\r\n// function injectNewToken(req: HttpRequest<unknown>, token: string, config: any): HttpRequest<unknown> {\r\n// return req.clone({\r\n// headers: req.headers.set('Authorization', `Bearer ${token}`)\r\n// });\r\n// }","import { HttpInterceptorFn } from '@angular/common/http';\r\nimport { timeout } from 'rxjs/operators';\r\nimport { REQUEST_TIMEOUT } from '@kuzntsv/uikit';\r\n\r\nexport const timeoutInterceptor: HttpInterceptorFn = (req, next) => {\r\n const defaultTimeout = req.context.get(REQUEST_TIMEOUT);\r\n\r\n return next(req).pipe(\r\n timeout(defaultTimeout)\r\n );\r\n};","import { InjectionToken, makeEnvironmentProviders, EnvironmentProviders } from '@angular/core';\r\nimport { HttpInterceptorFn } from '@angular/common/http';\r\nimport { UIKIT_CONFIG, UikitConfig } from '@kuzntsv/uikit';\r\n\r\nimport { UikitInterceptors } from './public-api';\r\n\r\n// Это кастомный Multi-InjectionToken, в который мы прячем интерцепторы библиотеки\r\nexport const UIKIT_INTERCEPTORS = new InjectionToken<HttpInterceptorFn[]>('UikitInterceptors');\r\n\r\nexport function provideUikit(config: UikitConfig): EnvironmentProviders {\r\n return makeEnvironmentProviders([\r\n { provide: UIKIT_CONFIG, useValue: config },\r\n \r\n // Регистрируем интерцептор внутри нашего собственного токена\r\n { provide: UIKIT_INTERCEPTORS, useValue: UikitInterceptors, multi: true }\r\n ]);\r\n};\r\n\r\n","import { apiPrefixInterceptor } from \"./api-prefix.interceptor\";\r\nimport { coreAuthInterceptor } from \"./auth.interceptor\";\r\nimport { coreErrorInterceptor } from \"./error.interceptor\";\r\nimport { timeoutInterceptor } from \"./timeout.interceptor\";\r\n\r\n// Экспортируем готовый пирог для приложений\r\n// Порядок интерцепторов очень важен. Сначала должен отработать интерцептор авторизации \r\n// (чтобы проверить оригинальный относительный URL и прикрепить токен), \r\n// а затем интерцептор подстановки Base URL (превращающий путь в абсолютный).\r\nexport const UikitInterceptors = [\r\n coreErrorInterceptor, // 1. Ловит абсолютно ВСЕ ошибки: и сетевые, и таймауты, и искусственные 401\r\n apiPrefixInterceptor, // 2. Сначала превращаем URL в абсолютный (https://...)\r\n coreAuthInterceptor, // 3. Теперь проверяем publicUrls по полному пути и подставляем токен\r\n timeoutInterceptor // 4. Ближе всего к сети — контролирует время выполнения самого запроса\r\n];\r\n\r\nexport * from './providers';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, effect, Component, viewChild, HostListener, inject, Injectable, Directive, signal, Pipe, ChangeDetectorRef, ChangeDetectionStrategy, linkedSignal, NgZone, ElementRef, InjectionToken, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
-
import { Router, RouterLink
|
|
4
|
-
import {
|
|
2
|
+
import { input, output, effect, Component, viewChild, HostListener, inject, Injectable, computed, Directive, signal, Pipe, ChangeDetectorRef, ChangeDetectionStrategy, linkedSignal, NgZone, ElementRef, InjectionToken, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
+
import { Router, RouterLink } from '@angular/router';
|
|
4
|
+
import { startWith, Subscription, Subject, tap, switchMap, map as map$1, forkJoin, take, filter, ReplaySubject, finalize } from 'rxjs';
|
|
5
|
+
import { RoleService, NotificationService, HIDE_ROLE_MARKER, UIKIT_NOTIFICATION_TOKEN, AuthService } from '@kuzntsv/uikit';
|
|
5
6
|
import * as i1 from '@angular/forms';
|
|
6
7
|
import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule, NgControl } from '@angular/forms';
|
|
7
8
|
import { MatButton, MatIconButton, MatAnchor } from '@angular/material/button';
|
|
@@ -18,7 +19,6 @@ import * as i2 from '@angular/material/autocomplete';
|
|
|
18
19
|
import { MatAutocompleteModule, MatOption } from '@angular/material/autocomplete';
|
|
19
20
|
import * as i3 from '@angular/material/chips';
|
|
20
21
|
import { MatChipsModule } from '@angular/material/chips';
|
|
21
|
-
import { startWith, Subscription, Subject, tap, switchMap, map as map$1, forkJoin, ReplaySubject } from 'rxjs';
|
|
22
22
|
import { map, debounceTime, distinctUntilChanged, startWith as startWith$1 } from 'rxjs/operators';
|
|
23
23
|
import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, MatOption as MatOption$1, MatOptgroup } from '@angular/material/core';
|
|
24
24
|
import { MatDateRangeInput, MatStartDate, MatEndDate, MatDatepickerToggle, MatDateRangePicker } from '@angular/material/datepicker';
|
|
@@ -334,16 +334,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
|
|
|
334
334
|
}] });
|
|
335
335
|
|
|
336
336
|
class BaseToolbarComponent {
|
|
337
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
339
|
+
*/
|
|
338
340
|
rolesNewBtn = input([], ...(ngDevMode ? [{ debugName: "rolesNewBtn" }] : /* istanbul ignore next */ []));
|
|
341
|
+
/**
|
|
342
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
343
|
+
*/
|
|
339
344
|
rolesEditBtn = input([], ...(ngDevMode ? [{ debugName: "rolesEditBtn" }] : /* istanbul ignore next */ []));
|
|
345
|
+
/**
|
|
346
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
347
|
+
*/
|
|
340
348
|
rolesRemoveBtn = input([], ...(ngDevMode ? [{ debugName: "rolesRemoveBtn" }] : /* istanbul ignore next */ []));
|
|
349
|
+
/**
|
|
350
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
351
|
+
*/
|
|
341
352
|
rolesCopyBtn = input([], ...(ngDevMode ? [{ debugName: "rolesCopyBtn" }] : /* istanbul ignore next */ []));
|
|
353
|
+
/**
|
|
354
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
355
|
+
*/
|
|
342
356
|
rolesExcelBtn = input([], ...(ngDevMode ? [{ debugName: "rolesExcelBtn" }] : /* istanbul ignore next */ []));
|
|
357
|
+
/**
|
|
358
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
359
|
+
*/
|
|
343
360
|
rolesCsvBtn = input([], ...(ngDevMode ? [{ debugName: "rolesCsvBtn" }] : /* istanbul ignore next */ []));
|
|
361
|
+
/**
|
|
362
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
363
|
+
*/
|
|
344
364
|
rolesPdfBtn = input([], ...(ngDevMode ? [{ debugName: "rolesPdfBtn" }] : /* istanbul ignore next */ []));
|
|
365
|
+
/**
|
|
366
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
367
|
+
*/
|
|
345
368
|
rolesPrintBtn = input([], ...(ngDevMode ? [{ debugName: "rolesPrintBtn" }] : /* istanbul ignore next */ []));
|
|
369
|
+
/**
|
|
370
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
371
|
+
*/
|
|
346
372
|
rolesRefreshBtn = input([], ...(ngDevMode ? [{ debugName: "rolesRefreshBtn" }] : /* istanbul ignore next */ []));
|
|
373
|
+
/**
|
|
374
|
+
* Список Ролей, для которых кнопка видна. Если в списке есть роль 'HIDE', то скрывается.
|
|
375
|
+
*/
|
|
347
376
|
rolesClearBtn = input([], ...(ngDevMode ? [{ debugName: "rolesClearBtn" }] : /* istanbul ignore next */ []));
|
|
348
377
|
// Состояния блокировки
|
|
349
378
|
newBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "newBtnDisabled" }] : /* istanbul ignore next */ []));
|
|
@@ -381,10 +410,28 @@ class BaseToolbarComponent {
|
|
|
381
410
|
clickedRefreshBtn = output();
|
|
382
411
|
clickedClearBtn = output();
|
|
383
412
|
// DI
|
|
384
|
-
authService = inject(AuthService);
|
|
413
|
+
// protected authService = inject(AuthService);
|
|
385
414
|
roleService = inject(RoleService);
|
|
386
|
-
|
|
387
|
-
|
|
415
|
+
// Вычисляемые сигналы видимости кнопок.
|
|
416
|
+
isNewBtnVisible = computed(() => this.checkVisibility(this.rolesNewBtn()), ...(ngDevMode ? [{ debugName: "isNewBtnVisible" }] : /* istanbul ignore next */ []));
|
|
417
|
+
isEditBtnVisible = computed(() => this.checkVisibility(this.rolesEditBtn()), ...(ngDevMode ? [{ debugName: "isEditBtnVisible" }] : /* istanbul ignore next */ []));
|
|
418
|
+
isRemoveBtnVisible = computed(() => this.checkVisibility(this.rolesRemoveBtn()), ...(ngDevMode ? [{ debugName: "isRemoveBtnVisible" }] : /* istanbul ignore next */ []));
|
|
419
|
+
isCopyBtnVisible = computed(() => this.checkVisibility(this.rolesCopyBtn()), ...(ngDevMode ? [{ debugName: "isCopyBtnVisible" }] : /* istanbul ignore next */ []));
|
|
420
|
+
isExcelBtnVisible = computed(() => this.checkVisibility(this.rolesExcelBtn()), ...(ngDevMode ? [{ debugName: "isExcelBtnVisible" }] : /* istanbul ignore next */ []));
|
|
421
|
+
isCsvBtnVisible = computed(() => this.checkVisibility(this.rolesCsvBtn()), ...(ngDevMode ? [{ debugName: "isCsvBtnVisible" }] : /* istanbul ignore next */ []));
|
|
422
|
+
isPdfBtnVisible = computed(() => this.checkVisibility(this.rolesPdfBtn()), ...(ngDevMode ? [{ debugName: "isPdfBtnVisible" }] : /* istanbul ignore next */ []));
|
|
423
|
+
isPrintBtnVisible = computed(() => this.checkVisibility(this.rolesPrintBtn()), ...(ngDevMode ? [{ debugName: "isPrintBtnVisible" }] : /* istanbul ignore next */ []));
|
|
424
|
+
isRefreshBtnVisible = computed(() => this.checkVisibility(this.rolesRefreshBtn()), ...(ngDevMode ? [{ debugName: "isRefreshBtnVisible" }] : /* istanbul ignore next */ []));
|
|
425
|
+
isClearBtnVisible = computed(() => this.checkVisibility(this.rolesClearBtn()), ...(ngDevMode ? [{ debugName: "isClearBtnVisible" }] : /* istanbul ignore next */ []));
|
|
426
|
+
/**
|
|
427
|
+
* Внутренний метод для вычисления видимости.
|
|
428
|
+
* Не вызывается напрямую из шаблона, а служит хелпером для декларативных computed.
|
|
429
|
+
* Проверяет, заблокирован ли доступ к элементу на основе списка ограничений.
|
|
430
|
+
* Возвращает true, если у пользователя есть запрещенная роль или передан маркер 'HIDE'.
|
|
431
|
+
* Администратор (ADMIN) всегда игнорирует любые запреты и маркер 'HIDE'.
|
|
432
|
+
*/
|
|
433
|
+
checkVisibility(forbiddenRoles) {
|
|
434
|
+
return !this.roleService.hasForbiddenRole(forbiddenRoles);
|
|
388
435
|
}
|
|
389
436
|
onNewClick() {
|
|
390
437
|
this.clickedNewBtn.emit();
|
|
@@ -417,7 +464,7 @@ class BaseToolbarComponent {
|
|
|
417
464
|
this.clickedClearBtn.emit();
|
|
418
465
|
}
|
|
419
466
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: BaseToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
420
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: BaseToolbarComponent, isStandalone: true, selector: "ngx-uik-base-toolbar", inputs: { rolesNewBtn: { classPropertyName: "rolesNewBtn", publicName: "rolesNewBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesEditBtn: { classPropertyName: "rolesEditBtn", publicName: "rolesEditBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesRemoveBtn: { classPropertyName: "rolesRemoveBtn", publicName: "rolesRemoveBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesCopyBtn: { classPropertyName: "rolesCopyBtn", publicName: "rolesCopyBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesExcelBtn: { classPropertyName: "rolesExcelBtn", publicName: "rolesExcelBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesCsvBtn: { classPropertyName: "rolesCsvBtn", publicName: "rolesCsvBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesPdfBtn: { classPropertyName: "rolesPdfBtn", publicName: "rolesPdfBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesPrintBtn: { classPropertyName: "rolesPrintBtn", publicName: "rolesPrintBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesRefreshBtn: { classPropertyName: "rolesRefreshBtn", publicName: "rolesRefreshBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesClearBtn: { classPropertyName: "rolesClearBtn", publicName: "rolesClearBtn", isSignal: true, isRequired: false, transformFunction: null }, newBtnDisabled: { classPropertyName: "newBtnDisabled", publicName: "newBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, editBtnDisabled: { classPropertyName: "editBtnDisabled", publicName: "editBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, removeBtnDisabled: { classPropertyName: "removeBtnDisabled", publicName: "removeBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, copyBtnDisabled: { classPropertyName: "copyBtnDisabled", publicName: "copyBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, excelBtnDisabled: { classPropertyName: "excelBtnDisabled", publicName: "excelBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, csvBtnDisabled: { classPropertyName: "csvBtnDisabled", publicName: "csvBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, pdfBtnDisabled: { classPropertyName: "pdfBtnDisabled", publicName: "pdfBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, printBtnDisabled: { classPropertyName: "printBtnDisabled", publicName: "printBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, refreshBtnDisabled: { classPropertyName: "refreshBtnDisabled", publicName: "refreshBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, clearBtnDisabled: { classPropertyName: "clearBtnDisabled", publicName: "clearBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, newBtnTooltip: { classPropertyName: "newBtnTooltip", publicName: "newBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, editBtnTooltip: { classPropertyName: "editBtnTooltip", publicName: "editBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, removeBtnTooltip: { classPropertyName: "removeBtnTooltip", publicName: "removeBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, copyBtnTooltip: { classPropertyName: "copyBtnTooltip", publicName: "copyBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, excelBtnTooltip: { classPropertyName: "excelBtnTooltip", publicName: "excelBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, csvBtnTooltip: { classPropertyName: "csvBtnTooltip", publicName: "csvBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, pdfBtnTooltip: { classPropertyName: "pdfBtnTooltip", publicName: "pdfBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, printBtnTooltip: { classPropertyName: "printBtnTooltip", publicName: "printBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, refreshBtnTooltip: { classPropertyName: "refreshBtnTooltip", publicName: "refreshBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, clearBtnTooltip: { classPropertyName: "clearBtnTooltip", publicName: "clearBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, newBtnOpt: { classPropertyName: "newBtnOpt", publicName: "newBtnOpt", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickedNewBtn: "clickedNewBtn", clickedEditBtn: "clickedEditBtn", clickedRemoveBtn: "clickedRemoveBtn", clickedCopyBtn: "clickedCopyBtn", clickedExcelBtn: "clickedExcelBtn", clickedCsvBtn: "clickedCsvBtn", clickedPdfBtn: "clickedPdfBtn", clickedPrintBtn: "clickedPrintBtn", clickedRefreshBtn: "clickedRefreshBtn", clickedClearBtn: "clickedClearBtn" }, ngImport: i0, template: "<mat-toolbar>\r\n @if (isShow(rolesNewBtn())) {\r\n @if (newBtnOpt() && newBtnOpt().length > 0) {\r\n <button [disabled]=\"newBtnDisabled()\" [matMenuTriggerFor]=\"menuNewBtn\"\r\n mat-icon-button [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n <mat-menu #menuNewBtn=\"matMenu\">\r\n @for (menuItem of newBtnOpt(); track menuItem) {\r\n @if (menuItem.title === '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <mat-divider></mat-divider>\r\n }\r\n @if (menuItem.title !== '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <button mat-menu-item\r\n (click)=\"menuItem.onClickFn ? menuItem.onClickFn('') : ''\"\r\n [disabled]=\"menuItem.disabledFn ? menuItem.disabledFn('') : menuItem.disabled\">\r\n @if (menuItem.icon) {\r\n <mat-icon>{{menuItem.icon}}</mat-icon>\r\n }\r\n {{ menuItem.title }}\r\n </button>\r\n }\r\n }\r\n </mat-menu>\r\n } \r\n @else {\r\n <button [disabled]=\"newBtnDisabled()\" (click)=\"onNewClick()\"\r\n mat-icon-button routerLink=\"new\" routerLinkActive=\"active\" [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n }\r\n\r\n @if (isShow(rolesEditBtn())) {\r\n <button [disabled]=\"editBtnDisabled()\" (click)=\"onEditClick()\"\r\n mat-icon-button routerLink=\"edit\" color=\"primary\" routerLinkActive=\"active\" [matTooltip]=\"editBtnTooltip()\">\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesRemoveBtn())) {\r\n <button [disabled]=\"removeBtnDisabled()\" (click)=\"onRemoveClick()\"\r\n mat-icon-button routerLink=\"delete\" color=\"warn\" routerLinkActive=\"active\" [matTooltip]=\"removeBtnTooltip()\">\r\n <mat-icon>remove</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesCopyBtn())) {\r\n <button [disabled]=\"copyBtnDisabled()\" (click)=\"onCopyClick()\"\r\n mat-icon-button routerLink=\"delete\" routerLinkActive=\"active\" [matTooltip]=\"copyBtnTooltip()\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesExcelBtn())) {\r\n <button [disabled]=\"excelBtnDisabled()\" (click)=\"onExcelClick()\"\r\n mat-icon-button routerLink=\"excel\" routerLinkActive=\"active\" [matTooltip]=\"excelBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">explicit</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesCsvBtn())) {\r\n <button [disabled]=\"csvBtnDisabled()\" (click)=\"onCsvClick()\"\r\n mat-icon-button routerLink=\"csv\" routerLinkActive=\"active\" [matTooltip]=\"csvBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">download</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesPdfBtn())) {\r\n <button [disabled]=\"pdfBtnDisabled()\" (click)=\"onPdfClick()\"\r\n mat-icon-button routerLink=\"pdf\" routerLinkActive=\"active\" [matTooltip]=\"pdfBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">picture_as_pdf</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesPrintBtn())) {\r\n <button [disabled]=\"printBtnDisabled()\" (click)=\"onPrintClick()\"\r\n mat-icon-button routerLink=\"print\" routerLinkActive=\"active\" [matTooltip]=\"printBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">print_outline</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesRefreshBtn())) {\r\n <button [disabled]=\"refreshBtnDisabled()\" (click)=\"onRefreshGridClick()\"\r\n mat-icon-button routerLink=\"refresh\" routerLinkActive=\"active\" [matTooltip]=\"refreshBtnTooltip()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesClearBtn())) {\r\n <button [disabled]=\"clearBtnDisabled()\" (click)=\"onClearClick()\"\r\n mat-icon-button routerLink=\"clear\" routerLinkActive=\"active\" [matTooltip]=\"clearBtnTooltip()\">\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n }\r\n</mat-toolbar>\r\n", styles: [""], dependencies: [{ kind: "component", type: MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }] });
|
|
467
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: BaseToolbarComponent, isStandalone: true, selector: "ngx-uik-base-toolbar", inputs: { rolesNewBtn: { classPropertyName: "rolesNewBtn", publicName: "rolesNewBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesEditBtn: { classPropertyName: "rolesEditBtn", publicName: "rolesEditBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesRemoveBtn: { classPropertyName: "rolesRemoveBtn", publicName: "rolesRemoveBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesCopyBtn: { classPropertyName: "rolesCopyBtn", publicName: "rolesCopyBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesExcelBtn: { classPropertyName: "rolesExcelBtn", publicName: "rolesExcelBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesCsvBtn: { classPropertyName: "rolesCsvBtn", publicName: "rolesCsvBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesPdfBtn: { classPropertyName: "rolesPdfBtn", publicName: "rolesPdfBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesPrintBtn: { classPropertyName: "rolesPrintBtn", publicName: "rolesPrintBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesRefreshBtn: { classPropertyName: "rolesRefreshBtn", publicName: "rolesRefreshBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesClearBtn: { classPropertyName: "rolesClearBtn", publicName: "rolesClearBtn", isSignal: true, isRequired: false, transformFunction: null }, newBtnDisabled: { classPropertyName: "newBtnDisabled", publicName: "newBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, editBtnDisabled: { classPropertyName: "editBtnDisabled", publicName: "editBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, removeBtnDisabled: { classPropertyName: "removeBtnDisabled", publicName: "removeBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, copyBtnDisabled: { classPropertyName: "copyBtnDisabled", publicName: "copyBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, excelBtnDisabled: { classPropertyName: "excelBtnDisabled", publicName: "excelBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, csvBtnDisabled: { classPropertyName: "csvBtnDisabled", publicName: "csvBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, pdfBtnDisabled: { classPropertyName: "pdfBtnDisabled", publicName: "pdfBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, printBtnDisabled: { classPropertyName: "printBtnDisabled", publicName: "printBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, refreshBtnDisabled: { classPropertyName: "refreshBtnDisabled", publicName: "refreshBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, clearBtnDisabled: { classPropertyName: "clearBtnDisabled", publicName: "clearBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, newBtnTooltip: { classPropertyName: "newBtnTooltip", publicName: "newBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, editBtnTooltip: { classPropertyName: "editBtnTooltip", publicName: "editBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, removeBtnTooltip: { classPropertyName: "removeBtnTooltip", publicName: "removeBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, copyBtnTooltip: { classPropertyName: "copyBtnTooltip", publicName: "copyBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, excelBtnTooltip: { classPropertyName: "excelBtnTooltip", publicName: "excelBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, csvBtnTooltip: { classPropertyName: "csvBtnTooltip", publicName: "csvBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, pdfBtnTooltip: { classPropertyName: "pdfBtnTooltip", publicName: "pdfBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, printBtnTooltip: { classPropertyName: "printBtnTooltip", publicName: "printBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, refreshBtnTooltip: { classPropertyName: "refreshBtnTooltip", publicName: "refreshBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, clearBtnTooltip: { classPropertyName: "clearBtnTooltip", publicName: "clearBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, newBtnOpt: { classPropertyName: "newBtnOpt", publicName: "newBtnOpt", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickedNewBtn: "clickedNewBtn", clickedEditBtn: "clickedEditBtn", clickedRemoveBtn: "clickedRemoveBtn", clickedCopyBtn: "clickedCopyBtn", clickedExcelBtn: "clickedExcelBtn", clickedCsvBtn: "clickedCsvBtn", clickedPdfBtn: "clickedPdfBtn", clickedPrintBtn: "clickedPrintBtn", clickedRefreshBtn: "clickedRefreshBtn", clickedClearBtn: "clickedClearBtn" }, ngImport: i0, template: "<mat-toolbar>\r\n @if (isNewBtnVisible()) {\r\n @if (newBtnOpt() && newBtnOpt().length > 0) {\r\n <button [disabled]=\"newBtnDisabled()\" [matMenuTriggerFor]=\"menuNewBtn\"\r\n mat-icon-button [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n <mat-menu #menuNewBtn=\"matMenu\">\r\n @for (menuItem of newBtnOpt(); track menuItem) {\r\n @if (menuItem.title === '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <mat-divider></mat-divider>\r\n }\r\n @if (menuItem.title !== '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <button mat-menu-item\r\n (click)=\"menuItem.onClickFn ? menuItem.onClickFn('') : ''\"\r\n [disabled]=\"menuItem.disabledFn ? menuItem.disabledFn('') : menuItem.disabled\">\r\n @if (menuItem.icon) {\r\n <mat-icon>{{menuItem.icon}}</mat-icon>\r\n }\r\n {{ menuItem.title }}\r\n </button>\r\n }\r\n }\r\n </mat-menu>\r\n } \r\n @else {\r\n <button [disabled]=\"newBtnDisabled()\" (click)=\"onNewClick()\"\r\n mat-icon-button routerLink=\"new\" routerLinkActive=\"active\" [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n }\r\n\r\n @if (isEditBtnVisible()) {\r\n <button [disabled]=\"editBtnDisabled()\" (click)=\"onEditClick()\"\r\n mat-icon-button routerLink=\"edit\" color=\"primary\" routerLinkActive=\"active\" [matTooltip]=\"editBtnTooltip()\">\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n }\r\n @if (isRemoveBtnVisible()) {\r\n <button [disabled]=\"removeBtnDisabled()\" (click)=\"onRemoveClick()\"\r\n mat-icon-button routerLink=\"delete\" color=\"warn\" routerLinkActive=\"active\" [matTooltip]=\"removeBtnTooltip()\">\r\n <mat-icon>remove</mat-icon>\r\n </button>\r\n }\r\n @if (isCopyBtnVisible()) {\r\n <button [disabled]=\"copyBtnDisabled()\" (click)=\"onCopyClick()\"\r\n mat-icon-button routerLink=\"delete\" routerLinkActive=\"active\" [matTooltip]=\"copyBtnTooltip()\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n }\r\n @if (isExcelBtnVisible()) {\r\n <button [disabled]=\"excelBtnDisabled()\" (click)=\"onExcelClick()\"\r\n mat-icon-button routerLink=\"excel\" routerLinkActive=\"active\" [matTooltip]=\"excelBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">explicit</mat-icon>\r\n </button>\r\n }\r\n @if (isCsvBtnVisible()) {\r\n <button [disabled]=\"csvBtnDisabled()\" (click)=\"onCsvClick()\"\r\n mat-icon-button routerLink=\"csv\" routerLinkActive=\"active\" [matTooltip]=\"csvBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">download</mat-icon>\r\n </button>\r\n }\r\n @if (isPdfBtnVisible()) {\r\n <button [disabled]=\"pdfBtnDisabled()\" (click)=\"onPdfClick()\"\r\n mat-icon-button routerLink=\"pdf\" routerLinkActive=\"active\" [matTooltip]=\"pdfBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">picture_as_pdf</mat-icon>\r\n </button>\r\n }\r\n @if (isPrintBtnVisible()) {\r\n <button [disabled]=\"printBtnDisabled()\" (click)=\"onPrintClick()\"\r\n mat-icon-button routerLink=\"print\" routerLinkActive=\"active\" [matTooltip]=\"printBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">print_outline</mat-icon>\r\n </button>\r\n }\r\n @if (isRefreshBtnVisible()) {\r\n <button [disabled]=\"refreshBtnDisabled()\" (click)=\"onRefreshGridClick()\"\r\n mat-icon-button routerLink=\"refresh\" routerLinkActive=\"active\" [matTooltip]=\"refreshBtnTooltip()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n }\r\n @if (isClearBtnVisible()) {\r\n <button [disabled]=\"clearBtnDisabled()\" (click)=\"onClearClick()\"\r\n mat-icon-button routerLink=\"clear\" routerLinkActive=\"active\" [matTooltip]=\"clearBtnTooltip()\">\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n }\r\n</mat-toolbar>\r\n", styles: [""], dependencies: [{ kind: "component", type: MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }] });
|
|
421
468
|
}
|
|
422
469
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: BaseToolbarComponent, decorators: [{
|
|
423
470
|
type: Component,
|
|
@@ -430,7 +477,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
|
|
|
430
477
|
MatDivider,
|
|
431
478
|
MatMenuTrigger,
|
|
432
479
|
MatMenuItem,
|
|
433
|
-
], template: "<mat-toolbar>\r\n @if (
|
|
480
|
+
], template: "<mat-toolbar>\r\n @if (isNewBtnVisible()) {\r\n @if (newBtnOpt() && newBtnOpt().length > 0) {\r\n <button [disabled]=\"newBtnDisabled()\" [matMenuTriggerFor]=\"menuNewBtn\"\r\n mat-icon-button [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n <mat-menu #menuNewBtn=\"matMenu\">\r\n @for (menuItem of newBtnOpt(); track menuItem) {\r\n @if (menuItem.title === '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <mat-divider></mat-divider>\r\n }\r\n @if (menuItem.title !== '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <button mat-menu-item\r\n (click)=\"menuItem.onClickFn ? menuItem.onClickFn('') : ''\"\r\n [disabled]=\"menuItem.disabledFn ? menuItem.disabledFn('') : menuItem.disabled\">\r\n @if (menuItem.icon) {\r\n <mat-icon>{{menuItem.icon}}</mat-icon>\r\n }\r\n {{ menuItem.title }}\r\n </button>\r\n }\r\n }\r\n </mat-menu>\r\n } \r\n @else {\r\n <button [disabled]=\"newBtnDisabled()\" (click)=\"onNewClick()\"\r\n mat-icon-button routerLink=\"new\" routerLinkActive=\"active\" [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n }\r\n\r\n @if (isEditBtnVisible()) {\r\n <button [disabled]=\"editBtnDisabled()\" (click)=\"onEditClick()\"\r\n mat-icon-button routerLink=\"edit\" color=\"primary\" routerLinkActive=\"active\" [matTooltip]=\"editBtnTooltip()\">\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n }\r\n @if (isRemoveBtnVisible()) {\r\n <button [disabled]=\"removeBtnDisabled()\" (click)=\"onRemoveClick()\"\r\n mat-icon-button routerLink=\"delete\" color=\"warn\" routerLinkActive=\"active\" [matTooltip]=\"removeBtnTooltip()\">\r\n <mat-icon>remove</mat-icon>\r\n </button>\r\n }\r\n @if (isCopyBtnVisible()) {\r\n <button [disabled]=\"copyBtnDisabled()\" (click)=\"onCopyClick()\"\r\n mat-icon-button routerLink=\"delete\" routerLinkActive=\"active\" [matTooltip]=\"copyBtnTooltip()\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n }\r\n @if (isExcelBtnVisible()) {\r\n <button [disabled]=\"excelBtnDisabled()\" (click)=\"onExcelClick()\"\r\n mat-icon-button routerLink=\"excel\" routerLinkActive=\"active\" [matTooltip]=\"excelBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">explicit</mat-icon>\r\n </button>\r\n }\r\n @if (isCsvBtnVisible()) {\r\n <button [disabled]=\"csvBtnDisabled()\" (click)=\"onCsvClick()\"\r\n mat-icon-button routerLink=\"csv\" routerLinkActive=\"active\" [matTooltip]=\"csvBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">download</mat-icon>\r\n </button>\r\n }\r\n @if (isPdfBtnVisible()) {\r\n <button [disabled]=\"pdfBtnDisabled()\" (click)=\"onPdfClick()\"\r\n mat-icon-button routerLink=\"pdf\" routerLinkActive=\"active\" [matTooltip]=\"pdfBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">picture_as_pdf</mat-icon>\r\n </button>\r\n }\r\n @if (isPrintBtnVisible()) {\r\n <button [disabled]=\"printBtnDisabled()\" (click)=\"onPrintClick()\"\r\n mat-icon-button routerLink=\"print\" routerLinkActive=\"active\" [matTooltip]=\"printBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">print_outline</mat-icon>\r\n </button>\r\n }\r\n @if (isRefreshBtnVisible()) {\r\n <button [disabled]=\"refreshBtnDisabled()\" (click)=\"onRefreshGridClick()\"\r\n mat-icon-button routerLink=\"refresh\" routerLinkActive=\"active\" [matTooltip]=\"refreshBtnTooltip()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n }\r\n @if (isClearBtnVisible()) {\r\n <button [disabled]=\"clearBtnDisabled()\" (click)=\"onClearClick()\"\r\n mat-icon-button routerLink=\"clear\" routerLinkActive=\"active\" [matTooltip]=\"clearBtnTooltip()\">\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n }\r\n</mat-toolbar>\r\n" }]
|
|
434
481
|
}], propDecorators: { rolesNewBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesNewBtn", required: false }] }], rolesEditBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesEditBtn", required: false }] }], rolesRemoveBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesRemoveBtn", required: false }] }], rolesCopyBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesCopyBtn", required: false }] }], rolesExcelBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesExcelBtn", required: false }] }], rolesCsvBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesCsvBtn", required: false }] }], rolesPdfBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesPdfBtn", required: false }] }], rolesPrintBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesPrintBtn", required: false }] }], rolesRefreshBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesRefreshBtn", required: false }] }], rolesClearBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesClearBtn", required: false }] }], newBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "newBtnDisabled", required: false }] }], editBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "editBtnDisabled", required: false }] }], removeBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeBtnDisabled", required: false }] }], copyBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyBtnDisabled", required: false }] }], excelBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "excelBtnDisabled", required: false }] }], csvBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "csvBtnDisabled", required: false }] }], pdfBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "pdfBtnDisabled", required: false }] }], printBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "printBtnDisabled", required: false }] }], refreshBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "refreshBtnDisabled", required: false }] }], clearBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearBtnDisabled", required: false }] }], newBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "newBtnTooltip", required: false }] }], editBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "editBtnTooltip", required: false }] }], removeBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeBtnTooltip", required: false }] }], copyBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyBtnTooltip", required: false }] }], excelBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "excelBtnTooltip", required: false }] }], csvBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "csvBtnTooltip", required: false }] }], pdfBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "pdfBtnTooltip", required: false }] }], printBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "printBtnTooltip", required: false }] }], refreshBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "refreshBtnTooltip", required: false }] }], clearBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearBtnTooltip", required: false }] }], newBtnOpt: [{ type: i0.Input, args: [{ isSignal: true, alias: "newBtnOpt", required: false }] }], clickedNewBtn: [{ type: i0.Output, args: ["clickedNewBtn"] }], clickedEditBtn: [{ type: i0.Output, args: ["clickedEditBtn"] }], clickedRemoveBtn: [{ type: i0.Output, args: ["clickedRemoveBtn"] }], clickedCopyBtn: [{ type: i0.Output, args: ["clickedCopyBtn"] }], clickedExcelBtn: [{ type: i0.Output, args: ["clickedExcelBtn"] }], clickedCsvBtn: [{ type: i0.Output, args: ["clickedCsvBtn"] }], clickedPdfBtn: [{ type: i0.Output, args: ["clickedPdfBtn"] }], clickedPrintBtn: [{ type: i0.Output, args: ["clickedPrintBtn"] }], clickedRefreshBtn: [{ type: i0.Output, args: ["clickedRefreshBtn"] }], clickedClearBtn: [{ type: i0.Output, args: ["clickedClearBtn"] }] } });
|
|
435
482
|
|
|
436
483
|
var Action;
|
|
@@ -510,16 +557,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
|
|
|
510
557
|
}], ctorParameters: () => [] });
|
|
511
558
|
|
|
512
559
|
class BaseNavBarMenuClass {
|
|
513
|
-
subscription = new Subscription();
|
|
514
|
-
authService = inject(AuthService);
|
|
515
560
|
roleService = inject(RoleService);
|
|
516
561
|
router = inject(Router);
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
562
|
+
/**
|
|
563
|
+
* Определяет видимость пункта меню.
|
|
564
|
+
* По умолчанию пункт меню ВИДИМ. Скрывается, если у пользователя есть запрещенная роль
|
|
565
|
+
* или если передан маркер скрытия фичи HIDE_ROLE_MARKER.
|
|
566
|
+
*/
|
|
567
|
+
isMenuVisible(forbiddenRoles) {
|
|
568
|
+
return !this.roleService.hasForbiddenRole(forbiddenRoles);
|
|
523
569
|
}
|
|
524
570
|
/** Нажата средняя кнопка (открыть ссылку в новой вкладке). */
|
|
525
571
|
onMiddleClick(event, baseUrl, menu) {
|
|
@@ -610,7 +656,7 @@ class BasePageClass {
|
|
|
610
656
|
editorRoles = [];
|
|
611
657
|
executeRoles = [];
|
|
612
658
|
/** Список ролей, для которых скрыть элемент. */
|
|
613
|
-
hideRoles = [
|
|
659
|
+
hideRoles = [HIDE_ROLE_MARKER];
|
|
614
660
|
/** Загрузка данных. */
|
|
615
661
|
loadData$ = new Subject();
|
|
616
662
|
/** Загрузка количества записей. */
|
|
@@ -1101,15 +1147,18 @@ class NavBarComponent extends BaseNavBarMenuClass {
|
|
|
1101
1147
|
title: 'Подтверждение',
|
|
1102
1148
|
message: 'Вы хотите выйти?',
|
|
1103
1149
|
btnNoTitle: 'Отмена',
|
|
1104
|
-
btnYesTitle: 'Выйти'
|
|
1105
|
-
}
|
|
1150
|
+
btnYesTitle: 'Выйти',
|
|
1151
|
+
},
|
|
1106
1152
|
});
|
|
1107
|
-
|
|
1153
|
+
dialogRef
|
|
1154
|
+
.afterClosed()
|
|
1155
|
+
.pipe(take(1), // Берем только одно значение (когда закрылся)
|
|
1156
|
+
filter((id) => !!id))
|
|
1157
|
+
.subscribe((id) => {
|
|
1108
1158
|
if (id) {
|
|
1109
1159
|
this.onLogout();
|
|
1110
1160
|
}
|
|
1111
1161
|
});
|
|
1112
|
-
this.subscription.add(subs);
|
|
1113
1162
|
}
|
|
1114
1163
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: NavBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1115
1164
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: NavBarComponent, isStandalone: true, selector: "ngx-uik-navbar", inputs: { visibleOnLogout: { classPropertyName: "visibleOnLogout", publicName: "visibleOnLogout", isSignal: true, isRequired: false, transformFunction: null }, visibleAvatar: { classPropertyName: "visibleAvatar", publicName: "visibleAvatar", isSignal: true, isRequired: false, transformFunction: null }, visibleLogoutBtn: { classPropertyName: "visibleLogoutBtn", publicName: "visibleLogoutBtn", isSignal: true, isRequired: false, transformFunction: null }, loggedIn: { classPropertyName: "loggedIn", publicName: "loggedIn", isSignal: true, isRequired: false, transformFunction: null }, fioUser: { classPropertyName: "fioUser", publicName: "fioUser", isSignal: true, isRequired: false, transformFunction: null }, userTooltip: { classPropertyName: "userTooltip", publicName: "userTooltip", isSignal: true, isRequired: false, transformFunction: null }, avatarURL: { classPropertyName: "avatarURL", publicName: "avatarURL", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { logout: "logout" }, usesInheritance: true, ngImport: i0, template: "@if (visibleOnLogout() || loggedIn()) {\r\n <nav class=\"ngx-uik-navbar-header\">\r\n \r\n <ng-content></ng-content>\r\n\r\n <div class=\"flex-spacer\"></div>\r\n \r\n @if (visibleAvatar() && (loggedIn() === false || !avatarURL)) {\r\n <mat-icon [matTooltip]=\"userTooltip()\">account_circle</mat-icon>\r\n }\r\n @if (visibleAvatar() && loggedIn() && avatarURL()) {\r\n <img\r\n class=\"user-photo\"\r\n [src]=\"avatarURL() | safe\"\r\n loading=\"lazy\"\r\n [alt]=\"fioUser()\"\r\n [matTooltip]=\"userTooltip()\">\r\n }\r\n\r\n <span class = \"user-name\" [matTooltip]=\"userTooltip()\">\r\n {{ fioUser() }}\r\n </span>\r\n\r\n @if (visibleLogoutBtn()) {\r\n <a mat-button class=\"pm-button\" (click)=\"openDialog()\">\u0412\u044B\u0439\u0442\u0438 <mat-icon>logout</mat-icon></a>\r\n }\r\n </nav>\r\n}", styles: [".ngx-uik-navbar-header{display:flex;flex-wrap:wrap;align-items:center;padding:8px 16px}.flex-spacer{flex-grow:1}.user-name{margin-left:8px;line-height:1rem;white-space:normal}.user-photo{border-radius:50%;width:32px;height:32px;margin-right:10px}.mat-mdc-button{color:#fff!important;padding-left:16px!important;padding-right:16px!important}.mdc-button{letter-spacing:normal}\n"], dependencies: [{ kind: "component", type: MatAnchor, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: SafePipe, name: "safe" }] });
|
|
@@ -1643,59 +1692,103 @@ class LoginPageComponent {
|
|
|
1643
1692
|
pending = false;
|
|
1644
1693
|
error = '';
|
|
1645
1694
|
isKiosk = false;
|
|
1646
|
-
/**
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1695
|
+
/**
|
|
1696
|
+
* Идентификатор АС получаем автоматически из ActivatedRoute Data!
|
|
1697
|
+
* (Для этого в настройках роутера должен быть включен withComponentInputBinding())
|
|
1698
|
+
*/
|
|
1699
|
+
idCas = input(0, ...(ngDevMode ? [{ debugName: "idCas" }] : /* istanbul ignore next */ []));
|
|
1650
1700
|
authService = inject(AuthService);
|
|
1651
|
-
|
|
1701
|
+
router = inject(Router);
|
|
1652
1702
|
loaderService = inject(LoaderService);
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
});
|
|
1657
|
-
}
|
|
1703
|
+
notificationService = inject(UIKIT_NOTIFICATION_TOKEN, {
|
|
1704
|
+
optional: true,
|
|
1705
|
+
});
|
|
1658
1706
|
ngOnInit() {
|
|
1659
|
-
if (localStorage.getItem('id_human') ||
|
|
1707
|
+
if (localStorage.getItem('id_human') ||
|
|
1708
|
+
localStorage.getItem('kiosk-keyboard-layout')) {
|
|
1660
1709
|
// this.isKiosk = true;
|
|
1661
1710
|
}
|
|
1662
1711
|
}
|
|
1663
|
-
ngOnDestroy() {
|
|
1664
|
-
this.sub.unsubscribe();
|
|
1665
|
-
}
|
|
1666
|
-
onSubmitError() {
|
|
1667
|
-
return () => {
|
|
1668
|
-
this.pending = false;
|
|
1669
|
-
this.loaderService.hide();
|
|
1670
|
-
};
|
|
1671
|
-
}
|
|
1672
1712
|
onSubmit($event) {
|
|
1673
1713
|
this.loaderService.show();
|
|
1674
1714
|
this.pending = true;
|
|
1675
|
-
this.authService
|
|
1715
|
+
this.authService
|
|
1716
|
+
.login($event.username, $event.password, this.idCas())
|
|
1717
|
+
.pipe(
|
|
1718
|
+
// Очищаем состояние лоадеров ВСЕГДА (и при успехе, и при ошибке)
|
|
1719
|
+
finalize(() => {
|
|
1720
|
+
this.pending = false;
|
|
1721
|
+
this.loaderService.hide();
|
|
1722
|
+
}))
|
|
1723
|
+
.subscribe({
|
|
1724
|
+
next: () => this.handleSuccessLogin(),
|
|
1725
|
+
error: (error) => {
|
|
1726
|
+
const errorMsg = error.error?.message || error.message || 'Ошибка при авторизации';
|
|
1727
|
+
this.notificationService?.error(errorMsg, 0);
|
|
1728
|
+
},
|
|
1729
|
+
});
|
|
1676
1730
|
}
|
|
1677
1731
|
onSubmitPermit($event) {
|
|
1678
1732
|
const permit = $event;
|
|
1679
|
-
this.
|
|
1733
|
+
this.loaderService.show();
|
|
1734
|
+
this.pending = true;
|
|
1735
|
+
this.authService
|
|
1736
|
+
.loginByPermit(permit, this.idCas())
|
|
1737
|
+
.pipe(
|
|
1738
|
+
// Очищаем состояние лоадеров ВСЕГДА (и при успехе, и при ошибке)
|
|
1739
|
+
finalize(() => {
|
|
1740
|
+
this.pending = false;
|
|
1741
|
+
this.loaderService.hide();
|
|
1742
|
+
}))
|
|
1743
|
+
.subscribe({
|
|
1744
|
+
next: () => this.handleSuccessLogin(),
|
|
1745
|
+
error: (error) => {
|
|
1746
|
+
const errorMsg = error.error?.message || error.message || 'Ошибка при авторизации';
|
|
1747
|
+
this.notificationService?.error(errorMsg, 0);
|
|
1748
|
+
},
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
handleSuccessLogin() {
|
|
1752
|
+
this.notificationService?.success('Успешная авторизация');
|
|
1753
|
+
// ЛОГИКА ВОЗВРАТА ПОСЛЕ УСПЕШНОГО ЛОГИНА
|
|
1754
|
+
if (this.router) {
|
|
1755
|
+
// Извлекаем returnUrl из текущего query-параметра текущего маршрута
|
|
1756
|
+
const currentUrlTree = this.router.parseUrl(this.router.url);
|
|
1757
|
+
const returnUrl = currentUrlTree.queryParamMap.get('returnUrl');
|
|
1758
|
+
if (returnUrl) {
|
|
1759
|
+
// Декодируем и перенаправляем пользователя туда, где он был
|
|
1760
|
+
this.router.navigateByUrl(decodeURIComponent(returnUrl));
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
// Если returnUrl нет, идем на главную
|
|
1764
|
+
this.router.navigate(['/']);
|
|
1765
|
+
}
|
|
1766
|
+
// Логика перенаправления обратно: достаем returnUrl из текущих query-параметров страницы логина
|
|
1767
|
+
const currentUrlTree = this.router.parseUrl(this.router.url);
|
|
1768
|
+
const returnUrl = currentUrlTree.queryParamMap.get('returnUrl');
|
|
1769
|
+
if (returnUrl) {
|
|
1770
|
+
this.router.navigateByUrl(decodeURIComponent(returnUrl));
|
|
1771
|
+
}
|
|
1772
|
+
{
|
|
1773
|
+
this.router.navigate(['/']); // дефолтный роут, если returnUrl нет
|
|
1774
|
+
}
|
|
1680
1775
|
}
|
|
1681
1776
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: LoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1682
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: LoginPageComponent, isStandalone: true, selector: "ngx-uik-login-page", ngImport: i0, template: "@if (!isKiosk) {\r\n <ngx-uik-login-form\r\n (submitted)=\"onSubmit($event)\"\r\n [pending]=\"pending\"\r\n [errorMessage]=\"error\">\r\n </ngx-uik-login-form>\r\n }\r\n @if (isKiosk) {\r\n <ngx-uik-permit-form\r\n (submitted)=\"onSubmitPermit($event)\"\r\n >\r\n </ngx-uik-permit-form>\r\n }", styles: [""], dependencies: [{ kind: "component", type: LoginFormComponent, selector: "ngx-uik-login-form", inputs: ["pending", "errorMessage"], outputs: ["submitted"] }, { kind: "component", type: PermitFormComponent, selector: "ngx-uik-permit-form", outputs: ["submitted"] }] });
|
|
1777
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: LoginPageComponent, isStandalone: true, selector: "ngx-uik-login-page", inputs: { idCas: { classPropertyName: "idCas", publicName: "idCas", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!isKiosk) {\r\n <ngx-uik-login-form\r\n (submitted)=\"onSubmit($event)\"\r\n [pending]=\"pending\"\r\n [errorMessage]=\"error\">\r\n </ngx-uik-login-form>\r\n }\r\n @if (isKiosk) {\r\n <ngx-uik-permit-form\r\n (submitted)=\"onSubmitPermit($event)\"\r\n >\r\n </ngx-uik-permit-form>\r\n }", styles: [""], dependencies: [{ kind: "component", type: LoginFormComponent, selector: "ngx-uik-login-form", inputs: ["pending", "errorMessage"], outputs: ["submitted"] }, { kind: "component", type: PermitFormComponent, selector: "ngx-uik-permit-form", outputs: ["submitted"] }] });
|
|
1683
1778
|
}
|
|
1684
1779
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: LoginPageComponent, decorators: [{
|
|
1685
1780
|
type: Component,
|
|
1686
1781
|
args: [{ selector: 'ngx-uik-login-page', imports: [LoginFormComponent, PermitFormComponent], template: "@if (!isKiosk) {\r\n <ngx-uik-login-form\r\n (submitted)=\"onSubmit($event)\"\r\n [pending]=\"pending\"\r\n [errorMessage]=\"error\">\r\n </ngx-uik-login-form>\r\n }\r\n @if (isKiosk) {\r\n <ngx-uik-permit-form\r\n (submitted)=\"onSubmitPermit($event)\"\r\n >\r\n </ngx-uik-permit-form>\r\n }" }]
|
|
1687
|
-
}],
|
|
1782
|
+
}], propDecorators: { idCas: [{ type: i0.Input, args: [{ isSignal: true, alias: "idCas", required: false }] }] } });
|
|
1688
1783
|
|
|
1689
1784
|
class DisableIfRoleDirective {
|
|
1690
|
-
|
|
1785
|
+
forbiddenRoles = input([], { ...(ngDevMode ? { debugName: "forbiddenRoles" } : /* istanbul ignore next */ {}), alias: 'ngxUikDisableIfRole' });
|
|
1691
1786
|
el = inject(ElementRef);
|
|
1692
|
-
authService = inject(AuthService);
|
|
1693
1787
|
roleService = inject(RoleService);
|
|
1694
1788
|
constructor() {
|
|
1695
1789
|
effect(() => {
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
const shouldDisable = !hasRequiredRole;
|
|
1790
|
+
// Спрашиваем у сервиса, заблокирована ли данная конфигурация ролей
|
|
1791
|
+
const shouldDisable = this.roleService.hasForbiddenRole(this.forbiddenRoles());
|
|
1699
1792
|
// 2. Безопасное управление атрибутом для любых элементов
|
|
1700
1793
|
const nativeEl = this.el.nativeElement;
|
|
1701
1794
|
if ('disabled' in nativeEl) {
|
|
@@ -1713,7 +1806,7 @@ class DisableIfRoleDirective {
|
|
|
1713
1806
|
});
|
|
1714
1807
|
}
|
|
1715
1808
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: DisableIfRoleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1716
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: DisableIfRoleDirective, isStandalone: true, selector: "[ngxUikDisableIfRole]", inputs: {
|
|
1809
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: DisableIfRoleDirective, isStandalone: true, selector: "[ngxUikDisableIfRole]", inputs: { forbiddenRoles: { classPropertyName: "forbiddenRoles", publicName: "ngxUikDisableIfRole", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
1717
1810
|
}
|
|
1718
1811
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: DisableIfRoleDirective, decorators: [{
|
|
1719
1812
|
type: Directive,
|
|
@@ -1721,43 +1814,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
|
|
|
1721
1814
|
selector: '[ngxUikDisableIfRole]',
|
|
1722
1815
|
standalone: true
|
|
1723
1816
|
}]
|
|
1724
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
1817
|
+
}], ctorParameters: () => [], propDecorators: { forbiddenRoles: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxUikDisableIfRole", required: false }] }] } });
|
|
1725
1818
|
|
|
1726
|
-
class
|
|
1727
|
-
|
|
1819
|
+
class HideIfForbiddenRoleDirective {
|
|
1820
|
+
forbiddenRoles = input([], { ...(ngDevMode ? { debugName: "forbiddenRoles" } : /* istanbul ignore next */ {}), alias: 'ngxUikHideIfForbiddenRole' });
|
|
1728
1821
|
el = inject(ElementRef);
|
|
1729
|
-
authService = inject(AuthService);
|
|
1730
1822
|
roleService = inject(RoleService);
|
|
1731
1823
|
constructor() {
|
|
1732
1824
|
effect(() => {
|
|
1733
|
-
// Элемент скрывается, если у пользователя
|
|
1734
|
-
|
|
1735
|
-
const isHide = this.roleService.isHideElement(this.roles(), this.authService.roles());
|
|
1825
|
+
// Элемент скрывается, если у пользователя есть запрещенная роль или передан маркер HIDE_ROLE_MARKER
|
|
1826
|
+
const shouldHide = this.roleService.hasForbiddenRole(this.forbiddenRoles());
|
|
1736
1827
|
// Управляем отображением. Пустая строка возвращает дефолтный CSS-стиль элемента.
|
|
1737
|
-
this.el.nativeElement.style.display =
|
|
1828
|
+
this.el.nativeElement.style.display = shouldHide ? 'none' : '';
|
|
1738
1829
|
});
|
|
1739
1830
|
}
|
|
1740
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type:
|
|
1741
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type:
|
|
1831
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: HideIfForbiddenRoleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1832
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: HideIfForbiddenRoleDirective, isStandalone: true, selector: "[ngxUikHideIfForbiddenRole]", inputs: { forbiddenRoles: { classPropertyName: "forbiddenRoles", publicName: "ngxUikHideIfForbiddenRole", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
1742
1833
|
}
|
|
1743
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type:
|
|
1834
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: HideIfForbiddenRoleDirective, decorators: [{
|
|
1744
1835
|
type: Directive,
|
|
1745
1836
|
args: [{
|
|
1746
|
-
selector: '[
|
|
1747
|
-
standalone: true
|
|
1837
|
+
selector: '[ngxUikHideIfForbiddenRole]',
|
|
1838
|
+
standalone: true,
|
|
1748
1839
|
}]
|
|
1749
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
1840
|
+
}], ctorParameters: () => [], propDecorators: { forbiddenRoles: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxUikHideIfForbiddenRole", required: false }] }] } });
|
|
1750
1841
|
|
|
1751
1842
|
class SetValueDirective {
|
|
1752
|
-
value = input(
|
|
1843
|
+
value = input(null, { ...(ngDevMode ? { debugName: "value" } : /* istanbul ignore next */ {}), alias: 'setValue' });
|
|
1753
1844
|
// 3. Используем опциональный inject, чтобы директива не падала, если формы нет
|
|
1754
1845
|
ngControl = inject(NgControl, { optional: true });
|
|
1755
1846
|
constructor() {
|
|
1756
1847
|
effect(() => {
|
|
1757
1848
|
// Эффект автоматически отслеживает изменение входного значения
|
|
1758
1849
|
const val = this.value();
|
|
1759
|
-
|
|
1760
|
-
|
|
1850
|
+
// Безопасное приведение undefined к null для стандартизации значений в формах
|
|
1851
|
+
const normalizedValue = val === undefined ? null : val;
|
|
1852
|
+
// Используем проверку, так как на старте ngControl.control может быть еще не создан Angular-ом
|
|
1853
|
+
if (this.ngControl && this.ngControl.control) {
|
|
1854
|
+
this.ngControl.control.setValue(normalizedValue, { emitEvent: false });
|
|
1761
1855
|
}
|
|
1762
1856
|
});
|
|
1763
1857
|
}
|
|
@@ -1794,14 +1888,15 @@ const redirectGuard = (route) => {
|
|
|
1794
1888
|
return true;
|
|
1795
1889
|
};
|
|
1796
1890
|
|
|
1891
|
+
/**
|
|
1892
|
+
* Пускает на роут только тех пользователей, у которых есть роли из списка allowedRoles.
|
|
1893
|
+
* ADMIN всегда имеет доступ.
|
|
1894
|
+
*/
|
|
1797
1895
|
const roleGuard = (allowedRoles) => {
|
|
1798
1896
|
return (route, state) => {
|
|
1799
|
-
const authService = inject(AuthService);
|
|
1800
1897
|
const roleService = inject(RoleService);
|
|
1801
|
-
// Читаем роли из Сигнала
|
|
1802
|
-
const userRoles = authService.roles();
|
|
1803
1898
|
// Проверяем доступ на основе аргумента allowedRoles
|
|
1804
|
-
return roleService.
|
|
1899
|
+
return roleService.hasAnyRole(allowedRoles);
|
|
1805
1900
|
};
|
|
1806
1901
|
};
|
|
1807
1902
|
|
|
@@ -1878,5 +1973,5 @@ class SecUser {
|
|
|
1878
1973
|
* Generated bundle index. Do not edit.
|
|
1879
1974
|
*/
|
|
1880
1975
|
|
|
1881
|
-
export { Action, AvatarService, BaseEditClass, BaseFilterClass, BaseMatChipComponent, BaseNavBarMenuClass, BasePageClass, BaseSelectAutocompleteWithVsComponent, BaseSelectWithGroupComponent, BaseServiceClass, BaseToolbarComponent, DateRangeInputComponent, DialogAction, DialogComponent, DisableIfRoleDirective, EmptyComponent, EntityAction, ExportService,
|
|
1976
|
+
export { Action, AvatarService, BaseEditClass, BaseFilterClass, BaseMatChipComponent, BaseNavBarMenuClass, BasePageClass, BaseSelectAutocompleteWithVsComponent, BaseSelectWithGroupComponent, BaseServiceClass, BaseToolbarComponent, DateRangeInputComponent, DialogAction, DialogComponent, DisableIfRoleDirective, EmptyComponent, EntityAction, ExportService, HideIfForbiddenRoleDirective, LOGGER_CONFIG, LoaderService, LocalStorageService, LoggerService, LoginPageComponent, MY_FORMATS, NavBarComponent, NotFoundComponent, ProgressSpinnerComponent, SafePipe, SecUser, SetValueDirective, SseService, TableComponent, TimePipe, TruncatePipe, authGuard, dateFormat, provideLogger, redirectGuard, roleGuard };
|
|
1882
1977
|
//# sourceMappingURL=kuzntsv-uikit-ui.mjs.map
|