@things-factory/auth-ui 10.1.259 → 10.1.261

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.
Files changed (44) hide show
  1. package/dist-client/pages/appliance/home.d.ts +0 -1
  2. package/dist-client/pages/appliance/home.js +5 -6
  3. package/dist-client/pages/appliance/home.js.map +1 -1
  4. package/dist-client/pages/application/applications.d.ts +0 -1
  5. package/dist-client/pages/application/applications.js +5 -6
  6. package/dist-client/pages/application/applications.js.map +1 -1
  7. package/dist-client/pages/audit/audit-page.d.ts +15 -14
  8. package/dist-client/pages/audit/audit-page.js +107 -139
  9. package/dist-client/pages/audit/audit-page.js.map +1 -1
  10. package/dist-client/pages/auth-provider/auth-provider-management.d.ts +9 -4
  11. package/dist-client/pages/auth-provider/auth-provider-management.js +29 -13
  12. package/dist-client/pages/auth-provider/auth-provider-management.js.map +1 -1
  13. package/dist-client/pages/domain-owner/domain-owner-management.js +2 -2
  14. package/dist-client/pages/domain-owner/domain-owner-management.js.map +1 -1
  15. package/dist-client/pages/list-address.test.d.ts +1 -0
  16. package/dist-client/pages/list-address.test.js +51 -0
  17. package/dist-client/pages/list-address.test.js.map +1 -0
  18. package/dist-client/pages/role/role-inheritance-shown.test.js +7 -6
  19. package/dist-client/pages/role/role-inheritance-shown.test.js.map +1 -1
  20. package/dist-client/pages/role/role-list-page.d.ts +20 -27
  21. package/dist-client/pages/role/role-list-page.js +49 -136
  22. package/dist-client/pages/role/role-list-page.js.map +1 -1
  23. package/dist-client/pages/user/user-list-page.d.ts +0 -1
  24. package/dist-client/pages/user/user-list-page.js +5 -6
  25. package/dist-client/pages/user/user-list-page.js.map +1 -1
  26. package/dist-client/tsconfig.tsbuildinfo +1 -1
  27. package/dist-client/utils/audit-words.d.ts +28 -0
  28. package/dist-client/utils/audit-words.js +36 -0
  29. package/dist-client/utils/audit-words.js.map +1 -1
  30. package/dist-client/utils/audit-words.test.js +33 -1
  31. package/dist-client/utils/audit-words.test.js.map +1 -1
  32. package/dist-client/utils/role-scope.d.ts +15 -0
  33. package/dist-client/utils/role-scope.js +13 -0
  34. package/dist-client/utils/role-scope.js.map +1 -0
  35. package/dist-client/utils/role-scope.test.d.ts +1 -0
  36. package/dist-client/utils/role-scope.test.js +18 -0
  37. package/dist-client/utils/role-scope.test.js.map +1 -0
  38. package/package.json +8 -7
  39. package/translations/en.json +1 -1
  40. package/translations/es.json +1 -1
  41. package/translations/ja.json +1 -1
  42. package/translations/ko.json +1 -1
  43. package/translations/ms.json +1 -1
  44. package/translations/zh.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"role-inheritance-shown.test.js","sourceRoot":"","sources":["../../../client/pages/role/role-inheritance-shown.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AACjC,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB;;;;GAIG;AAEH,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,EAAE,OAAO,CAAC,CAAA;AAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAA;AAEjF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAA;AACxG,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAA;AAE1G,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,kFAAkF,EAAE,GAAG,EAAE;QAC1F,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,6EAA6E,CAAC,CAAA;IACrG,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,qFAAqF,CAAC,CAAA;QAC7G,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAA;QACrE,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,wGAAwG,CAAC,CAAA;QACrI,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,uEAAuE,CAAC,CAAA;QACpG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IAC9D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,4DAA4D,CAAC,CAAA;IAC3F,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { readFileSync } from 'fs'\nimport path from 'path'\n\n/**\n * A domain that inherits from nowhere shows nothing about inheritance - no 「우리 역할 · 상속 · 전체」\n * buttons, no line about where roles come from, no source column (the user, 2026-10-28). The page\n * needs a DOM, so the test reads its source with comments stripped.\n */\n\nconst source = readFileSync(path.join(__dirname, 'role-list-page.ts'), 'utf-8')\nconst code = source.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '').replace(/^\\s*\\/\\/.*$/gm, '')\n\nconst scopes = code.slice(code.indexOf('private renderScopes('), code.indexOf('private renderLineage('))\nconst initialized = code.slice(code.indexOf('async pageInitialized('), code.indexOf('async pageUpdated('))\n\ndescribe('the role list in a domain with no parent', () => {\n it('★ inherits only when the profile names a parent - not knowing is not having none', () => {\n expect(code).toMatch(/private hasParent\\(\\): boolean \\{\\s*return this\\.parentDomain !== null\\s*\\}/)\n })\n\n it('★ draws no scope buttons, and so no lineage line', () => {\n expect(scopes).toMatch(/^private renderScopes\\(\\) \\{\\s*if \\(!this\\.hasParent\\(\\)\\) \\{\\s*return nothing\\s*\\}/)\n expect(code.match(/this\\.renderLineage\\(\\)/g)).toHaveLength(1)\n expect(scopes).toMatch(/this\\.renderLineage\\(\\)/)\n })\n\n it('★ leaves the source column and its list detail out', () => {\n expect(initialized).toMatch(/const inheriting = this\\.hasParent\\(\\)/)\n expect(initialized).toMatch(/details: inheriting \\? \\['privilegeCount', 'userCount', 'source'\\] : \\['privilegeCount', 'userCount'\\]/)\n expect(initialized).toMatch(/\\.\\.\\.\\(inheriting\\s*\\?\\s*\\[\\s*\\{\\s*type: 'string',\\s*name: 'source',/)\n expect(initialized.match(/name: 'source'/g)).toHaveLength(1)\n })\n\n it('counts the scopes only where there are scopes to count', () => {\n expect(initialized).toMatch(/if \\(this\\.hasParent\\(\\)\\) \\{\\s*this\\.countScopes\\(\\)\\s*\\}/)\n })\n})\n"]}
1
+ {"version":3,"file":"role-inheritance-shown.test.js","sourceRoot":"","sources":["../../../client/pages/role/role-inheritance-shown.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AACjC,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB;;;;GAIG;AAEH,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,EAAE,OAAO,CAAC,CAAA;AAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAA;AAEjF,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAA;AAC3G,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAA;AAErG,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,kFAAkF,EAAE,GAAG,EAAE;QAC1F,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,6EAA6E,CAAC,CAAA;IACrG,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,mHAAmH;QACnH,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,gDAAgD,CAAC,CAAA;QAC7E,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC9D,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,gEAAgE,CAAC,CAAA;IACxF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAA;QACrE,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,wGAAwG,CAAC,CAAA;QACrI,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,uEAAuE,CAAC,CAAA;QACpG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IAC9D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,qFAAqF,CAAC,CAAA;IACjH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { readFileSync } from 'fs'\nimport path from 'path'\n\n/**\n * A domain that inherits from nowhere shows nothing about inheritance - no 「우리 역할 · 상속 · 전체」\n * buttons, no line about where roles come from, no source column (the user, 2026-10-28). The page\n * needs a DOM, so the test reads its source with comments stripped.\n */\n\nconst source = readFileSync(path.join(__dirname, 'role-list-page.ts'), 'utf-8')\nconst code = source.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '').replace(/^\\s*\\/\\/.*$/gm, '')\n\nconst initialized = code.slice(code.indexOf('async pageInitialized('), code.indexOf('async fetchHandler('))\nconst counting = code.slice(code.indexOf('async countHandler('), code.indexOf('private renderNote('))\n\ndescribe('the role list in a domain with no parent', () => {\n it('★ inherits only when the profile names a parent - not knowing is not having none', () => {\n expect(code).toMatch(/private hasParent\\(\\): boolean \\{\\s*return this\\.parentDomain !== null\\s*\\}/)\n })\n\n it('★ draws no scope chips, and so no lineage line', () => {\n /* The chips are the grid's `inherited` filter (FOOTER-BUTTON-REVIEW G09): owned but not drawn without a parent. */\n expect(initialized).toMatch(/name: 'inherited',[\\s\\S]*?hidden: !inheriting,/)\n expect(code.match(/this\\.renderLineage\\(\\)/g)).toHaveLength(1)\n expect(code).toMatch(/\\$\\{this\\.hasParent\\(\\) \\? this\\.renderLineage\\(\\) : nothing\\}/)\n })\n\n it('★ leaves the source column and its list detail out', () => {\n expect(initialized).toMatch(/const inheriting = this\\.hasParent\\(\\)/)\n expect(initialized).toMatch(/details: inheriting \\? \\['privilegeCount', 'userCount', 'source'\\] : \\['privilegeCount', 'userCount'\\]/)\n expect(initialized).toMatch(/\\.\\.\\.\\(inheriting\\s*\\?\\s*\\[\\s*\\{\\s*type: 'string',\\s*name: 'source',/)\n expect(initialized.match(/name: 'source'/g)).toHaveLength(1)\n })\n\n it('counts the scopes only where there are scopes to count', () => {\n expect(counting).toMatch(/^async countHandler\\([^)]*\\) \\{\\s*if \\(!this\\.hasParent\\(\\)\\) \\{\\s*return \\{\\}\\s*\\}/)\n })\n})\n"]}
@@ -52,16 +52,6 @@ export declare class RoleListPage extends RoleListPageBase {
52
52
  * 셋을 가르는 이유는 화면이 「모른다」와 「없다」를 다르게 그려야 하기 때문이다.
53
53
  */
54
54
  private parentDomain;
55
- private scope;
56
- /**
57
- * 묶음마다 몇 건인가.
58
- *
59
- * 수를 함께 적는 이유는 **상속이 있다는 사실 자체가 보이게** 하는 것이다. 기본값을 「우리
60
- * 역할」로 좁혀 놓으면, 수가 없으면 상속 9건이 존재하는지조차 모른다.
61
- *
62
- * `undefined` 는 「아직 못 셌다」다 — 0 으로 메우면 「없다」와 같아 보인다.
63
- */
64
- private counts;
65
55
  private grist;
66
56
  /**
67
57
  * 저장과 삭제를 **툴바**에 둔다.
@@ -90,20 +80,19 @@ export declare class RoleListPage extends RoleListPageBase {
90
80
  handler: () => void;
91
81
  };
92
82
  actions: {
83
+ icon: string;
84
+ emphasis: {
85
+ raised: boolean;
86
+ outlined: boolean;
87
+ dense: boolean;
88
+ danger: boolean;
89
+ };
90
+ id: string;
93
91
  title: string;
94
92
  action: () => Promise<void>;
95
93
  }[];
96
94
  };
97
95
  render(): import("lit-html").TemplateResult<1>;
98
- /**
99
- * 세 묶음.
100
- *
101
- * **수를 함께 적는 것이 이 부품의 이유다.** 기본값을 「우리 역할」로 좁혀 두면 처음 화면이
102
- * 깨끗한 대신 **상속 9건이 있다는 사실이 사라진다.** 수가 그것을 되돌려 놓는다.
103
- *
104
- * 아직 못 센 묶음은 수를 **안 그린다** — 0 으로 메우면 「없다」와 같아 보인다.
105
- */
106
- private renderScopes;
107
96
  /**
108
97
  * 어디에서 물려받나 — **어느 도메인인지**를 적는다. 그 역할을 고치러 가야 할 곳이다.
109
98
  *
@@ -121,15 +110,20 @@ export declare class RoleListPage extends RoleListPageBase {
121
110
  * 「없다」로 접지 않는다.
122
111
  */
123
112
  private hasParent;
124
- private onScope;
125
113
  /**
126
- * 세 묶음의 건수.
114
+ * 세 묶음의 건수 — the grid's `countHandler`, beside each chip of the `inherited` filter.
127
115
  *
128
116
  * 세 번 묻는다. 한 번에 셋을 세는 질의가 서버에 없고, 각각 `total` 만 받으므로 가볍다
129
- * (UX 실측 158·566·684 bytes). 실패하면 **수를 안 그린다** — 틀린 수를 그리는 것보다
130
- * 없는 것이 낫다.
131
- */
132
- private countScopes;
117
+ * (UX 실측 158·566·684 bytes). 실패한 묶음은 **수를 안 그린다** — 틀린 수를 그리는 것보다
118
+ * 없는 것이 낫다. A domain with no parent has no 묶음 to count.
119
+ */
120
+ countHandler(_option: FetchOption): Promise<{
121
+ inherited?: undefined;
122
+ } | {
123
+ inherited: {
124
+ [x: string]: any;
125
+ };
126
+ }>;
133
127
  /**
134
128
  * 목록 위에 겹쳐 그린다 — 격자를 떼면 다시 읽을 길이 없어진다.
135
129
  *
@@ -154,7 +148,6 @@ export declare class RoleListPage extends RoleListPageBase {
154
148
  */
155
149
  private sourceCell;
156
150
  pageInitialized(): Promise<void>;
157
- pageUpdated(_changes: any, _lifecycle: any): Promise<void>;
158
151
  /**
159
152
  * 역할을 가져온다 — **권한 행은 받지 않는다.**
160
153
  *
@@ -172,7 +165,7 @@ export declare class RoleListPage extends RoleListPageBase {
172
165
  * `inherited` 는 화면이 고른 묶음을 그대로 넘긴다. 기본값이 「우리 역할」이라 처음 화면에
173
166
  * 못 고치는 행이 안 깔린다.
174
167
  */
175
- fetchHandler({ filters, page, limit, sortings }: FetchOption): Promise<{
168
+ fetchHandler({ filters: asked, page, limit, sortings }: FetchOption): Promise<{
176
169
  records: any;
177
170
  total: any;
178
171
  }>;
@@ -8,15 +8,16 @@ import gql from 'graphql-tag';
8
8
  import { css, html, nothing } from 'lit';
9
9
  import { customElement, property, query, state } from 'lit/decorators.js';
10
10
  import { client, gqlContext } from '@operato/graphql';
11
- import { openPopup } from '@operato/layout';
11
+ import { notify, openPopup } from '@operato/layout';
12
12
  import { OxPrompt } from '@operato/popup/ox-prompt.js';
13
13
  import { i18next, localize } from '@operato/i18n';
14
14
  import { p13n } from '@operato/p13n';
15
15
  import { InheritedValueType, navigate, PageView } from '@operato/shell';
16
- import { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
16
+ import { CommonButtonStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
17
17
  import { isMobileDevice } from '@operato/utils';
18
18
  import { getDomain } from '@things-factory/auth-base/dist-client';
19
19
  import { standsInheritedRefusal } from '../../utils/inherited-name-refusal.js';
20
+ import { roleQueryOf } from '../../utils/role-scope.js';
20
21
  /**
21
22
  * 역할 목록 — **보이는 것과 고칠 수 있는 것을 가른다.**
22
23
  *
@@ -69,25 +70,6 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
69
70
  * 셋을 가르는 이유는 화면이 「모른다」와 「없다」를 다르게 그려야 하기 때문이다.
70
71
  */
71
72
  this.parentDomain = undefined;
72
- /*
73
- * **어느 묶음을 보고 있나 — 기본값은 「우리 역할」이다.**
74
- *
75
- * 전에는 `Include` 로 열었다. 그러면 처음 화면에 **못 고치는 행 9개가 앞에 깔린다**
76
- * (UX 실측: miratek 2 · system 9). `None` 으로 열면 처음 화면이 2행이고 **그 2행이 전부
77
- * 고칠 수 있는 행**이다.
78
- *
79
- * 세 묶음은 서버에 이미 있다(`InheritedValueType`). 새로 만들 것이 없다.
80
- */
81
- this.scope = InheritedValueType.None;
82
- /**
83
- * 묶음마다 몇 건인가.
84
- *
85
- * 수를 함께 적는 이유는 **상속이 있다는 사실 자체가 보이게** 하는 것이다. 기본값을 「우리
86
- * 역할」로 좁혀 놓으면, 수가 없으면 상속 9건이 존재하는지조차 모른다.
87
- *
88
- * `undefined` 는 「아직 못 셌다」다 — 0 으로 메우면 「없다」와 같아 보인다.
89
- */
90
- this.counts = {};
91
73
  }
92
74
  static { this.styles = [
93
75
  /* The frame owns the page shell; the grist is the content it sizes (ADR-0060 decision 8). */
@@ -103,17 +85,6 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
103
85
  }
104
86
 
105
87
 
106
- /*
107
- ── 세 묶음 ────────────────────────────────────────────────────────────
108
- 고른 것은 면으로 말한다. 글자색만 바꾸면 야간에 안 보인다.
109
- */
110
- [scopes] {
111
- display: flex;
112
- align-items: center;
113
- gap: 4px;
114
- flex-wrap: wrap;
115
- }
116
-
117
88
  /*
118
89
  어디에서 물려받나 — 단추가 아니라 **사실을 적은 글**이다. 그래서 알약도 테두리도 없다.
119
90
  고르는 것과 읽는 것이 같은 모양이면 눌러 보게 된다.
@@ -126,40 +97,6 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
126
97
  color: var(--md-sys-color-on-surface-variant);
127
98
  }
128
99
 
129
- button[scope] {
130
- display: inline-flex;
131
- align-items: baseline;
132
- gap: 5px;
133
- padding: 5px 12px;
134
- font: var(--label-font, inherit);
135
- font-size: 0.82rem;
136
- color: var(--md-sys-color-on-surface-variant);
137
- background-color: transparent;
138
- border: 1px solid var(--md-sys-color-outline-variant);
139
- border-radius: var(--md-sys-shape-corner-full, 999px);
140
- cursor: pointer;
141
- white-space: nowrap;
142
- }
143
-
144
- button[scope]:hover {
145
- background-color: var(--md-sys-color-surface-variant);
146
- }
147
-
148
- button[scope][active] {
149
- color: var(--md-sys-color-on-secondary-container);
150
- background-color: var(--md-sys-color-secondary-container);
151
- border-color: var(--md-sys-color-secondary-container);
152
- }
153
-
154
- button[scope] [count] {
155
- font-size: 0.78rem;
156
- color: var(--md-sys-color-outline);
157
- }
158
-
159
- button[scope][active] [count] {
160
- color: var(--md-sys-color-on-secondary-container);
161
- }
162
-
163
100
  /*
164
101
  * 새 역할 단추 — **옆에 선 것들을 따라간다.**
165
102
  *
@@ -233,8 +170,9 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
233
170
  }
234
171
  },
235
172
  actions: [
236
- { title: i18next.t('button.save'), action: this.onSaveGrid.bind(this) },
237
- { title: i18next.t('button.delete'), action: this.onDeleteGrid.bind(this) }
173
+ /* Roles start in 「역할 추가」 above the list; here the rows are renamed and deleted. 저장 is the main action. */
174
+ { id: 'delete', title: i18next.t('button.delete'), action: this.onDeleteGrid.bind(this), ...CommonButtonStyles.delete },
175
+ { id: 'save', title: i18next.t('button.save'), action: this.onSaveGrid.bind(this), ...CommonButtonStyles.save }
238
176
  ]
239
177
  };
240
178
  }
@@ -245,14 +183,15 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
245
183
  .mode=${this.mode}
246
184
  .config=${this.config}
247
185
  .fetchHandler=${this.fetchHandler.bind(this)}
186
+ .countHandler=${this.countHandler.bind(this)}
248
187
  .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')}
188
+ ?url-params-sensitive=${this.active}
249
189
  >
250
190
  <div slot="headroom" class="header">
251
191
  <div class="filters">
252
- ${this.renderScopes()}
253
-
254
192
  <!-- 찾기는 제목 줄이 갖는다(context.search). 폼이 자기 검색칸을 또 그리면 둘이 된다. -->
255
193
  <ox-filters-form without-search></ox-filters-form>
194
+ ${this.hasParent() ? this.renderLineage() : nothing}
256
195
 
257
196
  <!--
258
197
  여기 ox-record-creator 가 있었다 — 목록에 빈 줄을 만들고 이름을 치게 하는
@@ -270,35 +209,6 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
270
209
  ${this.renderNote()}
271
210
  `;
272
211
  }
273
- /**
274
- * 세 묶음.
275
- *
276
- * **수를 함께 적는 것이 이 부품의 이유다.** 기본값을 「우리 역할」로 좁혀 두면 처음 화면이
277
- * 깨끗한 대신 **상속 9건이 있다는 사실이 사라진다.** 수가 그것을 되돌려 놓는다.
278
- *
279
- * 아직 못 센 묶음은 수를 **안 그린다** — 0 으로 메우면 「없다」와 같아 보인다.
280
- */
281
- renderScopes() {
282
- if (!this.hasParent()) {
283
- return nothing;
284
- }
285
- const scopes = [
286
- [InheritedValueType.None, 'label.ours'],
287
- [InheritedValueType.Only, 'label.inherited'],
288
- [InheritedValueType.Include, 'label.all']
289
- ];
290
- return html `
291
- <div scopes>
292
- ${scopes.map(([scope, key]) => html `
293
- <button scope ?active=${this.scope === scope} @click=${() => this.onScope(scope)}>
294
- ${i18next.t(key)}
295
- ${this.counts[scope] === undefined ? nothing : html `<span count>${this.counts[scope]}</span>`}
296
- </button>
297
- `)}
298
- ${this.renderLineage()}
299
- </div>
300
- `;
301
- }
302
212
  /**
303
213
  * 어디에서 물려받나 — **어느 도메인인지**를 적는다. 그 역할을 고치러 가야 할 곳이다.
304
214
  *
@@ -321,21 +231,17 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
321
231
  hasParent() {
322
232
  return this.parentDomain !== null;
323
233
  }
324
- onScope(scope) {
325
- if (this.scope === scope) {
326
- return;
327
- }
328
- this.scope = scope;
329
- this.grist.fetch();
330
- }
331
234
  /**
332
- * 세 묶음의 건수.
235
+ * 세 묶음의 건수 — the grid's `countHandler`, beside each chip of the `inherited` filter.
333
236
  *
334
237
  * 세 번 묻는다. 한 번에 셋을 세는 질의가 서버에 없고, 각각 `total` 만 받으므로 가볍다
335
- * (UX 실측 158·566·684 bytes). 실패하면 **수를 안 그린다** — 틀린 수를 그리는 것보다
336
- * 없는 것이 낫다.
238
+ * (UX 실측 158·566·684 bytes). 실패한 묶음은 **수를 안 그린다** — 틀린 수를 그리는 것보다
239
+ * 없는 것이 낫다. A domain with no parent has no 묶음 to count.
337
240
  */
338
- async countScopes() {
241
+ async countHandler(_option) {
242
+ if (!this.hasParent()) {
243
+ return {};
244
+ }
339
245
  const scopes = [InheritedValueType.None, InheritedValueType.Only, InheritedValueType.Include];
340
246
  const counted = await Promise.all(scopes.map(async (scope) => {
341
247
  const response = await client.query({
@@ -346,16 +252,14 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
346
252
  }
347
253
  }
348
254
  `,
349
- variables: { inherited: scope }
255
+ variables: { inherited: scope },
256
+ fetchPolicy: 'no-cache'
350
257
  });
351
258
  return [scope, response.errors?.length ? undefined : response.data?.roles?.total];
352
259
  }));
353
- this.counts = counted.reduce((counts, [scope, total]) => {
354
- if (total !== undefined) {
355
- counts[scope] = total;
356
- }
357
- return counts;
358
- }, {});
260
+ return {
261
+ inherited: counted.reduce((counts, [scope, total]) => (total === undefined ? counts : { ...counts, [scope]: total }), {})
262
+ };
359
263
  }
360
264
  /**
361
265
  * 목록 위에 겹쳐 그린다 — 격자를 떼면 다시 읽을 길이 없어진다.
@@ -424,9 +328,6 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
424
328
  * 안 적는다. 「모른다」를 「없다」로 접지 않는다.
425
329
  */
426
330
  this.parentDomain = mine && 'parent' in mine ? mine.parent : undefined;
427
- if (this.hasParent()) {
428
- this.countScopes();
429
- }
430
331
  const inheriting = this.hasParent();
431
332
  this.config = {
432
333
  /*
@@ -445,6 +346,29 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
445
346
  },
446
347
  columns: [
447
348
  { type: 'gutter', gutterName: 'sequence', fixed: true },
349
+ {
350
+ /*
351
+ * 세 묶음 — no column shows it, so a hidden one carries the filter: chips with each 묶음's count, 「우리 역할」 by
352
+ * default. A domain that inherits nothing draws no chips (`hidden`), as it draws no lineage or source column.
353
+ */
354
+ type: 'string',
355
+ name: 'inherited',
356
+ header: i18next.t('field.source'),
357
+ hidden: true,
358
+ record: { editable: false },
359
+ filter: {
360
+ type: 'select-buttons',
361
+ operator: 'eq',
362
+ label: '',
363
+ value: InheritedValueType.None,
364
+ hidden: !inheriting,
365
+ options: [
366
+ { value: InheritedValueType.None, display: i18next.t('label.ours') },
367
+ { value: InheritedValueType.Only, display: i18next.t('label.inherited') },
368
+ { value: InheritedValueType.Include, display: i18next.t('label.all') }
369
+ ]
370
+ }
371
+ },
448
372
  /* 지우기가 고른 행에 닿는다 — 고르는 칸이 없으면 「삭제」는 무엇을 지우는지 말할 수 없다. */
449
373
  { type: 'gutter', gutterName: 'row-selector', multiple: true, fixed: true },
450
374
  {
@@ -601,12 +525,7 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
601
525
  sorters: [{ name: 'name' }]
602
526
  };
603
527
  }
604
- async pageUpdated(_changes, _lifecycle) {
605
- if (this.active) {
606
- await this.updateComplete;
607
- this.grist.fetch();
608
- }
609
- }
528
+ /* No read on activation here: the list is bound to the address and reads itself whenever the page becomes active. */
610
529
  /**
611
530
  * 역할을 가져온다 — **권한 행은 받지 않는다.**
612
531
  *
@@ -624,7 +543,8 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
624
543
  * `inherited` 는 화면이 고른 묶음을 그대로 넘긴다. 기본값이 「우리 역할」이라 처음 화면에
625
544
  * 못 고치는 행이 안 깔린다.
626
545
  */
627
- async fetchHandler({ filters = [], page, limit, sortings = [] }) {
546
+ async fetchHandler({ filters: asked = [], page, limit, sortings = [] }) {
547
+ const { filters, inherited } = roleQueryOf(asked);
628
548
  this.fetchState = 'loading';
629
549
  this.filtered = filters.length > 0;
630
550
  try {
@@ -673,7 +593,7 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
673
593
  filters,
674
594
  pagination: { page, limit },
675
595
  sortings: sortings.length ? sortings : [{ name: 'name' }],
676
- inherited: this.scope
596
+ inherited: inherited
677
597
  }
678
598
  })).data.responses;
679
599
  this.total = response.total;
@@ -703,6 +623,7 @@ let RoleListPage = class RoleListPage extends RoleListPageBase {
703
623
  async onSaveGrid() {
704
624
  const dirty = this.grist.dirtyRecords;
705
625
  if (!dirty?.length) {
626
+ notify({ level: 'info', message: i18next.t('text.nothing-to-save') });
706
627
  return;
707
628
  }
708
629
  const patches = dirty.map((record) => {
@@ -984,14 +905,6 @@ __decorate([
984
905
  state(),
985
906
  __metadata("design:type", Object)
986
907
  ], RoleListPage.prototype, "parentDomain", void 0);
987
- __decorate([
988
- state(),
989
- __metadata("design:type", String)
990
- ], RoleListPage.prototype, "scope", void 0);
991
- __decorate([
992
- state(),
993
- __metadata("design:type", Object)
994
- ], RoleListPage.prototype, "counts", void 0);
995
908
  __decorate([
996
909
  query('ox-grist'),
997
910
  __metadata("design:type", Function)