@kuzntsv/uikit 1.0.6 → 1.0.8
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 +4 -0
- package/fesm2022/kuzntsv-uikit-interceptors.mjs.map +1 -1
- package/fesm2022/kuzntsv-uikit-ui.mjs +6 -4
- package/fesm2022/kuzntsv-uikit-ui.mjs.map +1 -1
- package/fesm2022/kuzntsv-uikit.mjs.map +1 -1
- package/package.json +1 -1
- package/types/kuzntsv-uikit-ui.d.ts +1 -1
- package/types/kuzntsv-uikit.d.ts +1 -0
|
@@ -28,6 +28,10 @@ const apiPrefixInterceptor = (req, next) => {
|
|
|
28
28
|
const coreAuthInterceptor = (req, next) => {
|
|
29
29
|
const config = inject(UIKIT_CONFIG);
|
|
30
30
|
const router = inject(Router);
|
|
31
|
+
const isAuthDisabled = !!config.auth.disabled;
|
|
32
|
+
if (isAuthDisabled) {
|
|
33
|
+
return next(req); // авторизация полностью отключена
|
|
34
|
+
}
|
|
31
35
|
// 0. маркер пропуска авторизации
|
|
32
36
|
if (req.context.get(BYPASS_AUTH) === true) {
|
|
33
37
|
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 { UIKIT_CONFIG } from '@kuzntsv/uikit';\r\nimport { API_NAME } from '@kuzntsv/uikit';\r\n\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 { HttpInterceptorFn } from '@angular/common/http';\r\nimport { inject } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { EMPTY } from 'rxjs';\r\nimport { UIKIT_CONFIG } from '@kuzntsv/uikit';\r\nimport { BYPASS_AUTH } from '@kuzntsv/uikit';\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 // 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 user = JSON.parse(\r\n localStorage.getItem(config.auth.userStorageKey) || '',\r\n );\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\r\n // Возвращаем пустой Observable или генерируем ошибку отмены запроса\r\n // Чтобы цепочка дальше не шла, так как пользователя уводят на логин\r\n return EMPTY;\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: string;\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(() => errorMsg);\r\n }\r\n\r\n switch (error.status) {\r\n case 0:\r\n errorMsg = 'Сервер не доступен';\r\n notification?.error(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 notification?.error(errorMsg); \r\n // }\r\n break;\r\n case 403:\r\n errorMsg = 'Недостаточно прав для выполнения действия.';\r\n notification?.error(errorMsg);\r\n break;\r\n case 404:\r\n errorMsg = 'Ресурс не найден'; \r\n notification?.error(errorMsg);\r\n break;\r\n case 500:\r\n errorMsg = 'Ошибка сервера. Попробуйте позже.'; \r\n notification?.error(errorMsg);\r\n break;\r\n default:\r\n // Для остальных ошибок (например, 400) просто показываем то, что пришло с сервера\r\n notification?.error(error.error?.message || 'Произошла непредвиденная ошибка');\r\n break;\r\n }\r\n return throwError(() => errorMsg);\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 { UikitInterceptors } from './public-api';\r\nimport { UIKIT_CONFIG, UikitConfig } from '@kuzntsv/uikit';\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 coreAuthInterceptor, // 1. Проверяем токен / редиректим\r\n apiPrefixInterceptor, // 2. Подставляем нужный домен (default/analytics и т.д.)\r\n timeoutInterceptor, // 3. Время таймаута для конкретного запроса\r\n coreErrorInterceptor // 4. Отлавливаем 401/403 ответы от сервера\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
|
+
{"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 { 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 } 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 user = JSON.parse(\r\n localStorage.getItem(config.auth.userStorageKey) || '',\r\n );\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\r\n // Возвращаем пустой Observable или генерируем ошибку отмены запроса\r\n // Чтобы цепочка дальше не шла, так как пользователя уводят на логин\r\n return EMPTY;\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: string;\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(() => errorMsg);\r\n }\r\n\r\n switch (error.status) {\r\n case 0:\r\n errorMsg = 'Сервер не доступен';\r\n notification?.error(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 notification?.error(errorMsg); \r\n // }\r\n break;\r\n case 403:\r\n errorMsg = 'Недостаточно прав для выполнения действия.';\r\n notification?.error(errorMsg);\r\n break;\r\n case 404:\r\n errorMsg = 'Ресурс не найден'; \r\n notification?.error(errorMsg);\r\n break;\r\n case 500:\r\n errorMsg = 'Ошибка сервера. Попробуйте позже.'; \r\n notification?.error(errorMsg);\r\n break;\r\n default:\r\n // Для остальных ошибок (например, 400) просто показываем то, что пришло с сервера\r\n notification?.error(error.error?.message || 'Произошла непредвиденная ошибка');\r\n break;\r\n }\r\n return throwError(() => errorMsg);\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 coreAuthInterceptor, // 1. Проверяем токен / редиректим\r\n apiPrefixInterceptor, // 2. Подставляем нужный домен (default/analytics и т.д.)\r\n timeoutInterceptor, // 3. Время таймаута для конкретного запроса\r\n coreErrorInterceptor // 4. Отлавливаем 401/403 ответы от сервера\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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"}
|
|
@@ -321,12 +321,13 @@ var DialogAction;
|
|
|
321
321
|
|
|
322
322
|
class EmptyComponent {
|
|
323
323
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: EmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
324
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.25", type: EmptyComponent, isStandalone: true, selector: "
|
|
324
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.25", type: EmptyComponent, isStandalone: true, selector: "app-empty-route-guard-holder", ngImport: i0, template: '' // пустой шаблон, так как гуард сразу уводит пользователя со страницы
|
|
325
325
|
, isInline: true });
|
|
326
326
|
}
|
|
327
327
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: EmptyComponent, decorators: [{
|
|
328
328
|
type: Component,
|
|
329
329
|
args: [{
|
|
330
|
+
selector: 'app-empty-route-guard-holder',
|
|
330
331
|
standalone: true,
|
|
331
332
|
template: '' // пустой шаблон, так как гуард сразу уводит пользователя со страницы
|
|
332
333
|
}]
|
|
@@ -656,16 +657,17 @@ class BasePageClass {
|
|
|
656
657
|
subscribeToLoadData(fnGetData, fnGetCount, fnMapEntity) {
|
|
657
658
|
// отменять стримы, созданные ранее
|
|
658
659
|
const subs = this.loadData$
|
|
659
|
-
.pipe(tap(() => this.loaderService.show()), switchMap(() => fnGetData()), map$1(v => fnMapEntity ? v.map(fnMapEntity()) : v))
|
|
660
|
+
.pipe(tap(() => this.loaderService.show()), switchMap(() => fnGetData()), map$1(v => (fnMapEntity && Array.isArray(v)) ? v.map(fnMapEntity()) : v))
|
|
660
661
|
.subscribe({
|
|
661
662
|
next: (response) => {
|
|
662
|
-
this.data.set(response);
|
|
663
|
+
this.data.set(response || []);
|
|
663
664
|
this.loaderService.hide();
|
|
664
665
|
},
|
|
665
666
|
error: (error) => {
|
|
666
667
|
this.loaderService.hide();
|
|
667
668
|
console.log(error);
|
|
668
|
-
|
|
669
|
+
const errorMessage = error.message || error;
|
|
670
|
+
this.notificationService?.error('Произошла ошибка: ' + errorMessage, 0);
|
|
669
671
|
}
|
|
670
672
|
});
|
|
671
673
|
this.subscription?.add(subs);
|