@things-factory/auth-ui 10.1.6 → 10.1.7
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/dist-client/components/role-privilege-picker.d.ts +37 -0
- package/dist-client/components/role-privilege-picker.js +58 -0
- package/dist-client/components/role-privilege-picker.js.map +1 -0
- package/dist-client/components/role-template-picker.d.ts +83 -0
- package/dist-client/components/role-template-picker.js +487 -0
- package/dist-client/components/role-template-picker.js.map +1 -0
- package/dist-client/pages/role/role-list-page.d.ts +104 -13
- package/dist-client/pages/role/role-list-page.js +396 -72
- package/dist-client/pages/role/role-list-page.js.map +1 -1
- package/dist-client/pages/role/role-privilege-page.d.ts +95 -37
- package/dist-client/pages/role/role-privilege-page.js +305 -126
- package/dist-client/pages/role/role-privilege-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/translations/en.json +27 -1
- package/translations/ja.json +14 -1
- package/translations/ko.json +26 -0
- package/translations/ms.json +15 -2
- package/translations/zh.json +14 -1
- package/dist-client/components/create-role.d.ts +0 -1
- package/dist-client/components/create-role.js +0 -117
- package/dist-client/components/create-role.js.map +0 -1
- package/dist-client/components/credential-manager.d.ts +0 -11
- package/dist-client/components/credential-manager.js +0 -64
- package/dist-client/components/credential-manager.js.map +0 -1
- package/dist-client/components/role-detail.d.ts +0 -144
- package/dist-client/components/role-detail.js +0 -698
- package/dist-client/components/role-detail.js.map +0 -1
- package/dist-client/components/role-edit-form.d.ts +0 -1
- package/dist-client/components/role-edit-form.js +0 -95
- package/dist-client/components/role-edit-form.js.map +0 -1
- package/dist-client/components/role-privilege-editor.d.ts +0 -1
- package/dist-client/components/role-privilege-editor.js +0 -368
- package/dist-client/components/role-privilege-editor.js.map +0 -1
- package/dist-client/pages/role/role-management.d.ts +0 -4
- package/dist-client/pages/role/role-management.js +0 -137
- package/dist-client/pages/role/role-management.js.map +0 -1
- package/dist-client/pages/user/user-management.d.ts +0 -35
- package/dist-client/pages/user/user-management.js +0 -223
- package/dist-client/pages/user/user-management.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-template-picker.js","sourceRoot":"","sources":["../../client/components/role-template-picker.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport type { CSSResultGroup } from 'lit'\n\nimport { client, gqlContext } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { CommonHeaderStyles, FormFieldStyles, ScrollbarStyles } from '@operato/styles'\n\ntype GrantView = { category: string; axes: string[]; missingAxes: string[] }\ntype TemplateView = {\n id: string\n name: string\n description?: string\n grants: GrantView[]\n privilegeCount: number\n missingCount: number\n defaultNameTaken: boolean\n grantsNothingDeliberately: boolean\n}\n\nconst AXIS_LABEL: Record<string, string> = {\n query: 'label.read',\n mutation: 'label.write',\n execute: 'label.execute'\n}\n\n/**\n * The module, in words people use.\n *\n * Same rule as the role privilege page (`moduleLabel` there): use\n * `privilege.category.<category>` when it exists and **fall back to the code word**. Not\n * inventing one is the point — a made-up name would read as product vocabulary and hide\n * from the UX lane that the sentence is still missing.\n */\nfunction moduleLabel(category: string): string {\n return i18next.t(`privilege.category.${category}`, { defaultValue: category })\n}\n\nfunction axisLabel(axis: string): string {\n return AXIS_LABEL[axis] ? i18next.t(AXIS_LABEL[axis]) : axis\n}\n\n/** Stable order inside a group, by the name a person actually reads. */\nfunction byName(a: GrantView, b: GrantView): number {\n return moduleLabel(a.category).localeCompare(moduleLabel(b.category))\n}\n\n/**\n * Starting a role.\n *\n * ── Why this stands where the blank row used to ──────────────────────────────\n * A new plant has no roles, and the old answer to \"make one\" was an empty line waiting for\n * a name. Naming it is the easy half; the hard half is which of 84 privileges belong to a\n * quality inspector, and that is a judgement the product has made and the plant has not.\n *\n * miratek is the case: two roles (Administrator, TWIN-CONNECTOR), no MES seats, and eleven\n * approval doors standing empty because there is nothing to route them to. Read from\n * inside, that looks like a plant that has not decided. It is a plant with nothing to\n * decide from.\n *\n * ── Both doors, in one place ─────────────────────────────────────────────────\n * The templates come first and the blank name last, because the order is what teaches: a\n * plant that sees \"quality inspector, 7 privileges\" learns what a seat looks like before\n * it is asked to invent one. Hiding the blank door would be worse, though — the seats a\n * factory actually has (\"night shift lead\", \"outside inspector\") are its own, and the\n * product does not know them.\n *\n * ── Why the name is editable ─────────────────────────────────────────────────\n * The template knows the seat exists; it does not know what the people there call it. And\n * because a role is also what an approval line points at, the same seat is sometimes\n * needed twice — a day and a night inspector hold the same privileges and take different\n * approvals. A fixed name would allow each template exactly once per domain.\n */\n@customElement('role-template-picker')\nexport class RoleTemplatePicker extends localize(i18next)(LitElement) {\n static styles: CSSResultGroup = [\n ScrollbarStyles,\n /*\n * Native controls, styled by the shared block.\n *\n * This used `md-filled-text-field` and the Material buttons until the user looked at it\n * (2026-09-11): \"too big, and the style does not fit.\" They are right — a filled field\n * with a floating label is a form control from a different density than the pills,\n * chips and 30px rows this product uses everywhere else.\n *\n * `FormFieldStyles` exists precisely for this: a component draws its input inside its\n * own shadow root, where the theme stylesheet cannot reach, so the token wiring has to\n * be declared per component. It goes first so local rules below can override it.\n */\n FormFieldStyles,\n /* The popup footer already has a convention — plain buttons, pill on pointer devices. */\n CommonHeaderStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n background-color: var(--md-sys-color-surface-container-lowest);\n color: var(--md-sys-color-on-surface);\n height: 100%;\n overflow: hidden;\n }\n\n [body] {\n display: grid;\n grid-template-columns: minmax(240px, 320px) 1fr;\n gap: var(--spacing-medium, 8px);\n padding: var(--spacing-medium, 8px);\n flex: 1;\n min-height: 0;\n }\n\n [panel] {\n display: flex;\n flex-direction: column;\n min-height: 0;\n background-color: var(--md-sys-color-surface);\n border-radius: var(--md-sys-shape-corner-medium, 8px);\n overflow: hidden;\n }\n\n [panel] > header {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: var(--spacing-small, 6px) var(--spacing-medium, 8px);\n font-size: var(--fontsize-small, 13px);\n color: var(--md-sys-color-on-surface-variant);\n background-color: var(--md-sys-color-surface-container);\n }\n\n [count] {\n color: var(--md-sys-color-primary);\n font-weight: 600;\n }\n\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n overflow-y: auto;\n flex: 1;\n }\n\n li[seat] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: var(--spacing-small, 6px) var(--spacing-medium, 8px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n cursor: pointer;\n }\n\n li[seat]:hover {\n background-color: var(--md-sys-color-surface-container-high);\n }\n\n li[seat][selected] {\n background-color: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n\n li[seat] [title-row] {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n li[seat] [name] {\n font-weight: 600;\n }\n\n li[seat] small {\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--fontsize-small, 12px);\n }\n\n li[seat][selected] small {\n color: inherit;\n }\n\n [tag] {\n font-size: var(--fontsize-smaller, 11px);\n padding: 0 6px;\n border-radius: var(--md-sys-shape-corner-full, 999px);\n background-color: var(--md-sys-color-surface-container-highest);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n [tag][warn] {\n background-color: var(--md-sys-color-error-container);\n color: var(--md-sys-color-on-error-container);\n }\n\n [detail] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-large, 14px);\n padding: var(--spacing-large, 14px);\n overflow-y: auto;\n flex: 1;\n }\n\n /* 곁말 — 필드 밑에 붙거나 혼자 선다. 본문과 같은 무게로 두면 읽는 순서가 흐려진다. */\n [note],\n label[field] small {\n margin: 0;\n font-size: var(--fontsize-small, 12px);\n color: var(--md-sys-color-on-surface-variant);\n line-height: 1.5;\n }\n\n dl[grants] {\n display: grid;\n grid-template-columns: minmax(8em, max-content) 1fr;\n /* 줄 사이가 2px 이었다. 이름이 위아래로 붙어 한 덩어리로 읽혔다. */\n gap: 6px var(--spacing-large, 14px);\n margin: 0;\n align-items: baseline;\n }\n\n /*\n * 모듈 이름이 **기준선**이다 — 굵기로 두 칸이 저절로 갈린다.\n *\n * 처음엔 거꾸로였다: 이름을 흐리게 두고 「쓰기」를 굵게 했더니, 눈이 먼저 닿는 것이\n * 오른쪽 칸이 되어 왼쪽이 뭘 말하는지 훑어지지 않았다. 사람이 이 표에서 찾는 것은\n * 「이 자리가 **어느 모듈**을 여나」이고, 읽기냐 쓰기냐는 그 다음이다.\n */\n dl[grants] dt {\n color: var(--md-sys-color-on-surface);\n font-size: var(--fontsize-small, 13px);\n font-weight: 600;\n }\n\n dl[grants] dd {\n margin: 0;\n display: flex;\n flex-wrap: wrap;\n /* 낱말 사이 가운뎃점 — 「읽기 쓰기」가 한 낱말로 붙어 보이던 것을 가른다. */\n gap: 0 6px;\n }\n\n dl[grants] dd [axis] + [axis]::before {\n content: '·';\n margin-right: 6px;\n color: var(--md-sys-color-outline);\n }\n\n [axis] {\n font-size: var(--fontsize-small, 12px);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n [axis][missing] {\n text-decoration: line-through;\n color: var(--md-sys-color-outline);\n }\n\n [empty] {\n margin: auto;\n text-align: center;\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--fontsize-small, 13px);\n padding: var(--spacing-large, 16px);\n }\n\n /* 자리 배치만 더한다 — 모양은 CommonHeaderStyles 의 .footer 가 갖는다. */\n .footer {\n justify-content: flex-end;\n }\n `\n ]\n\n @property({ type: Object }) page?: any\n\n @state() private templates: TemplateView[] = []\n @state() private selected?: TemplateView\n /** `undefined` means \"the blank door\" — name the seat yourself. */\n @state() private scratch = false\n @state() private name = ''\n @state() private description = ''\n\n async connectedCallback() {\n super.connectedCallback()\n await this.fetchTemplates()\n }\n\n private async fetchTemplates() {\n const response = await client.query({\n query: gql`\n query {\n roleTemplates {\n id\n name\n description\n privilegeCount\n missingCount\n defaultNameTaken\n grantsNothingDeliberately\n grants {\n category\n axes\n missingAxes\n }\n }\n }\n `,\n context: gqlContext()\n })\n\n /*\n * A GraphQL error arrives as `data: null` with `errors` set, and `?? []` would draw\n * that as \"this installation offers nothing\" — a refusal made to look like an answer.\n */\n if (response.errors?.length) {\n document.dispatchEvent(\n new CustomEvent('notify', { detail: { level: 'error', message: response.errors[0]?.message } })\n )\n return\n }\n\n this.templates = response.data?.roleTemplates || []\n }\n\n render() {\n return html`\n <div body>\n <div panel>\n <header>\n ${i18next.t('field.seat')}\n <span count>${this.templates.length}</span>\n </header>\n <ul>\n ${this.templates.map(\n template => html`\n <li seat ?selected=${!this.scratch && this.selected?.id === template.id} @click=${() => this.pick(template)}>\n <div title-row>\n <span name>${template.name}</span>\n ${template.defaultNameTaken\n ? html`<span tag>${i18next.t('text.already in this domain')}</span>`\n : nothing}\n ${template.missingCount\n ? html`<span tag warn>${i18next.t('text.x not here', { x: template.missingCount })}</span>`\n : nothing}\n </div>\n <small>${this.summarize(template)}</small>\n </li>\n `\n )}\n <li seat ?selected=${this.scratch} @click=${() => this.pickScratch()}>\n <div title-row>\n <md-icon>edit</md-icon>\n <span name>${i18next.t('button.name it yourself')}</span>\n </div>\n <small>${i18next.t('text.start from a blank seat')}</small>\n </li>\n </ul>\n </div>\n\n <div panel>${this.renderDetail()}</div>\n </div>\n\n <div class=\"footer\">\n <button @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${i18next.t('button.cancel')}</button>\n <button ok ?disabled=${!this.canCreate()} @click=${() => this.create()}>${i18next.t('button.create')}</button>\n </div>\n `\n }\n\n /**\n * What the seat opens, in one line — **counted, not interpreted.**\n *\n * This briefly said \"changes 6 · only sees 8\", which read well and was not something the\n * data supports: the privilege axis is an unconstrained string and its name does not\n * determine what the resolver behind it does. Counting is safe; grouping by meaning was\n * not. See `renderOpens`.\n *\n * \"0 privileges\" is still two different facts and must not be merged: granting nothing\n * on purpose is an approval seat, and a template whose grants are all missing here is a\n * defect (`missingCount`).\n */\n private summarize(template: TemplateView) {\n if (template.grantsNothingDeliberately) {\n return i18next.t('text.opens nothing, receives approvals')\n }\n\n return i18next.t('text.x modules y privileges', {\n x: template.grants.filter(grant => grant.axes.length).length,\n y: template.privilegeCount\n })\n }\n\n private renderDetail() {\n if (this.scratch) {\n return html`\n <header>${i18next.t('button.name it yourself')}</header>\n <div detail>\n <label field>\n ${i18next.t('field.name')}\n <input .value=${this.name} @input=${(e: any) => (this.name = e.target.value)} />\n </label>\n <label field>\n ${i18next.t('field.description')}\n <input .value=${this.description} @input=${(e: any) => (this.description = e.target.value)} />\n </label>\n <small>${i18next.t('text.a blank seat opens nothing until you give it privileges')}</small>\n </div>\n `\n }\n\n if (!this.selected) {\n return html`<div empty>${i18next.t('text.pick a seat to see what it opens')}</div>`\n }\n\n const template = this.selected\n\n return html`\n <header>${template.name}</header>\n <div detail>\n <label field>\n ${i18next.t('field.name')}\n <input .value=${this.name} @input=${(e: any) => (this.name = e.target.value)} />\n <small>${i18next.t('text.this plant may call the seat what it likes')}</small>\n </label>\n ${template.defaultNameTaken && this.name === template.name\n ? html`<p note>${i18next.t('text.a role of this name exists and will be added to')}</p>`\n : nothing}\n ${this.renderOpens(template)}\n </div>\n `\n }\n\n /**\n * 이 자리가 무엇을 여나 — **선언된 것만.**\n *\n * ⚠ 여기 「바꿀 수 있는 것 / 볼 수만 있는 것」 두 묶음이 있었다. 사용자가 물었다(2026-09-11):\n * 「바꿀 수 있고, 볼 수만 있는 것을 너가 어떻게 알아? 논리적이지 않은 것을 우겨넣지 말고.」\n *\n * 몰랐다. 지어낸 것이다. 근거가 없는 이유가 둘이다.\n *\n * ① `@privilege(privilege:)` 는 **제약 없는 문자열**이다(지시자 선언이 `privilege: String`\n * 이고 enum 이 아니다). 지금 쓰인 값이 mutation 484 · query 314 로 둘뿐인 것은 **오늘\n * 그렇게 쓴 것**이지 둘로 한정된 것이 아니다. 내 코드는 `axis !== 'query'` 로 갈랐으므로,\n * 처음 보는 값은 **알아서가 아니라 query 가 아니라서** 「바꿀 수 있는 것」으로 떨어졌다.\n * ② 이름이 뜻을 보장하지 않는다. 축 이름과 실제 GraphQL 연산이 어긋나는 자리가 6곳이고,\n * 그중 둘은 이 기능의 내 파일이다(`role-template-query.ts` — 템플릿을 **읽는** 질의에\n * `privilege: \"mutation\"` 을 달았다. 역할을 만드는 문이라서 그게 맞다). 축은 연산 종류가\n * 아니라 **어느 문을 지나야 하나**의 이름이다.\n *\n * 그래서 화면은 선언된 것을 그대로 낸다 — 어느 모듈에, 어느 권한이. 읽히게 만드는 것\n * (굵기·줄 간격·가운뎃점)은 아무것도 주장하지 않으므로 그대로 둔다.\n */\n private renderOpens(template: TemplateView) {\n if (template.grantsNothingDeliberately) {\n return html`<p note>${i18next.t('text.opens nothing, receives approvals')}</p>`\n }\n\n return html`\n <dl grants>\n ${[...template.grants].sort(byName).map(\n grant => html`\n <dt>${moduleLabel(grant.category)}</dt>\n <dd>\n ${grant.axes.map(axis => html`<span axis>${axisLabel(axis)}</span>`)}\n ${grant.missingAxes.map(axis => html`<span axis missing>${axisLabel(axis)}</span>`)}\n </dd>\n `\n )}\n </dl>\n ${template.missingCount\n ? html`<p note>${i18next.t('text.struck through are not installed here')}</p>`\n : nothing}\n `\n }\n\n private pick(template: TemplateView) {\n this.scratch = false\n this.selected = template\n this.name = template.name\n }\n\n private pickScratch() {\n this.scratch = true\n this.selected = undefined\n this.name = ''\n }\n\n private canCreate() {\n return Boolean(this.name.trim()) && (this.scratch || Boolean(this.selected))\n }\n\n private async create() {\n const created = this.scratch\n ? await this.page?.createBlankRole?.(this.name.trim(), this.description.trim())\n : await this.page?.createFromTemplate?.(this.selected!.id, this.name.trim())\n\n if (created) {\n this.dispatchEvent(new CustomEvent('close'))\n }\n }\n}\n"]}
|
|
@@ -5,25 +5,30 @@ import type { CSSResultGroup } from 'lit';
|
|
|
5
5
|
import { PageView } from '@operato/shell';
|
|
6
6
|
import type { FetchOption } from '@operato/data-grist';
|
|
7
7
|
/**
|
|
8
|
-
* 역할 목록 —
|
|
8
|
+
* 역할 목록 — **보이는 것과 고칠 수 있는 것을 가른다.**
|
|
9
9
|
*
|
|
10
10
|
* ── 옛 화면이 하던 것 (`pages/role/role-management.ts`) ──────────────────────
|
|
11
11
|
* `quick-find-list` 안에 역할을 늘어놓고, 펼치면 그 안에 이름 입력칸과 84줄의 권한 체크박스가
|
|
12
|
-
* 함께 있었다. 그 구조에서
|
|
12
|
+
* 함께 있었다. 그 구조에서 셋이 났다.
|
|
13
13
|
*
|
|
14
14
|
* ① 이름 입력이 매 글자마다 페이지로 올라가 **모든** 편집기에 공유됐다 — A 를 고치고 B 를
|
|
15
|
-
* 저장하면 B 의 이름이 A 가 됐다. 지금은
|
|
15
|
+
* 저장하면 B 의 이름이 A 가 됐다. 지금은 이름·설명을 격자에서 고친다.
|
|
16
16
|
* ② 목록에 권한이 하나도 안 보였다. 「이 역할이 무엇을 여나」를 알려면 펼쳐야 했다.
|
|
17
17
|
* ③ 한도도 쪽 나누기도 없었다.
|
|
18
18
|
*
|
|
19
|
-
* ──
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* ── 상속이 이 화면의 중심이다 ───────────────────────────────────────────────
|
|
20
|
+
* 목록은 부모 도메인의 역할까지 보여 준다 — **부여할 수 있는 범위가 그것**이기 때문이다.
|
|
21
|
+
* 그런데 그 행은 여기서 못 고친다(`updateRole` 이 `domain.id` 하나로 좁혀 찾는다).
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* 전에는 `Include` 로 열어서 **못 고치는 9행이 고칠 수 있는 2행 앞에 깔렸다**(UX 실측).
|
|
24
|
+
* 지금은 「우리 역할」로 열고, 세 묶음의 수를 함께 적어 **상속이 있다는 사실 자체는 남긴다.**
|
|
25
|
+
* 편집도 `editable` 함수로 상속 행에서 닫고, 삭제도 상속 행을 안 보낸다.
|
|
26
|
+
*
|
|
27
|
+
* ── 권한은 수만 낸다 ────────────────────────────────────────────────────────
|
|
28
|
+
* 전에는 `activity 쓰기 · activity-instance 쓰기·읽기` 식으로 잘린 코드 용어를 그렸고, 그것을
|
|
29
|
+
* 그리려고 권한 **행**을 받았다(UX 실측 5,731 bytes · 69ms 대 518 bytes · 7ms). 지금은
|
|
30
|
+
* `privilegeCount` 하나를 받는다. 권한 편집으로 가는 문은 **버튼 gutter 칸**이 진다 —
|
|
31
|
+
* 눌리는 숫자는 손잡이로 보이지 않는다.
|
|
27
32
|
*/
|
|
28
33
|
declare const RoleListPageBase: (new (...args: any[]) => {
|
|
29
34
|
__preferenceProviders: {
|
|
@@ -39,6 +44,16 @@ export declare class RoleListPage extends RoleListPageBase {
|
|
|
39
44
|
private total;
|
|
40
45
|
private filtered;
|
|
41
46
|
private mySubdomain;
|
|
47
|
+
private scope;
|
|
48
|
+
/**
|
|
49
|
+
* 묶음마다 몇 건인가.
|
|
50
|
+
*
|
|
51
|
+
* 수를 함께 적는 이유는 **상속이 있다는 사실 자체가 보이게** 하는 것이다. 기본값을 「우리
|
|
52
|
+
* 역할」로 좁혀 놓으면, 수가 없으면 상속 9건이 존재하는지조차 모른다.
|
|
53
|
+
*
|
|
54
|
+
* `undefined` 는 「아직 못 셌다」다 — 0 으로 메우면 「없다」와 같아 보인다.
|
|
55
|
+
*/
|
|
56
|
+
private counts;
|
|
42
57
|
private grist;
|
|
43
58
|
/**
|
|
44
59
|
* 저장과 삭제를 **툴바**에 둔다.
|
|
@@ -46,15 +61,50 @@ export declare class RoleListPage extends RoleListPageBase {
|
|
|
46
61
|
* 격자에서 고치는 화면들의 관례다(`fiscal-quarter-list-page` 외). 격자 안 편집은 여러 줄을
|
|
47
62
|
* 한꺼번에 고치므로, 줄마다 저장 단추를 두면 어디를 눌러야 하는지가 사라진다.
|
|
48
63
|
*/
|
|
64
|
+
/**
|
|
65
|
+
* 찾기는 **제목 줄**에 선다 — 셸이 그 자리를 모든 화면에 같은 모양으로 둔다.
|
|
66
|
+
*
|
|
67
|
+
* 이 페이지는 한동안 `ox-filters-form` 을 헤드룸의 칩 줄에 **직접** 끼워 넣고 있었다. 그래서
|
|
68
|
+
* 돋보기가 범위 칩과 만들기 단추 사이에 끼어, 같은 앱의 다른 목록과 찾기 자리가 달랐다
|
|
69
|
+
* (`env-var-list-page` 외 auth-ui 목록 다섯이 전부 아래 모양이다).
|
|
70
|
+
*
|
|
71
|
+
* 둘은 대안이 아니라 **다른 것**이다 — `search` 는 목록 전체를 훑는 글자 찾기이고,
|
|
72
|
+
* `filter` 는 칸별 조건 폼을 접었다 펴는 것이다. 표준 화면은 둘 다 선언한다.
|
|
73
|
+
*/
|
|
49
74
|
get context(): {
|
|
50
75
|
title: string;
|
|
51
76
|
help: string;
|
|
77
|
+
search: {
|
|
78
|
+
handler: (search: string) => void;
|
|
79
|
+
value: string;
|
|
80
|
+
};
|
|
81
|
+
filter: {
|
|
82
|
+
handler: () => void;
|
|
83
|
+
};
|
|
52
84
|
actions: {
|
|
53
85
|
title: string;
|
|
54
86
|
action: () => Promise<void>;
|
|
55
87
|
}[];
|
|
56
88
|
};
|
|
57
89
|
render(): import("lit-html").TemplateResult<1>;
|
|
90
|
+
/**
|
|
91
|
+
* 세 묶음.
|
|
92
|
+
*
|
|
93
|
+
* **수를 함께 적는 것이 이 부품의 이유다.** 기본값을 「우리 역할」로 좁혀 두면 처음 화면이
|
|
94
|
+
* 깨끗한 대신 **상속 9건이 있다는 사실이 사라진다.** 수가 그것을 되돌려 놓는다.
|
|
95
|
+
*
|
|
96
|
+
* 아직 못 센 묶음은 수를 **안 그린다** — 0 으로 메우면 「없다」와 같아 보인다.
|
|
97
|
+
*/
|
|
98
|
+
private renderScopes;
|
|
99
|
+
private onScope;
|
|
100
|
+
/**
|
|
101
|
+
* 세 묶음의 건수.
|
|
102
|
+
*
|
|
103
|
+
* 세 번 묻는다. 한 번에 셋을 세는 질의가 서버에 없고, 각각 `total` 만 받으므로 가볍다
|
|
104
|
+
* (UX 실측 158·566·684 bytes). 실패하면 **수를 안 그린다** — 틀린 수를 그리는 것보다
|
|
105
|
+
* 없는 것이 낫다.
|
|
106
|
+
*/
|
|
107
|
+
private countScopes;
|
|
58
108
|
/**
|
|
59
109
|
* 목록 위에 겹쳐 그린다 — 격자를 떼면 다시 읽을 길이 없어진다.
|
|
60
110
|
*
|
|
@@ -70,13 +120,32 @@ export declare class RoleListPage extends RoleListPageBase {
|
|
|
70
120
|
* 거절한다. 모를 때는 잠가 두는 쪽이 안전하다.
|
|
71
121
|
*/
|
|
72
122
|
private isInherited;
|
|
123
|
+
/**
|
|
124
|
+
* 출처 한 칸.
|
|
125
|
+
*
|
|
126
|
+
* 「우리」는 조용히 둔다 — 기본 상태에 색을 쓰면 색이 아무것도 말하지 않게 된다.
|
|
127
|
+
* 상속은 **어느 도메인에서 왔는지 함께 적는다.** 「상속」만 적으면 관리자가 어디로 가야
|
|
128
|
+
* 하는지 모른다.
|
|
129
|
+
*/
|
|
130
|
+
private sourceCell;
|
|
73
131
|
pageInitialized(): Promise<void>;
|
|
74
132
|
pageUpdated(_changes: any, _lifecycle: any): Promise<void>;
|
|
75
133
|
/**
|
|
76
|
-
*
|
|
134
|
+
* 역할을 가져온다 — **권한 행은 받지 않는다.**
|
|
135
|
+
*
|
|
136
|
+
* 전에는 `privileges { id name category }` 를 함께 물었다. 그것으로 그린 것은 잘린 코드 용어
|
|
137
|
+
* 셋이었고, 값은 이랬다.
|
|
138
|
+
*
|
|
139
|
+
* ```
|
|
140
|
+
* [UX 실측] 권한 포함 5,731 bytes · 69ms
|
|
141
|
+
* [UX 실측] 권한 없이 518 bytes · 7ms
|
|
142
|
+
* ```
|
|
77
143
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
144
|
+
* 바이트보다 큰 것은 **`Role.privileges` 필드 리졸버가 역할마다 한 번씩 도는 것**이 함께
|
|
145
|
+
* 없어지는 쪽이다. 지금은 `privilegeCount` 를 받는다 — DB 가 센다(`role-query.ts`).
|
|
146
|
+
*
|
|
147
|
+
* `inherited` 는 화면이 고른 묶음을 그대로 넘긴다. 기본값이 「우리 역할」이라 처음 화면에
|
|
148
|
+
* 못 고치는 행이 안 깔린다.
|
|
80
149
|
*/
|
|
81
150
|
fetchHandler({ filters, page, limit, sortings }: FetchOption): Promise<{
|
|
82
151
|
records: any;
|
|
@@ -101,6 +170,28 @@ export declare class RoleListPage extends RoleListPageBase {
|
|
|
101
170
|
* 않고 목록을 다시 읽는다 — 무엇이 남았는지가 화면에서 보이는 것이 맞다.
|
|
102
171
|
*/
|
|
103
172
|
private onDeleteGrid;
|
|
173
|
+
/**
|
|
174
|
+
* 역할을 만드는 두 문을 **한 자리에** 연다.
|
|
175
|
+
*
|
|
176
|
+
* ── 왜 `ox-record-creator`(빈 줄)를 걷어냈나 ────────────────────────────────
|
|
177
|
+
* 이름을 짓는 것은 쉬운 쪽이고 「품질검사원에게 84개 중 무엇을 주나」가 어려운 쪽인데, 빈
|
|
178
|
+
* 줄은 그 판단을 통째로 사람에게 넘긴다. 미라텍이 그래서 역할 둘뿐이다.
|
|
179
|
+
*
|
|
180
|
+
* 그리고 그 단추는 `.filters` 안에 있었는데 `CommonHeaderStyles` 는 `.actions button` 만
|
|
181
|
+
* 꾸민다. `.filters` 에 button 규칙이 없어서 **브라우저 기본 단추**가 그대로 나왔다 — 옆의
|
|
182
|
+
* 알약 범위 단추·검색과 같은 줄에서 혼자 네모난 회색 상자였다. 이 관례를 쓰는 다른 목록
|
|
183
|
+
* 화면(24 파일)도 전부 같은 상태다.
|
|
184
|
+
*
|
|
185
|
+
* ── 순서가 가르친다 ────────────────────────────────────────────────────────
|
|
186
|
+
* 템플릿이 먼저고 백지가 나중이다. 「품질검사원, 권한 7」을 본 사람은 자리가 어떻게 생긴
|
|
187
|
+
* 것인지 알고 나서 자기 것을 짓는다. 그렇다고 백지를 감추면 안 된다 — 「야간반장」·「외주
|
|
188
|
+
* 검사」 같은 자리는 그 공장이 아는 것이지 제품이 아는 게 아니다.
|
|
189
|
+
*/
|
|
190
|
+
private openCreate;
|
|
191
|
+
/** 템플릿에서 — 이름은 이 공장이 정한 것을 그대로 보낸다. */
|
|
192
|
+
createFromTemplate(templateId: string, name: string): Promise<boolean>;
|
|
193
|
+
/** 백지에서 — 권한 없이 선다. 목록의 권한 수 칸이 0 을 빨갛게 말하므로 다음 걸음이 보인다. */
|
|
194
|
+
createBlankRole(name: string, description: string): Promise<boolean>;
|
|
104
195
|
/**
|
|
105
196
|
* 새 역할.
|
|
106
197
|
*
|