@noatgnu/cupcake-core 1.3.4 → 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.
|
@@ -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() {
|
|
@@ -2258,7 +2260,8 @@ class LoginComponent {
|
|
|
2258
2260
|
constructor() {
|
|
2259
2261
|
this.loginForm = this.fb.group({
|
|
2260
2262
|
username: ['', [Validators.required]],
|
|
2261
|
-
password: ['', [Validators.required]]
|
|
2263
|
+
password: ['', [Validators.required]],
|
|
2264
|
+
rememberMe: [false]
|
|
2262
2265
|
});
|
|
2263
2266
|
}
|
|
2264
2267
|
returnUrl = '/';
|
|
@@ -2369,8 +2372,8 @@ class LoginComponent {
|
|
|
2369
2372
|
if (this.loginForm.valid) {
|
|
2370
2373
|
this.loading.set(true);
|
|
2371
2374
|
this.error.set(null);
|
|
2372
|
-
const { username, password } = this.loginForm.value;
|
|
2373
|
-
this.authService.login(username, password).subscribe({
|
|
2375
|
+
const { username, password, rememberMe } = this.loginForm.value;
|
|
2376
|
+
this.authService.login(username, password, rememberMe || false).subscribe({
|
|
2374
2377
|
next: (response) => {
|
|
2375
2378
|
this.success.set('Login successful!');
|
|
2376
2379
|
setTimeout(() => {
|
|
@@ -2414,7 +2417,8 @@ class LoginComponent {
|
|
|
2414
2417
|
return;
|
|
2415
2418
|
}
|
|
2416
2419
|
sessionStorage.removeItem('orcid_state');
|
|
2417
|
-
this.
|
|
2420
|
+
const rememberMe = this.loginForm.get('rememberMe')?.value || false;
|
|
2421
|
+
this.authService.handleORCIDCallback(code, state, rememberMe).subscribe({
|
|
2418
2422
|
next: (response) => {
|
|
2419
2423
|
this.success.set(`Welcome, ${response.user.firstName || response.user.username}!`);
|
|
2420
2424
|
setTimeout(() => {
|
|
@@ -2446,6 +2450,11 @@ class LoginComponent {
|
|
|
2446
2450
|
shouldShowRegistration = computed(() => this.registrationStatus()?.registrationEnabled === true, ...(ngDevMode ? [{ debugName: "shouldShowRegistration" }] : []));
|
|
2447
2451
|
shouldShowRegularLogin = computed(() => this.authConfig()?.regularLoginEnabled !== false, ...(ngDevMode ? [{ debugName: "shouldShowRegularLogin" }] : []));
|
|
2448
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" }] : []));
|
|
2449
2458
|
/**
|
|
2450
2459
|
* Navigate to registration page
|
|
2451
2460
|
*/
|
|
@@ -2455,11 +2464,11 @@ class LoginComponent {
|
|
|
2455
2464
|
});
|
|
2456
2465
|
}
|
|
2457
2466
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2458
|
-
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" }] });
|
|
2459
2468
|
}
|
|
2460
2469
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LoginComponent, decorators: [{
|
|
2461
2470
|
type: Component,
|
|
2462
|
-
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"] }]
|
|
2463
2472
|
}], ctorParameters: () => [] });
|
|
2464
2473
|
|
|
2465
2474
|
class RegisterComponent {
|