@kengcom202/kcore-ui 0.4.0 → 0.5.0
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/README.md +1 -1
- package/fesm2022/kengcom202-kcore-ui.mjs +411 -83
- package/fesm2022/kengcom202-kcore-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/kengcom202-kcore-ui.d.ts +149 -25
|
@@ -5,6 +5,7 @@ import { FormBuilder, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, Valid
|
|
|
5
5
|
import { HttpClient, HttpErrorResponse } from "@angular/common/http";
|
|
6
6
|
import { ActivatedRoute, Router, RouterLink } from "@angular/router";
|
|
7
7
|
import { catchError, throwError } from "rxjs";
|
|
8
|
+
import { toSignal } from "@angular/core/rxjs-interop";
|
|
8
9
|
var AnchoredPopup = class {
|
|
9
10
|
anchor;
|
|
10
11
|
component;
|
|
@@ -1395,7 +1396,8 @@ const KC_AUTH_CONFIG = new InjectionToken("KC_AUTH_CONFIG");
|
|
|
1395
1396
|
const KC_AUTH_PATHS = {
|
|
1396
1397
|
login: "/login",
|
|
1397
1398
|
register: "/register",
|
|
1398
|
-
ssoCallback: "/sso-callback"
|
|
1399
|
+
ssoCallback: "/sso-callback",
|
|
1400
|
+
thaidCallback: "/thaid-callback"
|
|
1399
1401
|
};
|
|
1400
1402
|
function resolveKcAuthConfig(o) {
|
|
1401
1403
|
return {
|
|
@@ -1404,7 +1406,8 @@ function resolveKcAuthConfig(o) {
|
|
|
1404
1406
|
apiBase: (o.apiBase ?? "/api").replace(/\/+$/, ""),
|
|
1405
1407
|
homeUrl: o.homeUrl || "/",
|
|
1406
1408
|
sso: o.sso ? { label: o.sso.label || "SSO" } : null,
|
|
1407
|
-
|
|
1409
|
+
thaid: o.thaid ? { label: o.thaid.label || "ThaiD" } : null,
|
|
1410
|
+
passwordLogin: o.passwordLogin !== false || !o.sso && !o.thaid,
|
|
1408
1411
|
register: o.register ?? "none",
|
|
1409
1412
|
orgLabel: o.orgLabel || "หน่วยงาน",
|
|
1410
1413
|
adminRoles: o.adminRoles ?? ["admin"],
|
|
@@ -1418,6 +1421,12 @@ function provideKcAuth(options) {
|
|
|
1418
1421
|
useValue: resolveKcAuthConfig(options)
|
|
1419
1422
|
}]);
|
|
1420
1423
|
}
|
|
1424
|
+
const KC_LOGIN_LOCK_SECONDS = 300;
|
|
1425
|
+
function kcLoginRetryAfter(err) {
|
|
1426
|
+
if (!(err instanceof HttpErrorResponse) || err.status !== 429) return 0;
|
|
1427
|
+
const s = Number(err.error?.retryAfter);
|
|
1428
|
+
return Number.isFinite(s) && s > 0 ? Math.ceil(s) : 300;
|
|
1429
|
+
}
|
|
1421
1430
|
function kcErrorMessage(err, fallback) {
|
|
1422
1431
|
if (err instanceof HttpErrorResponse) {
|
|
1423
1432
|
const m = err.error?.message;
|
|
@@ -1429,6 +1438,7 @@ function kcErrorMessage(err, fallback) {
|
|
|
1429
1438
|
const SESSION_KEY = "kc_session";
|
|
1430
1439
|
const KC_SSO_STATE_KEY = "kc_sso_state";
|
|
1431
1440
|
const KC_SSO_TICKET_KEY = "kc_sso_ticket";
|
|
1441
|
+
const KC_THAID_STATE_KEY = "kc_thaid_state";
|
|
1432
1442
|
const KC_RETURN_URL_KEY = "kc_return_url";
|
|
1433
1443
|
function kcTokenExpired(token, now = Date.now()) {
|
|
1434
1444
|
const part = token.split(".")[1];
|
|
@@ -1492,6 +1502,7 @@ var KcAuthService = class KcAuthService {
|
|
|
1492
1502
|
for (const k of [
|
|
1493
1503
|
KC_SSO_STATE_KEY,
|
|
1494
1504
|
KC_SSO_TICKET_KEY,
|
|
1505
|
+
KC_THAID_STATE_KEY,
|
|
1495
1506
|
KC_RETURN_URL_KEY
|
|
1496
1507
|
]) this.storage("sessionStorage")?.removeItem(k);
|
|
1497
1508
|
}
|
|
@@ -1719,6 +1730,9 @@ const AUTH_CSS = `
|
|
|
1719
1730
|
.kc-auth-field-error { color: var(--kc-auth-danger, #c62828); font-size: 0.86em; }
|
|
1720
1731
|
.kc-auth-hint { margin: 2px 0 0; color: var(--kc-auth-muted, #806f80); font-size: 0.86em; }
|
|
1721
1732
|
.kc-auth-check { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none; }
|
|
1733
|
+
.kc-auth-check:has(input:disabled) { cursor: not-allowed; opacity: 0.7; }
|
|
1734
|
+
.kc-auth-methods { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 22px; }
|
|
1735
|
+
.kc-auth-methods > .kc-auth-btn { margin-left: auto; min-width: 110px; }
|
|
1722
1736
|
|
|
1723
1737
|
/* ---- ปุ่ม ---- */
|
|
1724
1738
|
.kc-auth-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin-top: 6px; }
|
|
@@ -1760,7 +1774,7 @@ const AUTH_CSS = `
|
|
|
1760
1774
|
.kc-auth-btn-row { display: flex; gap: 10px; margin-top: 6px; }
|
|
1761
1775
|
.kc-auth-btn-row > .kc-auth-btn { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
1762
1776
|
/* ปิดรหัสผ่าน: ปุ่ม SSO ปุ่มเดียวตรงกลาง */
|
|
1763
|
-
.kc-auth-sso-only { display: flex;
|
|
1777
|
+
.kc-auth-sso-only { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 8px 0 4px; }
|
|
1764
1778
|
.kc-auth-sso-only > .kc-auth-btn { min-width: 75%; height: 46px; padding: 0 24px; font-size: 1.05em; }
|
|
1765
1779
|
.kc-auth-btn.block { display: flex; width: 100%; }
|
|
1766
1780
|
.kc-auth-btn.sm { height: 30px; padding: 0 10px; font-size: 0.93em; }
|
|
@@ -1981,6 +1995,23 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
1981
1995
|
}],
|
|
1982
1996
|
ctorParameters: () => []
|
|
1983
1997
|
});
|
|
1998
|
+
const KC_LOGIN_LOCK_KEY = "kc_login_lock";
|
|
1999
|
+
const lockKey = (username) => username.trim().toLowerCase();
|
|
2000
|
+
function readLocks(storage) {
|
|
2001
|
+
try {
|
|
2002
|
+
const raw = JSON.parse(storage?.getItem("kc_login_lock") ?? "{}");
|
|
2003
|
+
const now = Date.now();
|
|
2004
|
+
return Object.fromEntries(Object.entries(raw && typeof raw === "object" ? raw : {}).filter((e) => typeof e[1] === "number" && e[1] > now));
|
|
2005
|
+
} catch {
|
|
2006
|
+
return {};
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
function writeLocks(storage, locks) {
|
|
2010
|
+
try {
|
|
2011
|
+
if (Object.keys(locks).length) storage?.setItem(KC_LOGIN_LOCK_KEY, JSON.stringify(locks));
|
|
2012
|
+
else storage?.removeItem(KC_LOGIN_LOCK_KEY);
|
|
2013
|
+
} catch {}
|
|
2014
|
+
}
|
|
1984
2015
|
var KcLoginComponent = class KcLoginComponent {
|
|
1985
2016
|
config = inject(KC_AUTH_CONFIG);
|
|
1986
2017
|
paths = KC_AUTH_PATHS;
|
|
@@ -1988,19 +2019,57 @@ var KcLoginComponent = class KcLoginComponent {
|
|
|
1988
2019
|
http = inject(HttpClient);
|
|
1989
2020
|
router = inject(Router);
|
|
1990
2021
|
route = inject(ActivatedRoute);
|
|
2022
|
+
doc = inject(DOCUMENT);
|
|
1991
2023
|
busy = signal("", ...ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []);
|
|
2024
|
+
methods = signal({
|
|
2025
|
+
password: true,
|
|
2026
|
+
sso: true,
|
|
2027
|
+
thaid: true
|
|
2028
|
+
}, ...ngDevMode ? [{ debugName: "methods" }] : /* istanbul ignore next */ []);
|
|
2029
|
+
external = computed(() => [...this.config.sso && this.methods().sso ? [{
|
|
2030
|
+
key: "sso",
|
|
2031
|
+
label: this.config.sso.label,
|
|
2032
|
+
stateKey: KC_SSO_STATE_KEY
|
|
2033
|
+
}] : [], ...this.config.thaid && this.methods().thaid ? [{
|
|
2034
|
+
key: "thaid",
|
|
2035
|
+
label: this.config.thaid.label,
|
|
2036
|
+
stateKey: KC_THAID_STATE_KEY
|
|
2037
|
+
}] : []], ...ngDevMode ? [{ debugName: "external" }] : /* istanbul ignore next */ []);
|
|
2038
|
+
showPassword = computed(() => this.config.passwordLogin && this.methods().password || !this.external().length, ...ngDevMode ? [{ debugName: "showPassword" }] : /* istanbul ignore next */ []);
|
|
1992
2039
|
message = signal(null, ...ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []);
|
|
1993
2040
|
form = inject(FormBuilder).nonNullable.group({
|
|
1994
2041
|
username: ["", Validators.required],
|
|
1995
2042
|
password: ["", Validators.required]
|
|
1996
2043
|
});
|
|
2044
|
+
locks = signal(readLocks(this.storage()), ...ngDevMode ? [{ debugName: "locks" }] : /* istanbul ignore next */ []);
|
|
2045
|
+
now = signal(Date.now(), ...ngDevMode ? [{ debugName: "now" }] : /* istanbul ignore next */ []);
|
|
2046
|
+
username = toSignal(this.form.controls.username.valueChanges, { initialValue: "" });
|
|
2047
|
+
lockLeft = computed(() => {
|
|
2048
|
+
const until = this.locks()[lockKey(this.username())] ?? 0;
|
|
2049
|
+
return Math.max(0, Math.ceil((until - this.now()) / 1e3));
|
|
2050
|
+
}, ...ngDevMode ? [{ debugName: "lockLeft" }] : /* istanbul ignore next */ []);
|
|
2051
|
+
lockText = computed(() => {
|
|
2052
|
+
const s = this.lockLeft();
|
|
2053
|
+
return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
|
|
2054
|
+
}, ...ngDevMode ? [{ debugName: "lockText" }] : /* istanbul ignore next */ []);
|
|
2055
|
+
timer;
|
|
1997
2056
|
constructor() {
|
|
1998
2057
|
ensureAuthStyles();
|
|
2058
|
+
inject(DestroyRef).onDestroy(() => this.stopTimer());
|
|
2059
|
+
if (Object.keys(this.locks()).length) this.startTimer();
|
|
1999
2060
|
}
|
|
2000
2061
|
get returnUrl() {
|
|
2001
2062
|
return this.auth.safeReturnUrl(this.route.snapshot.queryParamMap.get("returnUrl"));
|
|
2002
2063
|
}
|
|
2003
2064
|
ngOnInit() {
|
|
2065
|
+
this.http.get(`${this.config.apiBase}/user/login-methods`).subscribe({
|
|
2066
|
+
next: (m) => this.methods.set({
|
|
2067
|
+
password: m?.password !== false,
|
|
2068
|
+
sso: m?.sso !== false,
|
|
2069
|
+
thaid: m?.thaid !== false
|
|
2070
|
+
}),
|
|
2071
|
+
error: () => {}
|
|
2072
|
+
});
|
|
2004
2073
|
if (this.route.snapshot.queryParamMap.get("expired") === "1") this.message.set({
|
|
2005
2074
|
text: "หมดเวลาการใช้งาน กรุณาเข้าสู่ระบบใหม่",
|
|
2006
2075
|
error: false
|
|
@@ -2008,7 +2077,7 @@ var KcLoginComponent = class KcLoginComponent {
|
|
|
2008
2077
|
else if (this.auth.isLoggedIn()) this.router.navigateByUrl(this.returnUrl);
|
|
2009
2078
|
}
|
|
2010
2079
|
submit() {
|
|
2011
|
-
if (this.busy()) return;
|
|
2080
|
+
if (this.busy() || this.lockLeft()) return;
|
|
2012
2081
|
const v = this.form.getRawValue();
|
|
2013
2082
|
if (!v.username.trim() || !v.password) {
|
|
2014
2083
|
this.message.set({
|
|
@@ -2024,33 +2093,66 @@ var KcLoginComponent = class KcLoginComponent {
|
|
|
2024
2093
|
password: v.password
|
|
2025
2094
|
}).subscribe({
|
|
2026
2095
|
next: (res) => {
|
|
2096
|
+
this.setLock(v.username, 0);
|
|
2027
2097
|
this.auth.start(res);
|
|
2028
2098
|
this.router.navigateByUrl(this.returnUrl);
|
|
2029
2099
|
},
|
|
2030
2100
|
error: (err) => {
|
|
2031
2101
|
this.busy.set("");
|
|
2032
|
-
|
|
2102
|
+
const wait = kcLoginRetryAfter(err);
|
|
2103
|
+
if (wait) this.setLock(v.username, Date.now() + wait * 1e3);
|
|
2104
|
+
else this.message.set({
|
|
2033
2105
|
text: kcErrorMessage(err, "เข้าสู่ระบบไม่สำเร็จ"),
|
|
2034
2106
|
error: true
|
|
2035
2107
|
});
|
|
2036
2108
|
}
|
|
2037
2109
|
});
|
|
2038
2110
|
}
|
|
2039
|
-
|
|
2040
|
-
const
|
|
2041
|
-
if (
|
|
2042
|
-
|
|
2111
|
+
setLock(username, until) {
|
|
2112
|
+
const next = { ...this.locks() };
|
|
2113
|
+
if (until) next[lockKey(username)] = until;
|
|
2114
|
+
else delete next[lockKey(username)];
|
|
2115
|
+
this.locks.set(next);
|
|
2116
|
+
this.now.set(Date.now());
|
|
2117
|
+
writeLocks(this.storage(), next);
|
|
2118
|
+
if (until) this.startTimer();
|
|
2119
|
+
}
|
|
2120
|
+
startTimer() {
|
|
2121
|
+
this.timer ??= setInterval(() => {
|
|
2122
|
+
this.now.set(Date.now());
|
|
2123
|
+
const live = Object.fromEntries(Object.entries(this.locks()).filter(([, until]) => until > this.now()));
|
|
2124
|
+
if (Object.keys(live).length === Object.keys(this.locks()).length) return;
|
|
2125
|
+
this.locks.set(live);
|
|
2126
|
+
writeLocks(this.storage(), live);
|
|
2127
|
+
if (!Object.keys(live).length) this.stopTimer();
|
|
2128
|
+
}, 1e3);
|
|
2129
|
+
}
|
|
2130
|
+
stopTimer() {
|
|
2131
|
+
clearInterval(this.timer);
|
|
2132
|
+
this.timer = void 0;
|
|
2133
|
+
}
|
|
2134
|
+
storage() {
|
|
2135
|
+
try {
|
|
2136
|
+
return this.doc.defaultView?.localStorage ?? null;
|
|
2137
|
+
} catch {
|
|
2138
|
+
return null;
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
startExternal(key) {
|
|
2142
|
+
const p = this.external().find((x) => x.key === key);
|
|
2143
|
+
if (!p || this.busy()) return;
|
|
2144
|
+
this.busy.set(key);
|
|
2043
2145
|
this.message.set(null);
|
|
2044
|
-
this.http.get(`${this.config.apiBase}/user/
|
|
2146
|
+
this.http.get(`${this.config.apiBase}/user/${key}/authorize-url`).subscribe({
|
|
2045
2147
|
next: ({ url, state }) => {
|
|
2046
|
-
this.auth.setTemp(
|
|
2148
|
+
this.auth.setTemp(p.stateKey, state);
|
|
2047
2149
|
this.auth.setTemp(KC_RETURN_URL_KEY, this.returnUrl);
|
|
2048
2150
|
this.auth.redirect(url);
|
|
2049
2151
|
},
|
|
2050
2152
|
error: (err) => {
|
|
2051
2153
|
this.busy.set("");
|
|
2052
2154
|
this.message.set({
|
|
2053
|
-
text: err.status === 404 ? `ระบบยังไม่ได้ตั้งค่าการเข้าสู่ระบบด้วย ${
|
|
2155
|
+
text: err.status === 404 ? `ระบบยังไม่ได้ตั้งค่าการเข้าสู่ระบบด้วย ${p.label}` : kcErrorMessage(err, `ไม่สามารถเชื่อมต่อ ${p.label} ได้ กรุณาลองใหม่อีกครั้ง`),
|
|
2054
2156
|
error: true
|
|
2055
2157
|
});
|
|
2056
2158
|
}
|
|
@@ -2080,11 +2182,15 @@ var KcLoginComponent = class KcLoginComponent {
|
|
|
2080
2182
|
<h1 class="kc-auth-title">{{ config.appName }}</h1>
|
|
2081
2183
|
<p class="kc-auth-subtitle">ลงชื่อเข้าสู่ระบบ</p>
|
|
2082
2184
|
|
|
2083
|
-
@if (
|
|
2185
|
+
@if (lockLeft()) {
|
|
2186
|
+
<div class="kc-auth-alert error" role="alert">
|
|
2187
|
+
เข้าสู่ระบบไม่สำเร็จเกินจำนวนครั้งที่กำหนด กรุณารอ {{ lockText() }} นาที แล้วลองใหม่อีกครั้ง
|
|
2188
|
+
</div>
|
|
2189
|
+
} @else if (message(); as m) {
|
|
2084
2190
|
<div class="kc-auth-alert" [class.error]="m.error" [class.info]="!m.error" role="alert">{{ m.text }}</div>
|
|
2085
2191
|
}
|
|
2086
2192
|
|
|
2087
|
-
@if (
|
|
2193
|
+
@if (showPassword()) {
|
|
2088
2194
|
<form [formGroup]="form" (ngSubmit)="submit()" novalidate>
|
|
2089
2195
|
<label class="kc-auth-field">
|
|
2090
2196
|
<span>ชื่อผู้ใช้</span>
|
|
@@ -2094,31 +2200,34 @@ var KcLoginComponent = class KcLoginComponent {
|
|
|
2094
2200
|
<span>รหัสผ่าน</span>
|
|
2095
2201
|
<kc-password><input class="kc-auth-input" type="password" formControlName="password" autocomplete="current-password" /></kc-password>
|
|
2096
2202
|
</label>
|
|
2097
|
-
<!-- ปุ่มเข้าสู่ระบบกับ SSO อยู่บรรทัดเดียวกัน
|
|
2203
|
+
<!-- ปุ่มเข้าสู่ระบบกับ SSO / ThaiD อยู่บรรทัดเดียวกัน แบ่งเท่ากัน — ปุ่มภายนอกใช้แค่ชื่อเพื่อให้พอดี -->
|
|
2098
2204
|
<div class="kc-auth-btn-row">
|
|
2099
|
-
<button type="submit" class="kc-auth-btn primary" [disabled]="!!busy()">
|
|
2100
|
-
{{ busy() === 'password' ? 'กำลังเข้าสู่ระบบ...' : 'เข้าสู่ระบบ' }}
|
|
2205
|
+
<button type="submit" class="kc-auth-btn primary" [disabled]="!!busy() || !!lockLeft()">
|
|
2206
|
+
{{ busy() === 'password' ? 'กำลังเข้าสู่ระบบ...' : lockLeft() ? 'รอ ' + lockText() : 'เข้าสู่ระบบ' }}
|
|
2101
2207
|
</button>
|
|
2102
|
-
@
|
|
2103
|
-
<button type="button" class="kc-auth-btn outline" [disabled]="!!busy()" (click)="
|
|
2104
|
-
[attr.title]="'เข้าสู่ระบบด้วย ' +
|
|
2105
|
-
{{ busy() ===
|
|
2208
|
+
@for (p of external(); track p.key) {
|
|
2209
|
+
<button type="button" class="kc-auth-btn outline" [disabled]="!!busy()" (click)="startExternal(p.key)"
|
|
2210
|
+
[attr.title]="'เข้าสู่ระบบด้วย ' + p.label">
|
|
2211
|
+
{{ busy() === p.key ? 'กำลังเชื่อมต่อ...' : p.label }}
|
|
2106
2212
|
</button>
|
|
2107
2213
|
}
|
|
2108
2214
|
</div>
|
|
2109
2215
|
</form>
|
|
2110
|
-
} @else
|
|
2111
|
-
<!-- ปิดรหัสผ่าน: มีแต่ปุ่ม SSO ตรงกลาง -->
|
|
2216
|
+
} @else {
|
|
2217
|
+
<!-- ปิดรหัสผ่าน: มีแต่ปุ่ม SSO / ThaiD ตรงกลาง -->
|
|
2112
2218
|
<div class="kc-auth-sso-only">
|
|
2113
|
-
|
|
2114
|
-
|
|
2219
|
+
@for (p of external(); track p.key) {
|
|
2220
|
+
<button type="button" class="kc-auth-btn" [class.primary]="$first" [class.outline]="!$first" [disabled]="!!busy()"
|
|
2221
|
+
(click)="startExternal(p.key)">
|
|
2222
|
+
{{ busy() === p.key ? 'กำลังเชื่อมต่อ...' : 'เข้าสู่ระบบด้วย ' + p.label }}
|
|
2115
2223
|
</button>
|
|
2224
|
+
}
|
|
2116
2225
|
</div>
|
|
2117
2226
|
}
|
|
2118
2227
|
|
|
2119
2228
|
@if (config.register === 'form') {
|
|
2120
2229
|
<p class="kc-auth-footer">ยังไม่มีบัญชี? <a class="kc-auth-link" [routerLink]="paths.register">ลงทะเบียน</a></p>
|
|
2121
|
-
} @else if (config.register === 'sso' && config.sso) {
|
|
2230
|
+
} @else if (config.register === 'sso' && config.sso && methods().sso) {
|
|
2122
2231
|
<p class="kc-auth-footer">ผู้ใช้ใหม่ กดปุ่ม {{ config.sso.label }} เพื่อลงทะเบียน</p>
|
|
2123
2232
|
}
|
|
2124
2233
|
<ng-content />
|
|
@@ -2221,11 +2330,15 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2221
2330
|
<h1 class="kc-auth-title">{{ config.appName }}</h1>
|
|
2222
2331
|
<p class="kc-auth-subtitle">ลงชื่อเข้าสู่ระบบ</p>
|
|
2223
2332
|
|
|
2224
|
-
@if (
|
|
2333
|
+
@if (lockLeft()) {
|
|
2334
|
+
<div class="kc-auth-alert error" role="alert">
|
|
2335
|
+
เข้าสู่ระบบไม่สำเร็จเกินจำนวนครั้งที่กำหนด กรุณารอ {{ lockText() }} นาที แล้วลองใหม่อีกครั้ง
|
|
2336
|
+
</div>
|
|
2337
|
+
} @else if (message(); as m) {
|
|
2225
2338
|
<div class="kc-auth-alert" [class.error]="m.error" [class.info]="!m.error" role="alert">{{ m.text }}</div>
|
|
2226
2339
|
}
|
|
2227
2340
|
|
|
2228
|
-
@if (
|
|
2341
|
+
@if (showPassword()) {
|
|
2229
2342
|
<form [formGroup]="form" (ngSubmit)="submit()" novalidate>
|
|
2230
2343
|
<label class="kc-auth-field">
|
|
2231
2344
|
<span>ชื่อผู้ใช้</span>
|
|
@@ -2235,31 +2348,34 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2235
2348
|
<span>รหัสผ่าน</span>
|
|
2236
2349
|
<kc-password><input class="kc-auth-input" type="password" formControlName="password" autocomplete="current-password" /></kc-password>
|
|
2237
2350
|
</label>
|
|
2238
|
-
<!-- ปุ่มเข้าสู่ระบบกับ SSO อยู่บรรทัดเดียวกัน
|
|
2351
|
+
<!-- ปุ่มเข้าสู่ระบบกับ SSO / ThaiD อยู่บรรทัดเดียวกัน แบ่งเท่ากัน — ปุ่มภายนอกใช้แค่ชื่อเพื่อให้พอดี -->
|
|
2239
2352
|
<div class="kc-auth-btn-row">
|
|
2240
|
-
<button type="submit" class="kc-auth-btn primary" [disabled]="!!busy()">
|
|
2241
|
-
{{ busy() === 'password' ? 'กำลังเข้าสู่ระบบ...' : 'เข้าสู่ระบบ' }}
|
|
2353
|
+
<button type="submit" class="kc-auth-btn primary" [disabled]="!!busy() || !!lockLeft()">
|
|
2354
|
+
{{ busy() === 'password' ? 'กำลังเข้าสู่ระบบ...' : lockLeft() ? 'รอ ' + lockText() : 'เข้าสู่ระบบ' }}
|
|
2242
2355
|
</button>
|
|
2243
|
-
@
|
|
2244
|
-
<button type="button" class="kc-auth-btn outline" [disabled]="!!busy()" (click)="
|
|
2245
|
-
[attr.title]="'เข้าสู่ระบบด้วย ' +
|
|
2246
|
-
{{ busy() ===
|
|
2356
|
+
@for (p of external(); track p.key) {
|
|
2357
|
+
<button type="button" class="kc-auth-btn outline" [disabled]="!!busy()" (click)="startExternal(p.key)"
|
|
2358
|
+
[attr.title]="'เข้าสู่ระบบด้วย ' + p.label">
|
|
2359
|
+
{{ busy() === p.key ? 'กำลังเชื่อมต่อ...' : p.label }}
|
|
2247
2360
|
</button>
|
|
2248
2361
|
}
|
|
2249
2362
|
</div>
|
|
2250
2363
|
</form>
|
|
2251
|
-
} @else
|
|
2252
|
-
<!-- ปิดรหัสผ่าน: มีแต่ปุ่ม SSO ตรงกลาง -->
|
|
2364
|
+
} @else {
|
|
2365
|
+
<!-- ปิดรหัสผ่าน: มีแต่ปุ่ม SSO / ThaiD ตรงกลาง -->
|
|
2253
2366
|
<div class="kc-auth-sso-only">
|
|
2254
|
-
|
|
2255
|
-
|
|
2367
|
+
@for (p of external(); track p.key) {
|
|
2368
|
+
<button type="button" class="kc-auth-btn" [class.primary]="$first" [class.outline]="!$first" [disabled]="!!busy()"
|
|
2369
|
+
(click)="startExternal(p.key)">
|
|
2370
|
+
{{ busy() === p.key ? 'กำลังเชื่อมต่อ...' : 'เข้าสู่ระบบด้วย ' + p.label }}
|
|
2256
2371
|
</button>
|
|
2372
|
+
}
|
|
2257
2373
|
</div>
|
|
2258
2374
|
}
|
|
2259
2375
|
|
|
2260
2376
|
@if (config.register === 'form') {
|
|
2261
2377
|
<p class="kc-auth-footer">ยังไม่มีบัญชี? <a class="kc-auth-link" [routerLink]="paths.register">ลงทะเบียน</a></p>
|
|
2262
|
-
} @else if (config.register === 'sso' && config.sso) {
|
|
2378
|
+
} @else if (config.register === 'sso' && config.sso && methods().sso) {
|
|
2263
2379
|
<p class="kc-auth-footer">ผู้ใช้ใหม่ กดปุ่ม {{ config.sso.label }} เพื่อลงทะเบียน</p>
|
|
2264
2380
|
}
|
|
2265
2381
|
<ng-content />
|
|
@@ -2678,22 +2794,35 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2678
2794
|
}],
|
|
2679
2795
|
ctorParameters: () => []
|
|
2680
2796
|
});
|
|
2681
|
-
|
|
2797
|
+
const CALLBACK_TEMPLATE = `
|
|
2798
|
+
<div class="kc-auth-screen">
|
|
2799
|
+
<div class="kc-auth-card center">
|
|
2800
|
+
<h1 class="kc-auth-title">{{ label }}</h1>
|
|
2801
|
+
@if (failed()) {
|
|
2802
|
+
<div class="kc-auth-alert error" role="alert" style="margin-top: 16px">{{ message() }}</div>
|
|
2803
|
+
<a class="kc-auth-btn" [routerLink]="paths.login">กลับไปหน้าเข้าสู่ระบบ</a>
|
|
2804
|
+
} @else {
|
|
2805
|
+
<p class="kc-auth-subtitle" style="margin-bottom: 0">{{ message() }}</p>
|
|
2806
|
+
}
|
|
2807
|
+
</div>
|
|
2808
|
+
</div>
|
|
2809
|
+
`;
|
|
2810
|
+
var KcExternalCallbackBase = class KcExternalCallbackBase {
|
|
2682
2811
|
config = inject(KC_AUTH_CONFIG);
|
|
2683
2812
|
auth = inject(KcAuthService);
|
|
2684
2813
|
http = inject(HttpClient);
|
|
2685
|
-
route = inject(ActivatedRoute);
|
|
2686
2814
|
router = inject(Router);
|
|
2815
|
+
route = inject(ActivatedRoute);
|
|
2687
2816
|
paths = KC_AUTH_PATHS;
|
|
2688
|
-
|
|
2689
|
-
message = signal(`กำลังเข้าสู่ระบบผ่าน ${this.label}...`, ...ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []);
|
|
2817
|
+
message = signal("", ...ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []);
|
|
2690
2818
|
failed = signal(false, ...ngDevMode ? [{ debugName: "failed" }] : /* istanbul ignore next */ []);
|
|
2691
2819
|
constructor() {
|
|
2692
2820
|
ensureAuthStyles();
|
|
2693
2821
|
}
|
|
2694
2822
|
ngOnInit() {
|
|
2823
|
+
this.message.set(`กำลังเข้าสู่ระบบผ่าน ${this.label}...`);
|
|
2695
2824
|
const params = this.route.snapshot.queryParamMap;
|
|
2696
|
-
const expectedState = this.auth.takeTemp(
|
|
2825
|
+
const expectedState = this.auth.takeTemp(this.stateKey);
|
|
2697
2826
|
const code = params.get("code");
|
|
2698
2827
|
if (params.get("error")) {
|
|
2699
2828
|
this.fail(`${this.label} ปฏิเสธการเข้าสู่ระบบ กรุณาลองใหม่อีกครั้ง`);
|
|
@@ -2701,9 +2830,9 @@ var KcSsoCallbackComponent = class KcSsoCallbackComponent {
|
|
|
2701
2830
|
}
|
|
2702
2831
|
if (!code) {
|
|
2703
2832
|
this.message.set(`กำลังเชื่อมต่อกับ ${this.label}...`);
|
|
2704
|
-
this.http.get(`${this.config.apiBase}/user/
|
|
2833
|
+
this.http.get(`${this.config.apiBase}/user/${this.endpoint}/authorize-url`).subscribe({
|
|
2705
2834
|
next: ({ url, state }) => {
|
|
2706
|
-
this.auth.setTemp(
|
|
2835
|
+
this.auth.setTemp(this.stateKey, state);
|
|
2707
2836
|
this.auth.redirect(url);
|
|
2708
2837
|
},
|
|
2709
2838
|
error: () => this.fail(`ไม่สามารถเชื่อมต่อ ${this.label} ได้ กรุณาเริ่มเข้าสู่ระบบใหม่`)
|
|
@@ -2714,14 +2843,52 @@ var KcSsoCallbackComponent = class KcSsoCallbackComponent {
|
|
|
2714
2843
|
this.fail("คำขอเข้าสู่ระบบไม่ถูกต้อง (state ไม่ตรงกัน) กรุณาเริ่มเข้าสู่ระบบใหม่");
|
|
2715
2844
|
return;
|
|
2716
2845
|
}
|
|
2846
|
+
this.exchange(code);
|
|
2847
|
+
}
|
|
2848
|
+
signIn(session) {
|
|
2849
|
+
this.auth.start(session);
|
|
2850
|
+
this.router.navigateByUrl(this.auth.safeReturnUrl(this.auth.takeTemp(KC_RETURN_URL_KEY)), { replaceUrl: true });
|
|
2851
|
+
}
|
|
2852
|
+
fail(message) {
|
|
2853
|
+
this.message.set(message);
|
|
2854
|
+
this.failed.set(true);
|
|
2855
|
+
}
|
|
2856
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
2857
|
+
minVersion: "12.0.0",
|
|
2858
|
+
version: "22.2.1",
|
|
2859
|
+
ngImport: i0,
|
|
2860
|
+
type: KcExternalCallbackBase,
|
|
2861
|
+
deps: [],
|
|
2862
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
2863
|
+
});
|
|
2864
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
2865
|
+
minVersion: "14.0.0",
|
|
2866
|
+
version: "22.2.1",
|
|
2867
|
+
type: KcExternalCallbackBase,
|
|
2868
|
+
isStandalone: true,
|
|
2869
|
+
ngImport: i0
|
|
2870
|
+
});
|
|
2871
|
+
};
|
|
2872
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
2873
|
+
minVersion: "12.0.0",
|
|
2874
|
+
version: "22.2.1",
|
|
2875
|
+
ngImport: i0,
|
|
2876
|
+
type: KcExternalCallbackBase,
|
|
2877
|
+
decorators: [{ type: Directive }],
|
|
2878
|
+
ctorParameters: () => []
|
|
2879
|
+
});
|
|
2880
|
+
var KcSsoCallbackComponent = class KcSsoCallbackComponent extends KcExternalCallbackBase {
|
|
2881
|
+
label = this.config.sso?.label ?? "SSO";
|
|
2882
|
+
endpoint = "sso";
|
|
2883
|
+
stateKey = KC_SSO_STATE_KEY;
|
|
2884
|
+
exchange(code) {
|
|
2717
2885
|
this.http.post(`${this.config.apiBase}/user/sso/callback`, { code }).subscribe({
|
|
2718
2886
|
next: (res) => {
|
|
2719
2887
|
if (res.mode === "signed-in" && res.token && res.user) {
|
|
2720
|
-
this.
|
|
2888
|
+
this.signIn({
|
|
2721
2889
|
token: res.token,
|
|
2722
2890
|
user: res.user
|
|
2723
2891
|
});
|
|
2724
|
-
this.router.navigateByUrl(this.auth.safeReturnUrl(this.auth.takeTemp(KC_RETURN_URL_KEY)), { replaceUrl: true });
|
|
2725
2892
|
return;
|
|
2726
2893
|
}
|
|
2727
2894
|
if (res.mode === "register" && res.ticket) {
|
|
@@ -2735,16 +2902,12 @@ var KcSsoCallbackComponent = class KcSsoCallbackComponent {
|
|
|
2735
2902
|
error: (err) => this.fail(kcErrorMessage(err, `ไม่สามารถเข้าสู่ระบบผ่าน ${this.label} ได้`))
|
|
2736
2903
|
});
|
|
2737
2904
|
}
|
|
2738
|
-
fail(message) {
|
|
2739
|
-
this.message.set(message);
|
|
2740
|
-
this.failed.set(true);
|
|
2741
|
-
}
|
|
2742
2905
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
2743
2906
|
minVersion: "12.0.0",
|
|
2744
2907
|
version: "22.2.1",
|
|
2745
2908
|
ngImport: i0,
|
|
2746
2909
|
type: KcSsoCallbackComponent,
|
|
2747
|
-
deps:
|
|
2910
|
+
deps: null,
|
|
2748
2911
|
target: i0.ɵɵFactoryTarget.Component
|
|
2749
2912
|
});
|
|
2750
2913
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
@@ -2753,20 +2916,9 @@ var KcSsoCallbackComponent = class KcSsoCallbackComponent {
|
|
|
2753
2916
|
type: KcSsoCallbackComponent,
|
|
2754
2917
|
isStandalone: true,
|
|
2755
2918
|
selector: "kc-sso-callback",
|
|
2919
|
+
usesInheritance: true,
|
|
2756
2920
|
ngImport: i0,
|
|
2757
|
-
template:
|
|
2758
|
-
<div class="kc-auth-screen">
|
|
2759
|
-
<div class="kc-auth-card center">
|
|
2760
|
-
<h1 class="kc-auth-title">{{ label }}</h1>
|
|
2761
|
-
@if (failed()) {
|
|
2762
|
-
<div class="kc-auth-alert error" role="alert" style="margin-top: 16px">{{ message() }}</div>
|
|
2763
|
-
<a class="kc-auth-btn" [routerLink]="paths.login">กลับไปหน้าเข้าสู่ระบบ</a>
|
|
2764
|
-
} @else {
|
|
2765
|
-
<p class="kc-auth-subtitle" style="margin-bottom: 0">{{ message() }}</p>
|
|
2766
|
-
}
|
|
2767
|
-
</div>
|
|
2768
|
-
</div>
|
|
2769
|
-
`,
|
|
2921
|
+
template: "\n <div class=\"kc-auth-screen\">\n <div class=\"kc-auth-card center\">\n <h1 class=\"kc-auth-title\">{{ label }}</h1>\n @if (failed()) {\n <div class=\"kc-auth-alert error\" role=\"alert\" style=\"margin-top: 16px\">{{ message() }}</div>\n <a class=\"kc-auth-btn\" [routerLink]=\"paths.login\">กลับไปหน้าเข้าสู่ระบบ</a>\n } @else {\n <p class=\"kc-auth-subtitle\" style=\"margin-bottom: 0\">{{ message() }}</p>\n }\n </div>\n </div>\n",
|
|
2770
2922
|
isInline: true,
|
|
2771
2923
|
dependencies: [{
|
|
2772
2924
|
kind: "directive",
|
|
@@ -2800,22 +2952,73 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2800
2952
|
selector: "kc-sso-callback",
|
|
2801
2953
|
standalone: true,
|
|
2802
2954
|
imports: [RouterLink],
|
|
2803
|
-
template:
|
|
2804
|
-
<div class="kc-auth-screen">
|
|
2805
|
-
<div class="kc-auth-card center">
|
|
2806
|
-
<h1 class="kc-auth-title">{{ label }}</h1>
|
|
2807
|
-
@if (failed()) {
|
|
2808
|
-
<div class="kc-auth-alert error" role="alert" style="margin-top: 16px">{{ message() }}</div>
|
|
2809
|
-
<a class="kc-auth-btn" [routerLink]="paths.login">กลับไปหน้าเข้าสู่ระบบ</a>
|
|
2810
|
-
} @else {
|
|
2811
|
-
<p class="kc-auth-subtitle" style="margin-bottom: 0">{{ message() }}</p>
|
|
2812
|
-
}
|
|
2813
|
-
</div>
|
|
2814
|
-
</div>
|
|
2815
|
-
`
|
|
2955
|
+
template: CALLBACK_TEMPLATE
|
|
2816
2956
|
}]
|
|
2817
|
-
}]
|
|
2818
|
-
|
|
2957
|
+
}]
|
|
2958
|
+
});
|
|
2959
|
+
var KcThaidCallbackComponent = class KcThaidCallbackComponent extends KcExternalCallbackBase {
|
|
2960
|
+
label = this.config.thaid?.label ?? "ThaiD";
|
|
2961
|
+
endpoint = "thaid";
|
|
2962
|
+
stateKey = KC_THAID_STATE_KEY;
|
|
2963
|
+
exchange(code) {
|
|
2964
|
+
this.http.post(`${this.config.apiBase}/user/thaid/callback`, { code }).subscribe({
|
|
2965
|
+
next: (res) => res?.token && res.user ? this.signIn(res) : this.fail("ไม่สามารถเข้าสู่ระบบได้ กรุณาลองใหม่อีกครั้ง"),
|
|
2966
|
+
error: (err) => this.fail(kcErrorMessage(err, `ไม่สามารถเข้าสู่ระบบผ่าน ${this.label} ได้`))
|
|
2967
|
+
});
|
|
2968
|
+
}
|
|
2969
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
2970
|
+
minVersion: "12.0.0",
|
|
2971
|
+
version: "22.2.1",
|
|
2972
|
+
ngImport: i0,
|
|
2973
|
+
type: KcThaidCallbackComponent,
|
|
2974
|
+
deps: null,
|
|
2975
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
2976
|
+
});
|
|
2977
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
2978
|
+
minVersion: "17.0.0",
|
|
2979
|
+
version: "22.2.1",
|
|
2980
|
+
type: KcThaidCallbackComponent,
|
|
2981
|
+
isStandalone: true,
|
|
2982
|
+
selector: "kc-thaid-callback",
|
|
2983
|
+
usesInheritance: true,
|
|
2984
|
+
ngImport: i0,
|
|
2985
|
+
template: "\n <div class=\"kc-auth-screen\">\n <div class=\"kc-auth-card center\">\n <h1 class=\"kc-auth-title\">{{ label }}</h1>\n @if (failed()) {\n <div class=\"kc-auth-alert error\" role=\"alert\" style=\"margin-top: 16px\">{{ message() }}</div>\n <a class=\"kc-auth-btn\" [routerLink]=\"paths.login\">กลับไปหน้าเข้าสู่ระบบ</a>\n } @else {\n <p class=\"kc-auth-subtitle\" style=\"margin-bottom: 0\">{{ message() }}</p>\n }\n </div>\n </div>\n",
|
|
2986
|
+
isInline: true,
|
|
2987
|
+
dependencies: [{
|
|
2988
|
+
kind: "directive",
|
|
2989
|
+
type: RouterLink,
|
|
2990
|
+
selector: "[routerLink]",
|
|
2991
|
+
inputs: [
|
|
2992
|
+
"target",
|
|
2993
|
+
"queryParams",
|
|
2994
|
+
"fragment",
|
|
2995
|
+
"queryParamsHandling",
|
|
2996
|
+
"state",
|
|
2997
|
+
"info",
|
|
2998
|
+
"relativeTo",
|
|
2999
|
+
"preserveFragment",
|
|
3000
|
+
"skipLocationChange",
|
|
3001
|
+
"replaceUrl",
|
|
3002
|
+
"browserUrl",
|
|
3003
|
+
"routerLink"
|
|
3004
|
+
]
|
|
3005
|
+
}]
|
|
3006
|
+
});
|
|
3007
|
+
};
|
|
3008
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
3009
|
+
minVersion: "12.0.0",
|
|
3010
|
+
version: "22.2.1",
|
|
3011
|
+
ngImport: i0,
|
|
3012
|
+
type: KcThaidCallbackComponent,
|
|
3013
|
+
decorators: [{
|
|
3014
|
+
type: Component,
|
|
3015
|
+
args: [{
|
|
3016
|
+
selector: "kc-thaid-callback",
|
|
3017
|
+
standalone: true,
|
|
3018
|
+
imports: [RouterLink],
|
|
3019
|
+
template: CALLBACK_TEMPLATE
|
|
3020
|
+
}]
|
|
3021
|
+
}]
|
|
2819
3022
|
});
|
|
2820
3023
|
function kcAuthRoutes() {
|
|
2821
3024
|
return [
|
|
@@ -2833,6 +3036,11 @@ function kcAuthRoutes() {
|
|
|
2833
3036
|
path: "sso-callback",
|
|
2834
3037
|
component: KcSsoCallbackComponent,
|
|
2835
3038
|
title: "เข้าสู่ระบบ"
|
|
3039
|
+
},
|
|
3040
|
+
{
|
|
3041
|
+
path: "thaid-callback",
|
|
3042
|
+
component: KcThaidCallbackComponent,
|
|
3043
|
+
title: "เข้าสู่ระบบ"
|
|
2836
3044
|
}
|
|
2837
3045
|
];
|
|
2838
3046
|
}
|
|
@@ -3163,6 +3371,33 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
|
|
|
3163
3371
|
search = signal("", ...ngDevMode ? [{ debugName: "search" }] : /* istanbul ignore next */ []);
|
|
3164
3372
|
editing = signal(null, ...ngDevMode ? [{ debugName: "editing" }] : /* istanbul ignore next */ []);
|
|
3165
3373
|
myId = computed(() => this.auth.user()?.id ?? "", ...ngDevMode ? [{ debugName: "myId" }] : /* istanbul ignore next */ []);
|
|
3374
|
+
methodsSaved = signal(null, ...ngDevMode ? [{ debugName: "methodsSaved" }] : /* istanbul ignore next */ []);
|
|
3375
|
+
methodsDraft = signal(null, ...ngDevMode ? [{ debugName: "methodsDraft" }] : /* istanbul ignore next */ []);
|
|
3376
|
+
savingMethods = signal(false, ...ngDevMode ? [{ debugName: "savingMethods" }] : /* istanbul ignore next */ []);
|
|
3377
|
+
methodsError = signal("", ...ngDevMode ? [{ debugName: "methodsError" }] : /* istanbul ignore next */ []);
|
|
3378
|
+
methodOptions = computed(() => [
|
|
3379
|
+
...this.config.passwordLogin ? [{
|
|
3380
|
+
key: "password",
|
|
3381
|
+
label: "ชื่อผู้ใช้ / รหัสผ่าน"
|
|
3382
|
+
}] : [],
|
|
3383
|
+
...this.config.sso ? [{
|
|
3384
|
+
key: "sso",
|
|
3385
|
+
label: this.config.sso.label
|
|
3386
|
+
}] : [],
|
|
3387
|
+
...this.config.thaid ? [{
|
|
3388
|
+
key: "thaid",
|
|
3389
|
+
label: this.config.thaid.label
|
|
3390
|
+
}] : []
|
|
3391
|
+
], ...ngDevMode ? [{ debugName: "methodOptions" }] : /* istanbul ignore next */ []);
|
|
3392
|
+
enabledCount = computed(() => {
|
|
3393
|
+
const m = this.methodsDraft();
|
|
3394
|
+
return m ? this.methodOptions().filter((o) => m[o.key]).length : 0;
|
|
3395
|
+
}, ...ngDevMode ? [{ debugName: "enabledCount" }] : /* istanbul ignore next */ []);
|
|
3396
|
+
methodsDirty = computed(() => {
|
|
3397
|
+
const a = this.methodsDraft();
|
|
3398
|
+
const b = this.methodsSaved();
|
|
3399
|
+
return !!a && !!b && (a.password !== b.password || a.sso !== b.sso || a.thaid !== b.thaid);
|
|
3400
|
+
}, ...ngDevMode ? [{ debugName: "methodsDirty" }] : /* istanbul ignore next */ []);
|
|
3166
3401
|
orgOptions = computed(() => [{
|
|
3167
3402
|
value: "",
|
|
3168
3403
|
label: "-- ไม่ระบุ --"
|
|
@@ -3188,6 +3423,51 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
|
|
|
3188
3423
|
}
|
|
3189
3424
|
ngOnInit() {
|
|
3190
3425
|
this.load();
|
|
3426
|
+
this.http.get(`${this.config.apiBase}/user/login-methods`).subscribe({
|
|
3427
|
+
next: (m) => {
|
|
3428
|
+
const v = {
|
|
3429
|
+
password: m?.password !== false,
|
|
3430
|
+
sso: m?.sso !== false,
|
|
3431
|
+
thaid: m?.thaid !== false
|
|
3432
|
+
};
|
|
3433
|
+
this.methodsSaved.set(v);
|
|
3434
|
+
this.methodsDraft.set({ ...v });
|
|
3435
|
+
},
|
|
3436
|
+
error: () => {}
|
|
3437
|
+
});
|
|
3438
|
+
}
|
|
3439
|
+
toggleMethod(key, on) {
|
|
3440
|
+
const m = this.methodsDraft();
|
|
3441
|
+
if (!m) return;
|
|
3442
|
+
const next = {
|
|
3443
|
+
...m,
|
|
3444
|
+
[key]: on
|
|
3445
|
+
};
|
|
3446
|
+
if (!this.methodOptions().some((o) => next[o.key])) return;
|
|
3447
|
+
this.methodsError.set("");
|
|
3448
|
+
this.methodsDraft.set(next);
|
|
3449
|
+
}
|
|
3450
|
+
saveMethods() {
|
|
3451
|
+
const m = this.methodsDraft();
|
|
3452
|
+
if (!m || this.savingMethods()) return;
|
|
3453
|
+
if (!this.methodOptions().some((o) => m[o.key])) {
|
|
3454
|
+
this.methodsError.set("ต้องเปิดการเข้าสู่ระบบอย่างน้อย 1 วิธี");
|
|
3455
|
+
return;
|
|
3456
|
+
}
|
|
3457
|
+
this.savingMethods.set(true);
|
|
3458
|
+
this.http.put(`${this.config.apiBase}/config/login-methods`, m).subscribe({
|
|
3459
|
+
next: (res) => {
|
|
3460
|
+
this.savingMethods.set(false);
|
|
3461
|
+
this.methodsSaved.set({ ...m });
|
|
3462
|
+
this.methodsError.set("");
|
|
3463
|
+
this.error.set("");
|
|
3464
|
+
this.success.set(res?.message || "บันทึกวิธีเข้าสู่ระบบเรียบร้อยแล้ว");
|
|
3465
|
+
},
|
|
3466
|
+
error: (err) => {
|
|
3467
|
+
this.savingMethods.set(false);
|
|
3468
|
+
this.methodsError.set(kcErrorMessage(err, "บันทึกวิธีเข้าสู่ระบบไม่สำเร็จ"));
|
|
3469
|
+
}
|
|
3470
|
+
});
|
|
3191
3471
|
}
|
|
3192
3472
|
load() {
|
|
3193
3473
|
this.loading.set(true);
|
|
@@ -3286,6 +3566,30 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
|
|
|
3286
3566
|
<div class="kc-auth-alert success" role="status">{{ success() }}</div>
|
|
3287
3567
|
}
|
|
3288
3568
|
|
|
3569
|
+
@if (methodOptions().length > 1 && methodsDraft(); as m) {
|
|
3570
|
+
<div class="kc-auth-panel">
|
|
3571
|
+
<h2 class="kc-auth-panel-title">วิธีเข้าสู่ระบบ</h2>
|
|
3572
|
+
<div class="kc-auth-methods">
|
|
3573
|
+
@for (o of methodOptions(); track o.key) {
|
|
3574
|
+
<label class="kc-auth-check">
|
|
3575
|
+
<input type="checkbox" [checked]="m[o.key]" [disabled]="savingMethods() || (m[o.key] && enabledCount() === 1)"
|
|
3576
|
+
(change)="toggleMethod(o.key, $any($event.target).checked)" />
|
|
3577
|
+
{{ o.label }}
|
|
3578
|
+
</label>
|
|
3579
|
+
}
|
|
3580
|
+
<button type="button" class="kc-auth-btn primary" [disabled]="savingMethods() || !methodsDirty()" (click)="saveMethods()">
|
|
3581
|
+
{{ savingMethods() ? 'กำลังบันทึก...' : 'บันทึก' }}
|
|
3582
|
+
</button>
|
|
3583
|
+
</div>
|
|
3584
|
+
@if (methodsError()) {
|
|
3585
|
+
<div class="kc-auth-alert error" role="alert" style="margin: 10px 0 0">{{ methodsError() }}</div>
|
|
3586
|
+
}
|
|
3587
|
+
<p class="kc-auth-hint" style="margin: 10px 0 0">
|
|
3588
|
+
ต้องเปิดอย่างน้อย 1 วิธี — ก่อนปิดวิธีอื่น ให้ลองเข้าสู่ระบบด้วยวิธีที่จะเหลือให้ได้ก่อน มีผลกับการเข้าสู่ระบบครั้งถัดไป (ผู้ที่เข้าอยู่แล้วใช้งานต่อได้)
|
|
3589
|
+
</p>
|
|
3590
|
+
</div>
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3289
3593
|
<div class="kc-auth-panel">
|
|
3290
3594
|
<input class="kc-auth-input" type="search" [placeholder]="'ค้นหาชื่อผู้ใช้ ชื่อ-สกุล ' + config.orgLabel + ' ระดับผู้ใช้ หรืออีเมล'"
|
|
3291
3595
|
[ngModel]="search()" (ngModelChange)="search.set($event)" aria-label="ค้นหาผู้ใช้" />
|
|
@@ -3499,6 +3803,30 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
3499
3803
|
<div class="kc-auth-alert success" role="status">{{ success() }}</div>
|
|
3500
3804
|
}
|
|
3501
3805
|
|
|
3806
|
+
@if (methodOptions().length > 1 && methodsDraft(); as m) {
|
|
3807
|
+
<div class="kc-auth-panel">
|
|
3808
|
+
<h2 class="kc-auth-panel-title">วิธีเข้าสู่ระบบ</h2>
|
|
3809
|
+
<div class="kc-auth-methods">
|
|
3810
|
+
@for (o of methodOptions(); track o.key) {
|
|
3811
|
+
<label class="kc-auth-check">
|
|
3812
|
+
<input type="checkbox" [checked]="m[o.key]" [disabled]="savingMethods() || (m[o.key] && enabledCount() === 1)"
|
|
3813
|
+
(change)="toggleMethod(o.key, $any($event.target).checked)" />
|
|
3814
|
+
{{ o.label }}
|
|
3815
|
+
</label>
|
|
3816
|
+
}
|
|
3817
|
+
<button type="button" class="kc-auth-btn primary" [disabled]="savingMethods() || !methodsDirty()" (click)="saveMethods()">
|
|
3818
|
+
{{ savingMethods() ? 'กำลังบันทึก...' : 'บันทึก' }}
|
|
3819
|
+
</button>
|
|
3820
|
+
</div>
|
|
3821
|
+
@if (methodsError()) {
|
|
3822
|
+
<div class="kc-auth-alert error" role="alert" style="margin: 10px 0 0">{{ methodsError() }}</div>
|
|
3823
|
+
}
|
|
3824
|
+
<p class="kc-auth-hint" style="margin: 10px 0 0">
|
|
3825
|
+
ต้องเปิดอย่างน้อย 1 วิธี — ก่อนปิดวิธีอื่น ให้ลองเข้าสู่ระบบด้วยวิธีที่จะเหลือให้ได้ก่อน มีผลกับการเข้าสู่ระบบครั้งถัดไป (ผู้ที่เข้าอยู่แล้วใช้งานต่อได้)
|
|
3826
|
+
</p>
|
|
3827
|
+
</div>
|
|
3828
|
+
}
|
|
3829
|
+
|
|
3502
3830
|
<div class="kc-auth-panel">
|
|
3503
3831
|
<input class="kc-auth-input" type="search" [placeholder]="'ค้นหาชื่อผู้ใช้ ชื่อ-สกุล ' + config.orgLabel + ' ระดับผู้ใช้ หรืออีเมล'"
|
|
3504
3832
|
[ngModel]="search()" (ngModelChange)="search.set($event)" aria-label="ค้นหาผู้ใช้" />
|
|
@@ -4115,6 +4443,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4115
4443
|
}],
|
|
4116
4444
|
ctorParameters: () => []
|
|
4117
4445
|
});
|
|
4118
|
-
export { AnchoredPopup, ClockPickerDirective, ClockPickerPopupComponent, DatePickerDirective, DatePickerPopupComponent, KC_AUTH_CONFIG, KC_AUTH_PATHS, KC_RETURN_URL_KEY, KC_SSO_STATE_KEY, KC_SSO_TICKET_KEY, KcAuthService, KcConfigKclluComponent, KcConfigUsersComponent, KcLoginComponent, KcPasswordToggleComponent, KcProfileComponent, KcRegisterComponent, KcSsoCallbackComponent, PICKER_CSS, SearchSelectComponent, ThaiDatePickerComponent, ensurePickerStyles, fixThaiText, formatDate, kcAdminGuard, kcAuthGuard, kcAuthInterceptor, kcAuthRoutes, kcErrorMessage, kcTokenExpired, parseDate, provideKcAuth, provideThaiPasteFix, resolveKcAuthConfig, toBuddhistText, toChristianText };
|
|
4446
|
+
export { AnchoredPopup, ClockPickerDirective, ClockPickerPopupComponent, DatePickerDirective, DatePickerPopupComponent, KC_AUTH_CONFIG, KC_AUTH_PATHS, KC_LOGIN_LOCK_KEY, KC_LOGIN_LOCK_SECONDS, KC_RETURN_URL_KEY, KC_SSO_STATE_KEY, KC_SSO_TICKET_KEY, KC_THAID_STATE_KEY, KcAuthService, KcConfigKclluComponent, KcConfigUsersComponent, KcLoginComponent, KcPasswordToggleComponent, KcProfileComponent, KcRegisterComponent, KcSsoCallbackComponent, KcThaidCallbackComponent, PICKER_CSS, SearchSelectComponent, ThaiDatePickerComponent, ensurePickerStyles, fixThaiText, formatDate, kcAdminGuard, kcAuthGuard, kcAuthInterceptor, kcAuthRoutes, kcErrorMessage, kcLoginRetryAfter, kcTokenExpired, parseDate, provideKcAuth, provideThaiPasteFix, resolveKcAuthConfig, toBuddhistText, toChristianText };
|
|
4119
4447
|
|
|
4120
4448
|
//# sourceMappingURL=kengcom202-kcore-ui.mjs.map
|