@kengcom202/kcore-ui 0.5.0 → 0.7.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 CHANGED
@@ -8,7 +8,7 @@ Angular 22 UI กลาง — ไม่พึ่งไลบรารีภา
8
8
  - `<app-search-select>` — dropdown พิมพ์ค้นหาได้ ค่าเป็น `value` ของ `SearchOption` (`''` = ไม่ระบุ) ปรับสีด้วย `--kc-ss-*`
9
9
  - `provideThaiPasteFix()` — ใส่ใน `app.config.ts` ครั้งเดียว แก้ข้อความไทยที่คัดลอกจาก PDF (□ แทนวรรณยุกต์, ช่องว่างหน้าวรรณยุกต์, "ํา") ตอนวางลงทุกช่อง
10
10
  - หน้าบัญชีผู้ใช้กลาง — `provideKcAuth({...})` + `kcAuthInterceptor` + `kcAuthRoutes()` (`/login`, `/register`, `/sso-callback`, `/thaid-callback`) — ปุ่ม SSO (`sso`) และ ThaiD (`thaid` เข้าสู่ระบบอย่างเดียว)
11
- และ `<kc-profile>`, `<kc-config-users>`, `<kc-config-kcllu>` คู่กับ `kcAuthGuard` / `kcAdminGuard`, `KcAuthService` — API ต้องทำ endpoint ตามสัญญาใน README ของรีโป kcore
11
+ และ `<kc-profile>`, `<kc-config-users>`, `<kc-config-kcllu>` คู่กับ `kcAuthGuard` / `kcAdminGuard`, `KcAuthService` — API ต้องทำ endpoint ตามสัญญาใน `README_NPM.md` ของรีโป kcore
12
12
  - utils: `toBuddhistText`, `toChristianText`, `parseDate`, `formatDate`, `fixThaiText`
13
13
 
14
14
  ```ts
@@ -1,5 +1,5 @@
1
1
  import * as i0 from "@angular/core";
2
- import { ApplicationRef, CSP_NONCE, Component, DOCUMENT, DestroyRef, Directive, ElementRef, EnvironmentInjector, Injectable, InjectionToken, NgZone, ViewChild, ViewEncapsulation, computed, createComponent, forwardRef, inject, input, makeEnvironmentProviders, provideEnvironmentInitializer, signal } from "@angular/core";
2
+ import { ApplicationRef, CSP_NONCE, Component, DOCUMENT, DestroyRef, Directive, ElementRef, EnvironmentInjector, Injectable, InjectionToken, NgZone, ViewChild, ViewEncapsulation, computed, createComponent, effect, forwardRef, inject, input, makeEnvironmentProviders, provideEnvironmentInitializer, signal, untracked } from "@angular/core";
3
3
  import * as i1 from "@angular/forms";
4
4
  import { FormBuilder, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, Validators } from "@angular/forms";
5
5
  import { HttpClient, HttpErrorResponse } from "@angular/common/http";
@@ -1409,6 +1409,7 @@ function resolveKcAuthConfig(o) {
1409
1409
  thaid: o.thaid ? { label: o.thaid.label || "ThaiD" } : null,
1410
1410
  passwordLogin: o.passwordLogin !== false || !o.sso && !o.thaid,
1411
1411
  register: o.register ?? "none",
1412
+ profileOrgChange: o.profileOrgChange === true,
1412
1413
  orgLabel: o.orgLabel || "หน่วยงาน",
1413
1414
  adminRoles: o.adminRoles ?? ["admin"],
1414
1415
  passwordMinLength: o.passwordMinLength ?? 4,
@@ -1609,6 +1610,8 @@ const kcAuthInterceptor = (req, next) => {
1609
1610
  const STYLE_ID = "kcore-auth-styles";
1610
1611
  const AUTH_CSS = `
1611
1612
  .kc-auth-screen, .kc-auth-page, .kc-auth-modal-bg {
1613
+ /* ค่าเริ่มต้นใช้ฟอนต์ของเว็บ — เว็บที่ body ใช้ฟอนต์เฉพาะทาง (เช่น TH Sarabun ของหน้าพิมพ์) ตั้งฟอนต์ของหน้าชุดนี้แยกได้ */
1614
+ font-family: var(--kc-auth-font-family, inherit);
1612
1615
  font-size: var(--kc-auth-font-size, 14px);
1613
1616
  color: var(--kc-auth-text, #3a2a3a);
1614
1617
  line-height: 1.5;
@@ -1617,6 +1620,8 @@ const AUTH_CSS = `
1617
1620
 
1618
1621
  /* ---- หน้าเต็มจอ (login / register / sso-callback) ---- */
1619
1622
  .kc-auth-screen {
1623
+ /* border-box: padding อยู่ใน 100vh — ไม่งั้นสูงเกินจอ 48px และมี scrollbar ทั้งที่เนื้อหาน้อย */
1624
+ box-sizing: border-box;
1620
1625
  min-height: 100vh;
1621
1626
  display: flex;
1622
1627
  align-items: center;
@@ -1626,16 +1631,23 @@ const AUTH_CSS = `
1626
1631
  }
1627
1632
  .kc-auth-card {
1628
1633
  width: 100%;
1629
- max-width: 380px;
1630
- padding: 28px 28px 24px;
1634
+ max-width: var(--kc-auth-card-width, 380px);
1635
+ /* ขนาดกรอบของหน้าเต็มจอปรับได้ เช่น สูง 80vh แล้วขยายตัวอักษร/ช่องกรอก/โลโก้ตามความสูงจอ — ค่าเริ่มต้น = ขนาดเดิม */
1636
+ min-height: var(--kc-auth-card-height, auto);
1637
+ display: flex;
1638
+ flex-direction: column;
1639
+ justify-content: center;
1640
+ padding: var(--kc-auth-card-padding, 28px 28px 24px);
1641
+ font-size: var(--kc-auth-card-font-size, inherit);
1631
1642
  background: var(--kc-auth-bg, #fff);
1632
1643
  border: 1px solid var(--kc-auth-border, #f3e1f3);
1633
1644
  border-radius: var(--kc-auth-radius, 14px);
1634
1645
  box-shadow: 0 12px 36px rgba(204, 102, 204, 0.12);
1635
1646
  }
1636
- .kc-auth-card.wide { max-width: 560px; }
1647
+ .kc-auth-card.wide { max-width: var(--kc-auth-card-wide-width, 560px); }
1637
1648
  .kc-auth-card.center { text-align: center; }
1638
- .kc-auth-logo { display: block; max-height: 72px; max-width: 100%; margin: 0 auto 12px; }
1649
+ .kc-auth-card .kc-auth-input, .kc-auth-card .kc-auth-btn { height: var(--kc-auth-card-input-height, var(--kc-auth-input-height, 40px)); }
1650
+ .kc-auth-logo { display: block; max-height: var(--kc-auth-logo-height, 72px); max-width: 100%; margin: 0 auto 12px; }
1639
1651
  .kc-auth-title { margin: 0; font-size: 1.35em; font-weight: 600; text-align: center; }
1640
1652
  .kc-auth-subtitle { margin: 4px 0 20px; color: var(--kc-auth-muted, #806f80); text-align: center; }
1641
1653
  .kc-auth-footer { margin: 18px 0 0; text-align: center; color: var(--kc-auth-muted, #806f80); font-size: 0.93em; }
@@ -1698,6 +1710,8 @@ const AUTH_CSS = `
1698
1710
  .kc-auth-pw > .kc-auth-input { padding-right: 42px; }
1699
1711
  .kc-auth-pw > input::-ms-reveal, .kc-auth-pw > input::-ms-clear { display: none; }
1700
1712
  .kc-auth-pw-toggle {
1713
+ /* <button> ไม่รับขนาดตัวอักษรจากแม่ (browser ตั้ง ~13px) — ต้อง inherit ไม่งั้นขนาด em ของไอคอนไม่ขยายตามกรอบ */
1714
+ font: inherit;
1701
1715
  position: absolute;
1702
1716
  top: 50%;
1703
1717
  right: 5px;
@@ -1726,6 +1740,20 @@ const AUTH_CSS = `
1726
1740
  --kc-ss-border: var(--kc-auth-input-border, #e9cde9);
1727
1741
  --kc-ss-text: var(--kc-auth-text, #3a2a3a);
1728
1742
  }
1743
+ .kc-auth-card .kc-auth-field .kc-ss { --kc-ss-height: var(--kc-auth-card-input-height, var(--kc-auth-input-height, 40px)); }
1744
+ /* ในกรอบหน้าเต็มจอ ขนาดย่อยทั้งหมดเป็น em ของตัวอักษรในกรอบ (= px เดิมที่ 14px) — ตั้ง --kc-auth-card-font-size
1745
+ แล้วไอคอน ระยะห่าง และ padding ขยาย/หดตามสัดส่วนเดียวกัน */
1746
+ .kc-auth-card .kc-auth-logo { margin-bottom: 0.86em; }
1747
+ .kc-auth-card .kc-auth-subtitle { margin: 0.3em 0 1.43em; }
1748
+ .kc-auth-card .kc-auth-footer { margin-top: 1.3em; }
1749
+ .kc-auth-card .kc-auth-field { gap: 0.3em; margin-bottom: 0.86em; }
1750
+ .kc-auth-card .kc-auth-input { padding: 0 0.72em; border-radius: 0.57em; }
1751
+ .kc-auth-card .kc-auth-pw > .kc-auth-input { padding-right: 3em; }
1752
+ .kc-auth-card .kc-auth-pw-toggle { right: 0.36em; width: 2.3em; height: 2.3em; border-radius: 0.43em; }
1753
+ .kc-auth-card .kc-auth-pw-toggle svg { width: 1.36em; height: 1.36em; }
1754
+ .kc-auth-card .kc-auth-btn { padding: 0 1.15em; border-radius: 0.57em; gap: 0.43em; }
1755
+ .kc-auth-card .kc-auth-btn-row { gap: 0.72em; margin-top: 0.43em; }
1756
+ .kc-auth-card .kc-auth-alert { padding: 0.72em 0.86em; margin-bottom: 1em; border-radius: 0.43em; }
1729
1757
  .kc-auth-value { padding: 8px 0; }
1730
1758
  .kc-auth-field-error { color: var(--kc-auth-danger, #c62828); font-size: 0.86em; }
1731
1759
  .kc-auth-hint { margin: 2px 0 0; color: var(--kc-auth-muted, #806f80); font-size: 0.86em; }
@@ -1776,6 +1804,7 @@ const AUTH_CSS = `
1776
1804
  /* ปิดรหัสผ่าน: ปุ่ม SSO ปุ่มเดียวตรงกลาง */
1777
1805
  .kc-auth-sso-only { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 8px 0 4px; }
1778
1806
  .kc-auth-sso-only > .kc-auth-btn { min-width: 75%; height: 46px; padding: 0 24px; font-size: 1.05em; }
1807
+ .kc-auth-card .kc-auth-sso-only > .kc-auth-btn { height: calc(var(--kc-auth-card-input-height, var(--kc-auth-input-height, 40px)) * 1.15); padding: 0 1.7em; }
1779
1808
  .kc-auth-btn.block { display: flex; width: 100%; }
1780
1809
  .kc-auth-btn.sm { height: 30px; padding: 0 10px; font-size: 0.93em; }
1781
1810
  .kc-auth-link { color: var(--kc-auth-accent, #a23ea2); text-decoration: none; cursor: pointer; }
@@ -2229,6 +2258,8 @@ var KcLoginComponent = class KcLoginComponent {
2229
2258
  <p class="kc-auth-footer">ยังไม่มีบัญชี? <a class="kc-auth-link" [routerLink]="paths.register">ลงทะเบียน</a></p>
2230
2259
  } @else if (config.register === 'sso' && config.sso && methods().sso) {
2231
2260
  <p class="kc-auth-footer">ผู้ใช้ใหม่ กดปุ่ม {{ config.sso.label }} เพื่อลงทะเบียน</p>
2261
+ } @else if (config.register === 'thaid' && config.thaid && methods().thaid) {
2262
+ <p class="kc-auth-footer">ผู้ใช้ใหม่ กดปุ่ม {{ config.thaid.label }} เพื่อลงทะเบียน</p>
2232
2263
  }
2233
2264
  <ng-content />
2234
2265
  </div>
@@ -2377,6 +2408,8 @@ i0.ɵɵngDeclareClassMetadata({
2377
2408
  <p class="kc-auth-footer">ยังไม่มีบัญชี? <a class="kc-auth-link" [routerLink]="paths.register">ลงทะเบียน</a></p>
2378
2409
  } @else if (config.register === 'sso' && config.sso && methods().sso) {
2379
2410
  <p class="kc-auth-footer">ผู้ใช้ใหม่ กดปุ่ม {{ config.sso.label }} เพื่อลงทะเบียน</p>
2411
+ } @else if (config.register === 'thaid' && config.thaid && methods().thaid) {
2412
+ <p class="kc-auth-footer">ผู้ใช้ใหม่ กดปุ่ม {{ config.thaid.label }} เพื่อลงทะเบียน</p>
2380
2413
  }
2381
2414
  <ng-content />
2382
2415
  </div>
@@ -2409,7 +2442,7 @@ function kcContactProblem(email, mobile) {
2409
2442
  var KcRegisterComponent = class KcRegisterComponent {
2410
2443
  config = inject(KC_AUTH_CONFIG);
2411
2444
  paths = KC_AUTH_PATHS;
2412
- ssoLabel = this.config.sso?.label ?? "SSO";
2445
+ ssoLabel = this.config.register === "thaid" ? this.config.thaid?.label ?? "ThaiD" : this.config.sso?.label ?? "SSO";
2413
2446
  auth = inject(KcAuthService);
2414
2447
  http = inject(HttpClient);
2415
2448
  router = inject(Router);
@@ -2442,7 +2475,7 @@ var KcRegisterComponent = class KcRegisterComponent {
2442
2475
  this.error.set("ระบบนี้ไม่เปิดให้ลงทะเบียนเอง กรุณาติดต่อผู้ดูแลระบบ");
2443
2476
  return;
2444
2477
  }
2445
- if (mode === "sso") {
2478
+ if (mode === "sso" || mode === "thaid") {
2446
2479
  this.ticket = this.auth.getTemp(KC_SSO_TICKET_KEY);
2447
2480
  if (!this.ticket) {
2448
2481
  this.error.set(`ยังไม่ได้ยืนยันตัวตน กรุณากลับไปกด "เข้าสู่ระบบด้วย ${this.ssoLabel}" ที่หน้าเข้าสู่ระบบก่อน`);
@@ -2830,13 +2863,7 @@ var KcExternalCallbackBase = class KcExternalCallbackBase {
2830
2863
  }
2831
2864
  if (!code) {
2832
2865
  this.message.set(`กำลังเชื่อมต่อกับ ${this.label}...`);
2833
- this.http.get(`${this.config.apiBase}/user/${this.endpoint}/authorize-url`).subscribe({
2834
- next: ({ url, state }) => {
2835
- this.auth.setTemp(this.stateKey, state);
2836
- this.auth.redirect(url);
2837
- },
2838
- error: () => this.fail(`ไม่สามารถเชื่อมต่อ ${this.label} ได้ กรุณาเริ่มเข้าสู่ระบบใหม่`)
2839
- });
2866
+ this.startFlow(this.endpoint, this.stateKey, this.label);
2840
2867
  return;
2841
2868
  }
2842
2869
  if (!expectedState || expectedState !== params.get("state")) {
@@ -2845,6 +2872,20 @@ var KcExternalCallbackBase = class KcExternalCallbackBase {
2845
2872
  }
2846
2873
  this.exchange(code);
2847
2874
  }
2875
+ startFlow(endpoint, stateKey, label) {
2876
+ this.http.get(`${this.config.apiBase}/user/${endpoint}/authorize-url`).subscribe({
2877
+ next: ({ url, state }) => {
2878
+ this.auth.setTemp(stateKey, state);
2879
+ this.auth.redirect(url);
2880
+ },
2881
+ error: () => this.fail(`ไม่สามารถเชื่อมต่อ ${label} ได้ กรุณาเริ่มเข้าสู่ระบบใหม่`)
2882
+ });
2883
+ }
2884
+ toRegister(ticket) {
2885
+ this.auth.setTemp(KC_SSO_TICKET_KEY, ticket);
2886
+ this.message.set("ยังไม่มีบัญชีในระบบ กำลังไปหน้าลงทะเบียน...");
2887
+ this.router.navigateByUrl(KC_AUTH_PATHS.register, { replaceUrl: true });
2888
+ }
2848
2889
  signIn(session) {
2849
2890
  this.auth.start(session);
2850
2891
  this.router.navigateByUrl(this.auth.safeReturnUrl(this.auth.takeTemp(KC_RETURN_URL_KEY)), { replaceUrl: true });
@@ -2892,9 +2933,13 @@ var KcSsoCallbackComponent = class KcSsoCallbackComponent extends KcExternalCall
2892
2933
  return;
2893
2934
  }
2894
2935
  if (res.mode === "register" && res.ticket) {
2895
- this.auth.setTemp(KC_SSO_TICKET_KEY, res.ticket);
2896
- this.message.set("ยังไม่มีบัญชีในระบบ กำลังไปหน้าลงทะเบียน...");
2897
- this.router.navigateByUrl(KC_AUTH_PATHS.register, { replaceUrl: true });
2936
+ this.toRegister(res.ticket);
2937
+ return;
2938
+ }
2939
+ if (res.mode === "thaid" && this.config.register === "thaid" && this.config.thaid) {
2940
+ const thaid = this.config.thaid.label;
2941
+ this.message.set(`ไม่พบบัญชีผู้ใช้ในระบบ กำลังไปยืนยันตัวตนด้วย ${thaid} เพื่อลงทะเบียน...`);
2942
+ this.startFlow("thaid", KC_THAID_STATE_KEY, thaid);
2898
2943
  return;
2899
2944
  }
2900
2945
  this.fail("ไม่สามารถเข้าสู่ระบบได้ กรุณาลองใหม่อีกครั้ง");
@@ -2962,7 +3007,17 @@ var KcThaidCallbackComponent = class KcThaidCallbackComponent extends KcExternal
2962
3007
  stateKey = KC_THAID_STATE_KEY;
2963
3008
  exchange(code) {
2964
3009
  this.http.post(`${this.config.apiBase}/user/thaid/callback`, { code }).subscribe({
2965
- next: (res) => res?.token && res.user ? this.signIn(res) : this.fail("ไม่สามารถเข้าสู่ระบบได้ กรุณาลองใหม่อีกครั้ง"),
3010
+ next: (res) => {
3011
+ if (res && "token" in res && res.token && res.user) {
3012
+ this.signIn(res);
3013
+ return;
3014
+ }
3015
+ if (res && "mode" in res && res.mode === "register" && res.ticket && this.config.register === "thaid") {
3016
+ this.toRegister(res.ticket);
3017
+ return;
3018
+ }
3019
+ this.fail("ไม่สามารถเข้าสู่ระบบได้ กรุณาลองใหม่อีกครั้ง");
3020
+ },
2966
3021
  error: (err) => this.fail(kcErrorMessage(err, `ไม่สามารถเข้าสู่ระบบผ่าน ${this.label} ได้`))
2967
3022
  });
2968
3023
  }
@@ -3055,10 +3110,12 @@ var KcProfileComponent = class KcProfileComponent {
3055
3110
  success = signal("", ...ngDevMode ? [{ debugName: "success" }] : /* istanbul ignore next */ []);
3056
3111
  fullName = signal("", ...ngDevMode ? [{ debugName: "fullName" }] : /* istanbul ignore next */ []);
3057
3112
  orgName = signal("", ...ngDevMode ? [{ debugName: "orgName" }] : /* istanbul ignore next */ []);
3113
+ orgs = signal([], ...ngDevMode ? [{ debugName: "orgs" }] : /* istanbul ignore next */ []);
3058
3114
  form = inject(FormBuilder).nonNullable.group({
3059
3115
  email: ["", [Validators.required, Validators.email]],
3060
3116
  mobile: ["", [Validators.required, Validators.pattern(/^0\d{9}$/)]],
3061
3117
  username: ["", [Validators.required, Validators.pattern(/^\S+$/)]],
3118
+ org: [""],
3062
3119
  password: [""],
3063
3120
  confirmPassword: [""]
3064
3121
  });
@@ -3070,10 +3127,12 @@ var KcProfileComponent = class KcProfileComponent {
3070
3127
  next: (me) => {
3071
3128
  this.fullName.set(me.fullName);
3072
3129
  this.orgName.set(me.orgName || me.org);
3130
+ if (this.config.profileOrgChange && me.orgs?.length) this.orgs.set(me.orgs);
3073
3131
  this.form.patchValue({
3074
3132
  email: me.email ?? "",
3075
3133
  mobile: me.mobile ?? "",
3076
- username: me.username ?? ""
3134
+ username: me.username ?? "",
3135
+ org: me.org ?? ""
3077
3136
  });
3078
3137
  this.loading.set(false);
3079
3138
  },
@@ -3093,7 +3152,7 @@ var KcProfileComponent = class KcProfileComponent {
3093
3152
  this.success.set("");
3094
3153
  this.form.markAllAsTouched();
3095
3154
  const v = this.form.getRawValue();
3096
- const problem = kcContactProblem(v.email, v.mobile) || kcUsernameProblem(v.username) || kcPasswordProblem(v.password, v.confirmPassword, this.config.passwordMinLength, false);
3155
+ const problem = kcContactProblem(v.email, v.mobile) || kcUsernameProblem(v.username) || kcPasswordProblem(v.password, v.confirmPassword, this.config.passwordMinLength, false) || (this.orgs().length && !v.org ? `กรุณาเลือก${this.config.orgLabel}ที่สังกัด` : "");
3097
3156
  this.error.set(problem);
3098
3157
  if (problem) return;
3099
3158
  const body = {
@@ -3102,6 +3161,7 @@ var KcProfileComponent = class KcProfileComponent {
3102
3161
  mobile: v.mobile.trim(),
3103
3162
  password: v.password
3104
3163
  };
3164
+ if (this.orgs().length) body.org = v.org;
3105
3165
  this.saving.set(true);
3106
3166
  this.http.put(`${this.config.apiBase}/user/me`, body).subscribe({
3107
3167
  next: (res) => {
@@ -3150,11 +3210,19 @@ var KcProfileComponent = class KcProfileComponent {
3150
3210
  <input class="kc-auth-input" type="text" [value]="fullName()" disabled />
3151
3211
  </label>
3152
3212
 
3213
+ @if (orgs().length) {
3214
+ <div class="kc-auth-field">
3215
+ <label class="kc-auth-label" for="kc-profile-org">{{ config.orgLabel }}ที่สังกัด <span class="req">*</span></label>
3216
+ <app-search-select inputId="kc-profile-org" [options]="orgs()" formControlName="org"
3217
+ [placeholder]="'-- เลือก' + config.orgLabel + 'ที่สังกัด --'" />
3218
+ </div>
3219
+ } @else {
3153
3220
  <label class="kc-auth-field">
3154
3221
  <span>{{ config.orgLabel }}ที่สังกัด</span>
3155
3222
  <input class="kc-auth-input" type="text" [value]="orgName()" disabled />
3156
3223
  <small class="kc-auth-hint">หากต้องการย้าย{{ config.orgLabel }} กรุณาติดต่อผู้ดูแลระบบ</small>
3157
3224
  </label>
3225
+ }
3158
3226
 
3159
3227
  <label class="kc-auth-field">
3160
3228
  <span>อีเมล <span class="req">*</span></span>
@@ -3259,6 +3327,17 @@ var KcProfileComponent = class KcProfileComponent {
3259
3327
  ],
3260
3328
  outputs: ["ngModelChange"]
3261
3329
  },
3330
+ {
3331
+ kind: "component",
3332
+ type: SearchSelectComponent,
3333
+ selector: "app-search-select",
3334
+ inputs: [
3335
+ "options",
3336
+ "placeholder",
3337
+ "searchHint",
3338
+ "inputId"
3339
+ ]
3340
+ },
3262
3341
  {
3263
3342
  kind: "component",
3264
3343
  type: KcPasswordToggleComponent,
@@ -3277,7 +3356,11 @@ i0.ɵɵngDeclareClassMetadata({
3277
3356
  args: [{
3278
3357
  selector: "kc-profile",
3279
3358
  standalone: true,
3280
- imports: [ReactiveFormsModule, KcPasswordToggleComponent],
3359
+ imports: [
3360
+ ReactiveFormsModule,
3361
+ SearchSelectComponent,
3362
+ KcPasswordToggleComponent
3363
+ ],
3281
3364
  template: `
3282
3365
  <div class="kc-auth-page single">
3283
3366
  <div class="kc-auth-panel">
@@ -3294,11 +3377,19 @@ i0.ɵɵngDeclareClassMetadata({
3294
3377
  <input class="kc-auth-input" type="text" [value]="fullName()" disabled />
3295
3378
  </label>
3296
3379
 
3380
+ @if (orgs().length) {
3381
+ <div class="kc-auth-field">
3382
+ <label class="kc-auth-label" for="kc-profile-org">{{ config.orgLabel }}ที่สังกัด <span class="req">*</span></label>
3383
+ <app-search-select inputId="kc-profile-org" [options]="orgs()" formControlName="org"
3384
+ [placeholder]="'-- เลือก' + config.orgLabel + 'ที่สังกัด --'" />
3385
+ </div>
3386
+ } @else {
3297
3387
  <label class="kc-auth-field">
3298
3388
  <span>{{ config.orgLabel }}ที่สังกัด</span>
3299
3389
  <input class="kc-auth-input" type="text" [value]="orgName()" disabled />
3300
3390
  <small class="kc-auth-hint">หากต้องการย้าย{{ config.orgLabel }} กรุณาติดต่อผู้ดูแลระบบ</small>
3301
3391
  </label>
3392
+ }
3302
3393
 
3303
3394
  <label class="kc-auth-field">
3304
3395
  <span>อีเมล <span class="req">*</span></span>
@@ -3360,6 +3451,7 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
3360
3451
  config = inject(KC_AUTH_CONFIG);
3361
3452
  auth = inject(KcAuthService);
3362
3453
  http = inject(HttpClient);
3454
+ org = input("", ...ngDevMode ? [{ debugName: "org" }] : /* istanbul ignore next */ []);
3363
3455
  users = signal([], ...ngDevMode ? [{ debugName: "users" }] : /* istanbul ignore next */ []);
3364
3456
  orgs = signal([], ...ngDevMode ? [{ debugName: "orgs" }] : /* istanbul ignore next */ []);
3365
3457
  roles = signal([], ...ngDevMode ? [{ debugName: "roles" }] : /* istanbul ignore next */ []);
@@ -3420,9 +3512,12 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
3420
3512
  }, ...ngDevMode ? [{ debugName: "filtered" }] : /* istanbul ignore next */ []);
3421
3513
  constructor() {
3422
3514
  ensureAuthStyles();
3515
+ effect(() => {
3516
+ this.org();
3517
+ untracked(() => this.load());
3518
+ });
3423
3519
  }
3424
3520
  ngOnInit() {
3425
- this.load();
3426
3521
  this.http.get(`${this.config.apiBase}/user/login-methods`).subscribe({
3427
3522
  next: (m) => {
3428
3523
  const v = {
@@ -3471,7 +3566,9 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
3471
3566
  }
3472
3567
  load() {
3473
3568
  this.loading.set(true);
3474
- this.http.get(`${this.config.apiBase}/config/users`).subscribe({
3569
+ const org = this.org();
3570
+ const params = org ? { org } : {};
3571
+ this.http.get(`${this.config.apiBase}/config/users`, { params }).subscribe({
3475
3572
  next: (res) => {
3476
3573
  this.users.set(res.users ?? []);
3477
3574
  this.orgs.set(res.orgs ?? []);
@@ -3548,6 +3645,13 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
3548
3645
  type: KcConfigUsersComponent,
3549
3646
  isStandalone: true,
3550
3647
  selector: "kc-config-users",
3648
+ inputs: { org: {
3649
+ classPropertyName: "org",
3650
+ publicName: "org",
3651
+ isSignal: true,
3652
+ isRequired: false,
3653
+ transformFunction: null
3654
+ } },
3551
3655
  host: { listeners: { "document:keydown.escape": "close()" } },
3552
3656
  ngImport: i0,
3553
3657
  template: `
@@ -3938,7 +4042,15 @@ i0.ɵɵngDeclareClassMetadata({
3938
4042
  `
3939
4043
  }]
3940
4044
  }],
3941
- ctorParameters: () => []
4045
+ ctorParameters: () => [],
4046
+ propDecorators: { org: [{
4047
+ type: i0.Input,
4048
+ args: [{
4049
+ isSignal: true,
4050
+ alias: "org",
4051
+ required: false
4052
+ }]
4053
+ }] }
3942
4054
  });
3943
4055
  var KcConfigKclluComponent = class KcConfigKclluComponent {
3944
4056
  config = inject(KC_AUTH_CONFIG);