@noatgnu/cupcake-core 1.3.2 → 1.3.5
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.
|
@@ -4,7 +4,7 @@ import * as i1 from '@angular/common/http';
|
|
|
4
4
|
import { HttpClient, HttpParams, provideHttpClient, withInterceptors, HttpClientModule } from '@angular/common/http';
|
|
5
5
|
import { BehaviorSubject, catchError, throwError, switchMap, filter, take, map, tap, Subject, timer, EMPTY, interval, debounceTime, distinctUntilChanged } from 'rxjs';
|
|
6
6
|
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
|
7
|
-
import { map as map$1, takeUntil, tap as tap$1, switchMap as switchMap$1
|
|
7
|
+
import { map as map$1, takeUntil, tap as tap$1, switchMap as switchMap$1 } from 'rxjs/operators';
|
|
8
8
|
import * as i1$1 from '@angular/forms';
|
|
9
9
|
import { FormBuilder, Validators, ReactiveFormsModule, FormsModule, NonNullableFormBuilder } from '@angular/forms';
|
|
10
10
|
import * as i2 from '@angular/common';
|
|
@@ -374,21 +374,23 @@ class AuthService {
|
|
|
374
374
|
state: response.state
|
|
375
375
|
})));
|
|
376
376
|
}
|
|
377
|
-
handleORCIDCallback(code, state) {
|
|
378
|
-
const params = new URLSearchParams({ code, state });
|
|
377
|
+
handleORCIDCallback(code, state, rememberMe = false) {
|
|
378
|
+
const params = new URLSearchParams({ code, state, remember_me: rememberMe.toString() });
|
|
379
379
|
return this.http.get(`${this.apiUrl}/auth/orcid/callback/?${params}`)
|
|
380
380
|
.pipe(tap(response => this.setAuthData(response)));
|
|
381
381
|
}
|
|
382
|
-
exchangeORCIDToken(accessToken, orcidId) {
|
|
382
|
+
exchangeORCIDToken(accessToken, orcidId, rememberMe = false) {
|
|
383
383
|
return this.http.post(`${this.apiUrl}/auth/orcid/token/`, {
|
|
384
384
|
access_token: accessToken,
|
|
385
|
-
orcid_id: orcidId
|
|
385
|
+
orcid_id: orcidId,
|
|
386
|
+
remember_me: rememberMe
|
|
386
387
|
}).pipe(tap(response => this.setAuthData(response)));
|
|
387
388
|
}
|
|
388
|
-
login(username, password) {
|
|
389
|
+
login(username, password, rememberMe = false) {
|
|
389
390
|
return this.http.post(`${this.apiUrl}/auth/login/`, {
|
|
390
391
|
username,
|
|
391
|
-
password
|
|
392
|
+
password,
|
|
393
|
+
remember_me: rememberMe
|
|
392
394
|
}).pipe(tap(response => this.setAuthData(response)));
|
|
393
395
|
}
|
|
394
396
|
logout() {
|
|
@@ -1166,7 +1168,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1166
1168
|
|
|
1167
1169
|
const WEBSOCKET_ENDPOINT = new InjectionToken('WEBSOCKET_ENDPOINT', {
|
|
1168
1170
|
providedIn: 'root',
|
|
1169
|
-
factory: () => 'notifications'
|
|
1171
|
+
factory: () => 'ccc/notifications'
|
|
1170
1172
|
});
|
|
1171
1173
|
class WebSocketService {
|
|
1172
1174
|
authService;
|
|
@@ -1184,7 +1186,7 @@ class WebSocketService {
|
|
|
1184
1186
|
connectionState$ = computed(() => this.connectionState(), ...(ngDevMode ? [{ debugName: "connectionState$" }] : []));
|
|
1185
1187
|
lastError$ = computed(() => this.lastError(), ...(ngDevMode ? [{ debugName: "lastError$" }] : []));
|
|
1186
1188
|
config_token = inject(CUPCAKE_CORE_CONFIG);
|
|
1187
|
-
endpoint = inject(WEBSOCKET_ENDPOINT, { optional: true }) || 'notifications';
|
|
1189
|
+
endpoint = inject(WEBSOCKET_ENDPOINT, { optional: true }) || 'ccc/notifications';
|
|
1188
1190
|
constructor(authService) {
|
|
1189
1191
|
this.authService = authService;
|
|
1190
1192
|
this.config = {
|
|
@@ -1207,14 +1209,14 @@ class WebSocketService {
|
|
|
1207
1209
|
const url = new URL(apiUrl);
|
|
1208
1210
|
const protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
1209
1211
|
const host = url.host;
|
|
1210
|
-
const endpoint = this.config?.endpoint || 'notifications';
|
|
1212
|
+
const endpoint = this.config?.endpoint || 'ccc/notifications';
|
|
1211
1213
|
return `${protocol}//${host}/ws/${endpoint}/`;
|
|
1212
1214
|
}
|
|
1213
1215
|
catch (error) {
|
|
1214
1216
|
console.error('Invalid API URL in cupcake config:', apiUrl);
|
|
1215
1217
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
1216
1218
|
const host = window.location.host;
|
|
1217
|
-
const endpoint = this.config?.endpoint || 'notifications';
|
|
1219
|
+
const endpoint = this.config?.endpoint || 'ccc/notifications';
|
|
1218
1220
|
return `${protocol}//${host}/ws/${endpoint}/`;
|
|
1219
1221
|
}
|
|
1220
1222
|
}
|
|
@@ -1472,6 +1474,9 @@ class AsyncTaskMonitorService extends BaseApiService {
|
|
|
1472
1474
|
tasksSubject = new BehaviorSubject([]);
|
|
1473
1475
|
isSubscribed = false;
|
|
1474
1476
|
websocket = inject(WebSocketService);
|
|
1477
|
+
constructor() {
|
|
1478
|
+
super();
|
|
1479
|
+
}
|
|
1475
1480
|
tasks$ = this.tasksSubject.asObservable();
|
|
1476
1481
|
activeTasks$ = this.tasks$.pipe(map$1(tasks => {
|
|
1477
1482
|
const taskArray = Array.isArray(tasks) ? tasks : [];
|
|
@@ -1490,21 +1495,16 @@ class AsyncTaskMonitorService extends BaseApiService {
|
|
|
1490
1495
|
}
|
|
1491
1496
|
console.log('AsyncTaskMonitorService: Starting real-time updates');
|
|
1492
1497
|
this.isSubscribed = true;
|
|
1493
|
-
if (!this.websocket.connectionState$() || this.websocket.connectionState$() === 'disconnected') {
|
|
1494
|
-
console.log('AsyncTaskMonitorService: WebSocket not connected, connecting now...');
|
|
1495
|
-
this.websocket.connect();
|
|
1496
|
-
}
|
|
1497
|
-
else {
|
|
1498
|
-
console.log('AsyncTaskMonitorService: WebSocket already connected');
|
|
1499
|
-
}
|
|
1500
|
-
this.websocket.isConnected$.pipe(takeUntil(this.destroy$), filter$1(connected => connected)).subscribe(() => {
|
|
1501
|
-
console.log('AsyncTaskMonitorService: WebSocket connected, subscribing to async_task_updates');
|
|
1502
|
-
this.websocket.subscribe('async_task_updates');
|
|
1503
|
-
});
|
|
1504
1498
|
this.websocket.filterMessages('async_task.update').pipe(takeUntil(this.destroy$)).subscribe((message) => {
|
|
1505
1499
|
console.log('AsyncTaskMonitorService: Received async_task.update message:', message);
|
|
1506
1500
|
this.handleTaskUpdate(message);
|
|
1507
1501
|
});
|
|
1502
|
+
this.websocket.isConnected$.pipe(takeUntil(this.destroy$)).subscribe(isConnected => {
|
|
1503
|
+
if (isConnected) {
|
|
1504
|
+
console.log('AsyncTaskMonitorService: WebSocket connected, subscribing to async_task_updates channel');
|
|
1505
|
+
this.websocket.subscribe('async_task_updates');
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
1508
|
this.loadAllTasks();
|
|
1509
1509
|
}
|
|
1510
1510
|
stopRealtimeUpdates() {
|
|
@@ -1535,7 +1535,14 @@ class AsyncTaskMonitorService extends BaseApiService {
|
|
|
1535
1535
|
console.log('AsyncTaskMonitorService: Current tasks in subject:', currentTasks.length);
|
|
1536
1536
|
const existingTaskIndex = currentTasks.findIndex(t => t.id === taskId);
|
|
1537
1537
|
console.log('AsyncTaskMonitorService: Existing task index:', existingTaskIndex);
|
|
1538
|
-
|
|
1538
|
+
const isTaskCompleted = message.status === TaskStatus.SUCCESS ||
|
|
1539
|
+
message.status === TaskStatus.FAILURE ||
|
|
1540
|
+
message.status === TaskStatus.CANCELLED;
|
|
1541
|
+
if (isTaskCompleted) {
|
|
1542
|
+
console.log('AsyncTaskMonitorService: Task completed, fetching full task details from API');
|
|
1543
|
+
this.loadSingleTask(taskId);
|
|
1544
|
+
}
|
|
1545
|
+
else if (existingTaskIndex >= 0) {
|
|
1539
1546
|
const existingTask = currentTasks[existingTaskIndex];
|
|
1540
1547
|
const updatedTask = {
|
|
1541
1548
|
...existingTask,
|
|
@@ -1555,7 +1562,30 @@ class AsyncTaskMonitorService extends BaseApiService {
|
|
|
1555
1562
|
this.loadAllTasks();
|
|
1556
1563
|
}
|
|
1557
1564
|
}
|
|
1558
|
-
|
|
1565
|
+
loadSingleTask(taskId) {
|
|
1566
|
+
this.get(`${this.apiUrl}/async-tasks/${taskId}/`).subscribe({
|
|
1567
|
+
next: (task) => {
|
|
1568
|
+
console.log('AsyncTaskMonitorService: Loaded single task from API:', task);
|
|
1569
|
+
const currentTasks = this.tasksSubject.value;
|
|
1570
|
+
const existingTaskIndex = currentTasks.findIndex(t => t.id === taskId);
|
|
1571
|
+
if (existingTaskIndex >= 0) {
|
|
1572
|
+
const updatedTasks = [...currentTasks];
|
|
1573
|
+
updatedTasks[existingTaskIndex] = task;
|
|
1574
|
+
console.log('AsyncTaskMonitorService: Updated task in list with full details');
|
|
1575
|
+
this.tasksSubject.next(updatedTasks);
|
|
1576
|
+
}
|
|
1577
|
+
else {
|
|
1578
|
+
console.log('AsyncTaskMonitorService: Adding new task to list');
|
|
1579
|
+
this.tasksSubject.next([task, ...currentTasks]);
|
|
1580
|
+
}
|
|
1581
|
+
},
|
|
1582
|
+
error: (error) => {
|
|
1583
|
+
console.error('AsyncTaskMonitorService: Error loading single task:', error);
|
|
1584
|
+
this.loadAllTasks();
|
|
1585
|
+
}
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: AsyncTaskMonitorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1559
1589
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: AsyncTaskMonitorService, providedIn: 'root' });
|
|
1560
1590
|
}
|
|
1561
1591
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: AsyncTaskMonitorService, decorators: [{
|
|
@@ -1563,7 +1593,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1563
1593
|
args: [{
|
|
1564
1594
|
providedIn: 'root'
|
|
1565
1595
|
}]
|
|
1566
|
-
}] });
|
|
1596
|
+
}], ctorParameters: () => [] });
|
|
1567
1597
|
|
|
1568
1598
|
class ToastService {
|
|
1569
1599
|
toastsSignal = signal([], ...(ngDevMode ? [{ debugName: "toastsSignal" }] : []));
|
|
@@ -1939,8 +1969,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1939
1969
|
|
|
1940
1970
|
const WEBSOCKET_ENDPOINTS = new InjectionToken('WEBSOCKET_ENDPOINTS');
|
|
1941
1971
|
class WebSocketEndpoints {
|
|
1942
|
-
static CORE_NOTIFICATIONS = 'notifications';
|
|
1943
|
-
static CORE_ADMIN = 'admin';
|
|
1972
|
+
static CORE_NOTIFICATIONS = 'ccc/notifications';
|
|
1973
|
+
static CORE_ADMIN = 'ccc/admin';
|
|
1944
1974
|
}
|
|
1945
1975
|
class WebSocketConfigService {
|
|
1946
1976
|
endpoints = new Map();
|
|
@@ -1992,6 +2022,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1992
2022
|
}]
|
|
1993
2023
|
}], ctorParameters: () => [] });
|
|
1994
2024
|
|
|
2025
|
+
class AdminWebSocketService extends WebSocketService {
|
|
2026
|
+
constructor(authService) {
|
|
2027
|
+
super(authService);
|
|
2028
|
+
this.endpoint = 'ccc/admin';
|
|
2029
|
+
this.config.endpoint = 'ccc/admin';
|
|
2030
|
+
this.config.url = this.getWebSocketUrl();
|
|
2031
|
+
}
|
|
2032
|
+
getAdminNotifications() {
|
|
2033
|
+
return this.filterMessages('admin.notification');
|
|
2034
|
+
}
|
|
2035
|
+
getSystemNotifications() {
|
|
2036
|
+
return this.filterMessages('system.notification');
|
|
2037
|
+
}
|
|
2038
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: AdminWebSocketService, deps: [{ token: AuthService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2039
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: AdminWebSocketService, providedIn: 'root' });
|
|
2040
|
+
}
|
|
2041
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: AdminWebSocketService, decorators: [{
|
|
2042
|
+
type: Injectable,
|
|
2043
|
+
args: [{
|
|
2044
|
+
providedIn: 'root'
|
|
2045
|
+
}]
|
|
2046
|
+
}], ctorParameters: () => [{ type: AuthService }] });
|
|
2047
|
+
|
|
1995
2048
|
class LabGroupService extends BaseApiService {
|
|
1996
2049
|
// LAB GROUPS
|
|
1997
2050
|
getLabGroups(params) {
|
|
@@ -2207,7 +2260,8 @@ class LoginComponent {
|
|
|
2207
2260
|
constructor() {
|
|
2208
2261
|
this.loginForm = this.fb.group({
|
|
2209
2262
|
username: ['', [Validators.required]],
|
|
2210
|
-
password: ['', [Validators.required]]
|
|
2263
|
+
password: ['', [Validators.required]],
|
|
2264
|
+
rememberMe: [false]
|
|
2211
2265
|
});
|
|
2212
2266
|
}
|
|
2213
2267
|
returnUrl = '/';
|
|
@@ -2318,8 +2372,8 @@ class LoginComponent {
|
|
|
2318
2372
|
if (this.loginForm.valid) {
|
|
2319
2373
|
this.loading.set(true);
|
|
2320
2374
|
this.error.set(null);
|
|
2321
|
-
const { username, password } = this.loginForm.value;
|
|
2322
|
-
this.authService.login(username, password).subscribe({
|
|
2375
|
+
const { username, password, rememberMe } = this.loginForm.value;
|
|
2376
|
+
this.authService.login(username, password, rememberMe || false).subscribe({
|
|
2323
2377
|
next: (response) => {
|
|
2324
2378
|
this.success.set('Login successful!');
|
|
2325
2379
|
setTimeout(() => {
|
|
@@ -2363,7 +2417,8 @@ class LoginComponent {
|
|
|
2363
2417
|
return;
|
|
2364
2418
|
}
|
|
2365
2419
|
sessionStorage.removeItem('orcid_state');
|
|
2366
|
-
this.
|
|
2420
|
+
const rememberMe = this.loginForm.get('rememberMe')?.value || false;
|
|
2421
|
+
this.authService.handleORCIDCallback(code, state, rememberMe).subscribe({
|
|
2367
2422
|
next: (response) => {
|
|
2368
2423
|
this.success.set(`Welcome, ${response.user.firstName || response.user.username}!`);
|
|
2369
2424
|
setTimeout(() => {
|
|
@@ -2395,6 +2450,11 @@ class LoginComponent {
|
|
|
2395
2450
|
shouldShowRegistration = computed(() => this.registrationStatus()?.registrationEnabled === true, ...(ngDevMode ? [{ debugName: "shouldShowRegistration" }] : []));
|
|
2396
2451
|
shouldShowRegularLogin = computed(() => this.authConfig()?.regularLoginEnabled !== false, ...(ngDevMode ? [{ debugName: "shouldShowRegularLogin" }] : []));
|
|
2397
2452
|
registrationMessage = computed(() => this.registrationStatus()?.message || 'Registration is currently enabled', ...(ngDevMode ? [{ debugName: "registrationMessage" }] : []));
|
|
2453
|
+
rememberMeDuration = computed(() => {
|
|
2454
|
+
const config = this.authConfig();
|
|
2455
|
+
const days = config?.jwtTokenLifetimes?.rememberMe?.refreshTokenDays || 30;
|
|
2456
|
+
return days;
|
|
2457
|
+
}, ...(ngDevMode ? [{ debugName: "rememberMeDuration" }] : []));
|
|
2398
2458
|
/**
|
|
2399
2459
|
* Navigate to registration page
|
|
2400
2460
|
*/
|
|
@@ -2404,11 +2464,11 @@ class LoginComponent {
|
|
|
2404
2464
|
});
|
|
2405
2465
|
}
|
|
2406
2466
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2407
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: LoginComponent, isStandalone: true, selector: "ccc-login", ngImport: i0, template: "<div class=\"container\">\r\n <div class=\"login-wrapper\">\r\n <div class=\"card\">\r\n <div class=\"card-body\">\r\n @if (siteConfig$ | async; as config) {\r\n <h3 class=\"card-title text-center mb-4\">\r\n <i class=\"bi bi-flask me-2\"></i>{{ config.siteName }}\r\n </h3>\r\n }\r\n\r\n <!-- Success Alert -->\r\n @if (success()) {\r\n <ngb-alert type=\"success\" (closed)=\"clearSuccess()\" [dismissible]=\"true\">\r\n {{ success() }}\r\n </ngb-alert>\r\n }\r\n\r\n <!-- Error Alert -->\r\n @if (error()) {\r\n <ngb-alert type=\"danger\" (closed)=\"clearError()\" [dismissible]=\"true\">\r\n {{ error() }}\r\n </ngb-alert>\r\n }\r\n\r\n <!-- ORCID Login Section -->\r\n @if (shouldShowOrcidLogin()) {\r\n <div class=\"mb-4\">\r\n <button \r\n type=\"button\" \r\n class=\"btn btn-primary w-100 mb-3\"\r\n [disabled]=\"loading()\"\r\n (click)=\"loginWithORCID()\">\r\n @if (loading()) {\r\n <span class=\"spinner-border spinner-border-sm me-2\" aria-hidden=\"true\"></span>\r\n }\r\n <i class=\"bi bi-person-badge me-2\"></i>\r\n Login with ORCID\r\n </button>\r\n <p class=\"text-muted text-center small\">\r\n Sign in with your ORCID account for seamless access\r\n </p>\r\n </div>\r\n }\r\n\r\n <!-- Divider -->\r\n @if (shouldShowOrcidLogin() && shouldShowRegularLogin()) {\r\n <div class=\"text-center mb-4\">\r\n <span class=\"text-muted\">or</span>\r\n </div>\r\n }\r\n\r\n <!-- Traditional Login Form -->\r\n @if (shouldShowRegularLogin()) {\r\n <form [formGroup]=\"loginForm\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"mb-3\">\r\n <label for=\"username\" class=\"form-label\">Username</label>\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <i class=\"bi bi-person\"></i>\r\n </span>\r\n <input \r\n type=\"text\" \r\n class=\"form-control\" \r\n id=\"username\"\r\n formControlName=\"username\"\r\n [class.is-invalid]=\"loginForm.get('username')?.invalid && loginForm.get('username')?.touched\"\r\n placeholder=\"Enter your username\">\r\n </div>\r\n @if (loginForm.get('username')?.invalid && loginForm.get('username')?.touched) {\r\n <div class=\"invalid-feedback d-block\">\r\n Username is required\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"mb-3\">\r\n <label for=\"password\" class=\"form-label\">Password</label>\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <i class=\"bi bi-lock\"></i>\r\n </span>\r\n <input \r\n type=\"password\" \r\n class=\"form-control\" \r\n id=\"password\"\r\n formControlName=\"password\"\r\n [class.is-invalid]=\"loginForm.get('password')?.invalid && loginForm.get('password')?.touched\"\r\n placeholder=\"Enter your password\">\r\n </div>\r\n @if (loginForm.get('password')?.invalid && loginForm.get('password')?.touched) {\r\n <div class=\"invalid-feedback d-block\">\r\n Password is required\r\n </div>\r\n }\r\n </div>\r\n\r\n <button \r\n type=\"submit\" \r\n class=\"btn btn-outline-primary w-100\"\r\n [disabled]=\"loginForm.invalid || loading()\">\r\n @if (loading()) {\r\n <span class=\"spinner-border spinner-border-sm me-2\" aria-hidden=\"true\"></span>\r\n }\r\n <i class=\"bi bi-box-arrow-in-right me-2\"></i>\r\n Sign In\r\n </button>\r\n </form>\r\n }\r\n\r\n <!-- Registration Information -->\r\n @if (shouldShowRegistration()) {\r\n <div class=\"mt-4 text-center\">\r\n <div class=\"alert alert-info py-2\" role=\"alert\">\r\n <i class=\"bi bi-person-plus me-1\"></i>\r\n <strong>New Users:</strong> {{ registrationMessage() }}\r\n <div class=\"mt-2\">\r\n <button type=\"button\" class=\"btn btn-outline-primary btn-sm\" (click)=\"goToRegister()\">\r\n <i class=\"bi bi-person-plus me-1\"></i>Create Account\r\n </button>\r\n </div>\r\n <div class=\"mt-1\">\r\n <small class=\"text-muted\">\r\n @if (shouldShowOrcidLogin()) {\r\n <span>You can also sign in with ORCID to create an account</span>\r\n }\r\n </small>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Additional Information -->\r\n @if (siteConfig$ | async; as config) {\r\n <div class=\"mt-4 text-center\">\r\n <p class=\"text-muted small\">\r\n {{ config.siteName }} - Scientific Metadata Management\r\n </p>\r\n @if (shouldShowOrcidLogin() && !shouldShowRegistration()) {\r\n <p class=\"text-muted small\">\r\n <i class=\"bi bi-info-circle me-1\"></i>\r\n New users can sign in directly with ORCID\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".container{min-height:100vh;display:flex;align-items:center;justify-content:center;background:none;overflow:auto}.login-wrapper{width:100%;max-width:450px}.card{border:none;border-radius:12px;box-shadow:0 8px 24px var(--cupcake-shadow);background:var(--cupcake-card-bg);backdrop-filter:blur(10px);width:100%}.card-body{padding:2rem}.card-title{color:var(--cupcake-text);font-weight:600}.btn-primary{background:linear-gradient(135deg,var(--cupcake-primary) 0%,var(--cupcake-primary-dark) 100%);border:none;border-radius:8px;padding:12px;font-weight:500;transition:all .3s ease}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(var(--cupcake-primary-rgb),.3)}.btn-outline-primary{border-radius:8px;padding:12px;font-weight:500;transition:all .3s ease}.btn-outline-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(var(--cupcake-primary-rgb),.2)}.input-group-text{background:var(--cupcake-bg-tertiary);border-color:var(--cupcake-border);color:var(--cupcake-text-muted)}.form-control{border-radius:0 8px 8px 0;transition:all .3s ease}.form-control:focus{box-shadow:0 0 0 .2rem rgba(var(--cupcake-primary-rgb),.15);border-color:var(--cupcake-primary)}.input-group-text:first-child{border-radius:8px 0 0 8px}.spinner-border-sm{width:1rem;height:1rem}ngb-alert{border-radius:8px;border:none}ngb-alert.alert-success{background:var(--bs-success-bg-subtle, rgba(25, 135, 84, .1));color:var(--bs-success-text-emphasis, #0f5132);border:1px solid var(--bs-success-border-subtle, rgba(25, 135, 84, .2))}ngb-alert.alert-danger{background:var(--bs-danger-bg-subtle, rgba(220, 53, 69, .1));color:var(--bs-danger-text-emphasis, #842029);border:1px solid var(--bs-danger-border-subtle, rgba(220, 53, 69, .2))}:root[data-bs-theme=dark] ngb-alert.alert-success,.dark-mode ngb-alert.alert-success{background:#19875426;color:#75b798;border:1px solid rgba(25,135,84,.3)}:root[data-bs-theme=dark] ngb-alert.alert-danger,.dark-mode ngb-alert.alert-danger{background:#dc354526;color:#ea868f;border:1px solid rgba(220,53,69,.3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: NgbAlert, selector: "ngb-alert", inputs: ["animation", "dismissible", "type"], outputs: ["closed"], exportAs: ["ngbAlert"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] });
|
|
2467
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: LoginComponent, isStandalone: true, selector: "ccc-login", ngImport: i0, template: "<div class=\"container\">\r\n <div class=\"login-wrapper\">\r\n <div class=\"card\">\r\n <div class=\"card-body\">\r\n @if (siteConfig$ | async; as config) {\r\n <h3 class=\"card-title text-center mb-4\">\r\n <i class=\"bi bi-flask me-2\"></i>{{ config.siteName }}\r\n </h3>\r\n }\r\n\r\n <!-- Success Alert -->\r\n @if (success()) {\r\n <ngb-alert type=\"success\" (closed)=\"clearSuccess()\" [dismissible]=\"true\">\r\n {{ success() }}\r\n </ngb-alert>\r\n }\r\n\r\n <!-- Error Alert -->\r\n @if (error()) {\r\n <ngb-alert type=\"danger\" (closed)=\"clearError()\" [dismissible]=\"true\">\r\n {{ error() }}\r\n </ngb-alert>\r\n }\r\n\r\n <!-- ORCID Login Section -->\r\n @if (shouldShowOrcidLogin()) {\r\n <div class=\"mb-4\">\r\n <button \r\n type=\"button\" \r\n class=\"btn btn-primary w-100 mb-3\"\r\n [disabled]=\"loading()\"\r\n (click)=\"loginWithORCID()\">\r\n @if (loading()) {\r\n <span class=\"spinner-border spinner-border-sm me-2\" aria-hidden=\"true\"></span>\r\n }\r\n <i class=\"bi bi-person-badge me-2\"></i>\r\n Login with ORCID\r\n </button>\r\n <p class=\"text-muted text-center small\">\r\n Sign in with your ORCID account for seamless access\r\n </p>\r\n </div>\r\n }\r\n\r\n <!-- Divider -->\r\n @if (shouldShowOrcidLogin() && shouldShowRegularLogin()) {\r\n <div class=\"text-center mb-4\">\r\n <span class=\"text-muted\">or</span>\r\n </div>\r\n }\r\n\r\n <!-- Traditional Login Form -->\r\n @if (shouldShowRegularLogin()) {\r\n <form [formGroup]=\"loginForm\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"mb-3\">\r\n <label for=\"username\" class=\"form-label\">Username</label>\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <i class=\"bi bi-person\"></i>\r\n </span>\r\n <input \r\n type=\"text\" \r\n class=\"form-control\" \r\n id=\"username\"\r\n formControlName=\"username\"\r\n [class.is-invalid]=\"loginForm.get('username')?.invalid && loginForm.get('username')?.touched\"\r\n placeholder=\"Enter your username\">\r\n </div>\r\n @if (loginForm.get('username')?.invalid && loginForm.get('username')?.touched) {\r\n <div class=\"invalid-feedback d-block\">\r\n Username is required\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"mb-3\">\r\n <label for=\"password\" class=\"form-label\">Password</label>\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <i class=\"bi bi-lock\"></i>\r\n </span>\r\n <input\r\n type=\"password\"\r\n class=\"form-control\"\r\n id=\"password\"\r\n formControlName=\"password\"\r\n [class.is-invalid]=\"loginForm.get('password')?.invalid && loginForm.get('password')?.touched\"\r\n placeholder=\"Enter your password\">\r\n </div>\r\n @if (loginForm.get('password')?.invalid && loginForm.get('password')?.touched) {\r\n <div class=\"invalid-feedback d-block\">\r\n Password is required\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"mb-3 form-check\">\r\n <input\r\n type=\"checkbox\"\r\n class=\"form-check-input\"\r\n id=\"rememberMe\"\r\n formControlName=\"rememberMe\">\r\n <label class=\"form-check-label\" for=\"rememberMe\">\r\n <i class=\"bi bi-clock-history me-1\"></i>\r\n Remember me for {{ rememberMeDuration() }} days\r\n </label>\r\n <div class=\"form-text\">\r\n Keep me logged in on this device\r\n </div>\r\n </div>\r\n\r\n <button\r\n type=\"submit\"\r\n class=\"btn btn-outline-primary w-100\"\r\n [disabled]=\"loginForm.invalid || loading()\">\r\n @if (loading()) {\r\n <span class=\"spinner-border spinner-border-sm me-2\" aria-hidden=\"true\"></span>\r\n }\r\n <i class=\"bi bi-box-arrow-in-right me-2\"></i>\r\n Sign In\r\n </button>\r\n </form>\r\n }\r\n\r\n <!-- Registration Information -->\r\n @if (shouldShowRegistration()) {\r\n <div class=\"mt-4 text-center\">\r\n <div class=\"alert alert-info py-2\" role=\"alert\">\r\n <i class=\"bi bi-person-plus me-1\"></i>\r\n <strong>New Users:</strong> {{ registrationMessage() }}\r\n <div class=\"mt-2\">\r\n <button type=\"button\" class=\"btn btn-outline-primary btn-sm\" (click)=\"goToRegister()\">\r\n <i class=\"bi bi-person-plus me-1\"></i>Create Account\r\n </button>\r\n </div>\r\n <div class=\"mt-1\">\r\n <small class=\"text-muted\">\r\n @if (shouldShowOrcidLogin()) {\r\n <span>You can also sign in with ORCID to create an account</span>\r\n }\r\n </small>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Additional Information -->\r\n @if (siteConfig$ | async; as config) {\r\n <div class=\"mt-4 text-center\">\r\n <p class=\"text-muted small\">\r\n {{ config.siteName }} - Scientific Metadata Management\r\n </p>\r\n @if (shouldShowOrcidLogin() && !shouldShowRegistration()) {\r\n <p class=\"text-muted small\">\r\n <i class=\"bi bi-info-circle me-1\"></i>\r\n New users can sign in directly with ORCID\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".container{min-height:100vh;display:flex;align-items:center;justify-content:center;background:none;overflow:auto}.login-wrapper{width:100%;max-width:450px}.card{border:none;border-radius:12px;box-shadow:0 8px 24px var(--cupcake-shadow);background:var(--cupcake-card-bg);backdrop-filter:blur(10px);width:100%}.card-body{padding:2rem}.card-title{color:var(--cupcake-text);font-weight:600}.btn-primary{background:linear-gradient(135deg,var(--cupcake-primary) 0%,var(--cupcake-primary-dark) 100%);border:none;border-radius:8px;padding:12px;font-weight:500;transition:all .3s ease}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(var(--cupcake-primary-rgb),.3)}.btn-outline-primary{border-radius:8px;padding:12px;font-weight:500;transition:all .3s ease}.btn-outline-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(var(--cupcake-primary-rgb),.2)}.input-group-text{background:var(--cupcake-bg-tertiary);border-color:var(--cupcake-border);color:var(--cupcake-text-muted)}.form-control{border-radius:0 8px 8px 0;transition:all .3s ease}.form-control:focus{box-shadow:0 0 0 .2rem rgba(var(--cupcake-primary-rgb),.15);border-color:var(--cupcake-primary)}.input-group-text:first-child{border-radius:8px 0 0 8px}.spinner-border-sm{width:1rem;height:1rem}ngb-alert{border-radius:8px;border:none}ngb-alert.alert-success{background:var(--bs-success-bg-subtle, rgba(25, 135, 84, .1));color:var(--bs-success-text-emphasis, #0f5132);border:1px solid var(--bs-success-border-subtle, rgba(25, 135, 84, .2))}ngb-alert.alert-danger{background:var(--bs-danger-bg-subtle, rgba(220, 53, 69, .1));color:var(--bs-danger-text-emphasis, #842029);border:1px solid var(--bs-danger-border-subtle, rgba(220, 53, 69, .2))}:root[data-bs-theme=dark] ngb-alert.alert-success,.dark-mode ngb-alert.alert-success{background:#19875426;color:#75b798;border:1px solid rgba(25,135,84,.3)}:root[data-bs-theme=dark] ngb-alert.alert-danger,.dark-mode ngb-alert.alert-danger{background:#dc354526;color:#ea868f;border:1px solid rgba(220,53,69,.3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: NgbAlert, selector: "ngb-alert", inputs: ["animation", "dismissible", "type"], outputs: ["closed"], exportAs: ["ngbAlert"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] });
|
|
2408
2468
|
}
|
|
2409
2469
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LoginComponent, decorators: [{
|
|
2410
2470
|
type: Component,
|
|
2411
|
-
args: [{ selector: 'ccc-login', standalone: true, imports: [CommonModule, ReactiveFormsModule, NgbAlert], template: "<div class=\"container\">\r\n <div class=\"login-wrapper\">\r\n <div class=\"card\">\r\n <div class=\"card-body\">\r\n @if (siteConfig$ | async; as config) {\r\n <h3 class=\"card-title text-center mb-4\">\r\n <i class=\"bi bi-flask me-2\"></i>{{ config.siteName }}\r\n </h3>\r\n }\r\n\r\n <!-- Success Alert -->\r\n @if (success()) {\r\n <ngb-alert type=\"success\" (closed)=\"clearSuccess()\" [dismissible]=\"true\">\r\n {{ success() }}\r\n </ngb-alert>\r\n }\r\n\r\n <!-- Error Alert -->\r\n @if (error()) {\r\n <ngb-alert type=\"danger\" (closed)=\"clearError()\" [dismissible]=\"true\">\r\n {{ error() }}\r\n </ngb-alert>\r\n }\r\n\r\n <!-- ORCID Login Section -->\r\n @if (shouldShowOrcidLogin()) {\r\n <div class=\"mb-4\">\r\n <button \r\n type=\"button\" \r\n class=\"btn btn-primary w-100 mb-3\"\r\n [disabled]=\"loading()\"\r\n (click)=\"loginWithORCID()\">\r\n @if (loading()) {\r\n <span class=\"spinner-border spinner-border-sm me-2\" aria-hidden=\"true\"></span>\r\n }\r\n <i class=\"bi bi-person-badge me-2\"></i>\r\n Login with ORCID\r\n </button>\r\n <p class=\"text-muted text-center small\">\r\n Sign in with your ORCID account for seamless access\r\n </p>\r\n </div>\r\n }\r\n\r\n <!-- Divider -->\r\n @if (shouldShowOrcidLogin() && shouldShowRegularLogin()) {\r\n <div class=\"text-center mb-4\">\r\n <span class=\"text-muted\">or</span>\r\n </div>\r\n }\r\n\r\n <!-- Traditional Login Form -->\r\n @if (shouldShowRegularLogin()) {\r\n <form [formGroup]=\"loginForm\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"mb-3\">\r\n <label for=\"username\" class=\"form-label\">Username</label>\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <i class=\"bi bi-person\"></i>\r\n </span>\r\n <input \r\n type=\"text\" \r\n class=\"form-control\" \r\n id=\"username\"\r\n formControlName=\"username\"\r\n [class.is-invalid]=\"loginForm.get('username')?.invalid && loginForm.get('username')?.touched\"\r\n placeholder=\"Enter your username\">\r\n </div>\r\n @if (loginForm.get('username')?.invalid && loginForm.get('username')?.touched) {\r\n <div class=\"invalid-feedback d-block\">\r\n Username is required\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"mb-3\">\r\n <label for=\"password\" class=\"form-label\">Password</label>\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <i class=\"bi bi-lock\"></i>\r\n </span>\r\n <input
|
|
2471
|
+
args: [{ selector: 'ccc-login', standalone: true, imports: [CommonModule, ReactiveFormsModule, NgbAlert], template: "<div class=\"container\">\r\n <div class=\"login-wrapper\">\r\n <div class=\"card\">\r\n <div class=\"card-body\">\r\n @if (siteConfig$ | async; as config) {\r\n <h3 class=\"card-title text-center mb-4\">\r\n <i class=\"bi bi-flask me-2\"></i>{{ config.siteName }}\r\n </h3>\r\n }\r\n\r\n <!-- Success Alert -->\r\n @if (success()) {\r\n <ngb-alert type=\"success\" (closed)=\"clearSuccess()\" [dismissible]=\"true\">\r\n {{ success() }}\r\n </ngb-alert>\r\n }\r\n\r\n <!-- Error Alert -->\r\n @if (error()) {\r\n <ngb-alert type=\"danger\" (closed)=\"clearError()\" [dismissible]=\"true\">\r\n {{ error() }}\r\n </ngb-alert>\r\n }\r\n\r\n <!-- ORCID Login Section -->\r\n @if (shouldShowOrcidLogin()) {\r\n <div class=\"mb-4\">\r\n <button \r\n type=\"button\" \r\n class=\"btn btn-primary w-100 mb-3\"\r\n [disabled]=\"loading()\"\r\n (click)=\"loginWithORCID()\">\r\n @if (loading()) {\r\n <span class=\"spinner-border spinner-border-sm me-2\" aria-hidden=\"true\"></span>\r\n }\r\n <i class=\"bi bi-person-badge me-2\"></i>\r\n Login with ORCID\r\n </button>\r\n <p class=\"text-muted text-center small\">\r\n Sign in with your ORCID account for seamless access\r\n </p>\r\n </div>\r\n }\r\n\r\n <!-- Divider -->\r\n @if (shouldShowOrcidLogin() && shouldShowRegularLogin()) {\r\n <div class=\"text-center mb-4\">\r\n <span class=\"text-muted\">or</span>\r\n </div>\r\n }\r\n\r\n <!-- Traditional Login Form -->\r\n @if (shouldShowRegularLogin()) {\r\n <form [formGroup]=\"loginForm\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"mb-3\">\r\n <label for=\"username\" class=\"form-label\">Username</label>\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <i class=\"bi bi-person\"></i>\r\n </span>\r\n <input \r\n type=\"text\" \r\n class=\"form-control\" \r\n id=\"username\"\r\n formControlName=\"username\"\r\n [class.is-invalid]=\"loginForm.get('username')?.invalid && loginForm.get('username')?.touched\"\r\n placeholder=\"Enter your username\">\r\n </div>\r\n @if (loginForm.get('username')?.invalid && loginForm.get('username')?.touched) {\r\n <div class=\"invalid-feedback d-block\">\r\n Username is required\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"mb-3\">\r\n <label for=\"password\" class=\"form-label\">Password</label>\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <i class=\"bi bi-lock\"></i>\r\n </span>\r\n <input\r\n type=\"password\"\r\n class=\"form-control\"\r\n id=\"password\"\r\n formControlName=\"password\"\r\n [class.is-invalid]=\"loginForm.get('password')?.invalid && loginForm.get('password')?.touched\"\r\n placeholder=\"Enter your password\">\r\n </div>\r\n @if (loginForm.get('password')?.invalid && loginForm.get('password')?.touched) {\r\n <div class=\"invalid-feedback d-block\">\r\n Password is required\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"mb-3 form-check\">\r\n <input\r\n type=\"checkbox\"\r\n class=\"form-check-input\"\r\n id=\"rememberMe\"\r\n formControlName=\"rememberMe\">\r\n <label class=\"form-check-label\" for=\"rememberMe\">\r\n <i class=\"bi bi-clock-history me-1\"></i>\r\n Remember me for {{ rememberMeDuration() }} days\r\n </label>\r\n <div class=\"form-text\">\r\n Keep me logged in on this device\r\n </div>\r\n </div>\r\n\r\n <button\r\n type=\"submit\"\r\n class=\"btn btn-outline-primary w-100\"\r\n [disabled]=\"loginForm.invalid || loading()\">\r\n @if (loading()) {\r\n <span class=\"spinner-border spinner-border-sm me-2\" aria-hidden=\"true\"></span>\r\n }\r\n <i class=\"bi bi-box-arrow-in-right me-2\"></i>\r\n Sign In\r\n </button>\r\n </form>\r\n }\r\n\r\n <!-- Registration Information -->\r\n @if (shouldShowRegistration()) {\r\n <div class=\"mt-4 text-center\">\r\n <div class=\"alert alert-info py-2\" role=\"alert\">\r\n <i class=\"bi bi-person-plus me-1\"></i>\r\n <strong>New Users:</strong> {{ registrationMessage() }}\r\n <div class=\"mt-2\">\r\n <button type=\"button\" class=\"btn btn-outline-primary btn-sm\" (click)=\"goToRegister()\">\r\n <i class=\"bi bi-person-plus me-1\"></i>Create Account\r\n </button>\r\n </div>\r\n <div class=\"mt-1\">\r\n <small class=\"text-muted\">\r\n @if (shouldShowOrcidLogin()) {\r\n <span>You can also sign in with ORCID to create an account</span>\r\n }\r\n </small>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Additional Information -->\r\n @if (siteConfig$ | async; as config) {\r\n <div class=\"mt-4 text-center\">\r\n <p class=\"text-muted small\">\r\n {{ config.siteName }} - Scientific Metadata Management\r\n </p>\r\n @if (shouldShowOrcidLogin() && !shouldShowRegistration()) {\r\n <p class=\"text-muted small\">\r\n <i class=\"bi bi-info-circle me-1\"></i>\r\n New users can sign in directly with ORCID\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".container{min-height:100vh;display:flex;align-items:center;justify-content:center;background:none;overflow:auto}.login-wrapper{width:100%;max-width:450px}.card{border:none;border-radius:12px;box-shadow:0 8px 24px var(--cupcake-shadow);background:var(--cupcake-card-bg);backdrop-filter:blur(10px);width:100%}.card-body{padding:2rem}.card-title{color:var(--cupcake-text);font-weight:600}.btn-primary{background:linear-gradient(135deg,var(--cupcake-primary) 0%,var(--cupcake-primary-dark) 100%);border:none;border-radius:8px;padding:12px;font-weight:500;transition:all .3s ease}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(var(--cupcake-primary-rgb),.3)}.btn-outline-primary{border-radius:8px;padding:12px;font-weight:500;transition:all .3s ease}.btn-outline-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(var(--cupcake-primary-rgb),.2)}.input-group-text{background:var(--cupcake-bg-tertiary);border-color:var(--cupcake-border);color:var(--cupcake-text-muted)}.form-control{border-radius:0 8px 8px 0;transition:all .3s ease}.form-control:focus{box-shadow:0 0 0 .2rem rgba(var(--cupcake-primary-rgb),.15);border-color:var(--cupcake-primary)}.input-group-text:first-child{border-radius:8px 0 0 8px}.spinner-border-sm{width:1rem;height:1rem}ngb-alert{border-radius:8px;border:none}ngb-alert.alert-success{background:var(--bs-success-bg-subtle, rgba(25, 135, 84, .1));color:var(--bs-success-text-emphasis, #0f5132);border:1px solid var(--bs-success-border-subtle, rgba(25, 135, 84, .2))}ngb-alert.alert-danger{background:var(--bs-danger-bg-subtle, rgba(220, 53, 69, .1));color:var(--bs-danger-text-emphasis, #842029);border:1px solid var(--bs-danger-border-subtle, rgba(220, 53, 69, .2))}:root[data-bs-theme=dark] ngb-alert.alert-success,.dark-mode ngb-alert.alert-success{background:#19875426;color:#75b798;border:1px solid rgba(25,135,84,.3)}:root[data-bs-theme=dark] ngb-alert.alert-danger,.dark-mode ngb-alert.alert-danger{background:#dc354526;color:#ea868f;border:1px solid rgba(220,53,69,.3)}\n"] }]
|
|
2412
2472
|
}], ctorParameters: () => [] });
|
|
2413
2473
|
|
|
2414
2474
|
class RegisterComponent {
|
|
@@ -3601,5 +3661,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3601
3661
|
* Generated bundle index. Do not edit.
|
|
3602
3662
|
*/
|
|
3603
3663
|
|
|
3604
|
-
export { AnnotationType, ApiService, AsyncTaskMonitorService, AuthService, BaseApiService, CUPCAKE_CORE_CONFIG, CupcakeCoreModule, InvitationStatus, InvitationStatusLabels, LabGroupService, LabGroupsComponent, LoginComponent, NotificationService, PoweredByFooterComponent, RegisterComponent, ResourceRole, ResourceRoleLabels, ResourceService, ResourceType, ResourceTypeLabels, ResourceVisibility, ResourceVisibilityLabels, SiteConfigComponent, SiteConfigService, TASK_STATUS_COLORS, TASK_STATUS_LABELS, TASK_TYPE_LABELS, TaskStatus, TaskType, ThemeService, ToastContainerComponent, ToastService, UserManagementComponent, UserManagementService, UserProfileComponent, WEBSOCKET_ENDPOINT, WEBSOCKET_ENDPOINTS, WebSocketConfigService, WebSocketEndpoints, WebSocketService, adminGuard, authGuard, authInterceptor, resetRefreshState };
|
|
3664
|
+
export { AdminWebSocketService, AnnotationType, ApiService, AsyncTaskMonitorService, AuthService, BaseApiService, CUPCAKE_CORE_CONFIG, CupcakeCoreModule, InvitationStatus, InvitationStatusLabels, LabGroupService, LabGroupsComponent, LoginComponent, NotificationService, PoweredByFooterComponent, RegisterComponent, ResourceRole, ResourceRoleLabels, ResourceService, ResourceType, ResourceTypeLabels, ResourceVisibility, ResourceVisibilityLabels, SiteConfigComponent, SiteConfigService, TASK_STATUS_COLORS, TASK_STATUS_LABELS, TASK_TYPE_LABELS, TaskStatus, TaskType, ThemeService, ToastContainerComponent, ToastService, UserManagementComponent, UserManagementService, UserProfileComponent, WEBSOCKET_ENDPOINT, WEBSOCKET_ENDPOINTS, WebSocketConfigService, WebSocketEndpoints, WebSocketService, adminGuard, authGuard, authInterceptor, resetRefreshState };
|
|
3605
3665
|
//# sourceMappingURL=noatgnu-cupcake-core.mjs.map
|