@things-factory/auth-ui 10.1.198 → 10.1.203
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/access-decision-popup.js +7 -5
- package/dist-client/components/access-decision-popup.js.map +1 -1
- package/dist-client/components/access-request-popup.d.ts +9 -1
- package/dist-client/components/access-request-popup.js +55 -4
- package/dist-client/components/access-request-popup.js.map +1 -1
- package/dist-client/components/role-task-edit.d.ts +22 -0
- package/dist-client/components/role-task-edit.js +17 -0
- package/dist-client/components/role-task-edit.js.map +1 -0
- package/dist-client/components/role-task-edit.test.d.ts +1 -0
- package/dist-client/components/role-task-edit.test.js +34 -0
- package/dist-client/components/role-task-edit.test.js.map +1 -0
- package/dist-client/pages/access-request/access-requests.js +4 -2
- package/dist-client/pages/access-request/access-requests.js.map +1 -1
- package/dist-client/pages/access-request/my-access-requests.js +3 -2
- package/dist-client/pages/access-request/my-access-requests.js.map +1 -1
- package/dist-client/pages/role/role-privilege-page.d.ts +10 -2
- package/dist-client/pages/role/role-privilege-page.js +62 -3
- package/dist-client/pages/role/role-privilege-page.js.map +1 -1
- package/dist-client/pages/role/role-task-review.test.js +13 -2
- package/dist-client/pages/role/role-task-review.test.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/access-request.d.ts +15 -1
- package/dist-client/utils/access-request.js +19 -2
- package/dist-client/utils/access-request.js.map +1 -1
- package/dist-client/utils/access-request.test.js +26 -1
- package/dist-client/utils/access-request.test.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/translations/en.json +11 -1
- package/translations/es.json +11 -1
- package/translations/ja.json +11 -1
- package/translations/ko.json +11 -1
- package/translations/ms.json +11 -1
- package/translations/zh.json +11 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"my-access-requests.js","sourceRoot":"","sources":["../../../client/pages/access-request/my-access-requests.ts"],"names":[],"mappings":";AAAA,OAAO,iCAAiC,CAAA;AAExC,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC/B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAGlE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAC3F,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"my-access-requests.js","sourceRoot":"","sources":["../../../client/pages/access-request/my-access-requests.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist/ox-grist.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport type { DataGrist } from '@operato/data-grist'\nimport { client, gqlContext } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { PageView } from '@operato/shell'\nimport { CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport { neededWords } from '../../utils/access-request.js'\nimport { arrayFromResponse, listOutcome } from '../../utils/list-result.js'\n\n/**\n * The person's own access requests - what became of each (ADR-0103). A notification may not reach them;\n * this does.\n */\n@customElement('my-access-requests-page')\nexport class MyAccessRequestsPage extends localize(i18next)(PageView) {\n static styles = [\n WorkSurfacePageStyles,\n CommonGristStyles,\n ScrollbarStyles,\n css`\n [failed] {\n padding: var(--spacing-medium);\n color: var(--md-sys-color-error);\n }\n `\n ]\n\n @property({ type: Boolean }) active: boolean = false\n @property({ type: Object }) config: any\n @property({ type: Boolean }) failed: boolean = false\n\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return { title: i18next.t('access-request.title.my access requests') }\n }\n\n render() {\n return html`\n <ox-grist class=\"page-fill\" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.config} .fetchHandler=${this.fetchHandler.bind(this)}></ox-grist>\n ${this.failed ? html`<div failed>${i18next.t('text.the list could not be loaded')}</div>` : ''}\n `\n }\n\n async pageInitialized() {\n const t = i18next.t.bind(i18next)\n this.config = {\n pagination: { infinite: true },\n rows: { appendable: false, selectable: false },\n columns: [\n {\n type: 'gutter',\n gutterName: 'button',\n icon: 'undo',\n title: t('access-request.button.withdraw'),\n handlers: { click: (_c: any, _d: any, _col: any, record: any) => record?.state === 'PENDING' && this.withdraw(record) }\n },\n { type: 'string', name: 'needed', header: t('access-request.field.needed'), record: { editable: false }, width: 260 },\n { type: 'string', name: 'stateWords', header: t('field.state'), record: { align: 'center', editable: false }, width: 100 },\n { type: 'string', name: 'grantedRoleName', header: t('access-request.field.granted role'), record: { editable: false }, width: 140 },\n { type: 'string', name: 'decisionReason', header: t('access-request.field.decision reason'), record: { editable: false }, width: 220 },\n { type: 'datetime', name: 'createdAt', header: t('field.created at'), width: 170 }\n ]\n }\n }\n\n async pageUpdated(_changes: any, _lifecycle: any) {\n if (this.active) {\n await this.updateComplete\n this.grist.fetch()\n }\n }\n\n private async withdraw(record: any) {\n const confirmed = await OxPrompt.open({\n type: 'warning',\n title: i18next.t('access-request.button.withdraw'),\n text: record.needed,\n confirmButton: { text: i18next.t('access-request.button.withdraw') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n if (!confirmed) return\n\n await client.mutate({\n mutation: gql`\n mutation ($id: String!) {\n withdrawAccessRequest(id: $id) {\n id\n }\n }\n `,\n variables: { id: record.id },\n context: gqlContext()\n })\n this.grist.fetch()\n }\n\n async fetchHandler() {\n const response = await client.query({\n query: gql`\n query {\n myAccessRequests {\n id\n category\n privilege\n taskId\n state\n expiresAt\n createdAt\n decisionReason\n grantedRole {\n name\n }\n }\n }\n `,\n context: gqlContext(),\n fetchPolicy: 'network-only'\n })\n const { items, failed } = listOutcome(arrayFromResponse(response, 'myAccessRequests'))\n this.failed = failed\n const t = i18next.t.bind(i18next)\n const records = items.map((item: any) => {\n const state = item.state === 'PENDING' && item.expiresAt && new Date(item.expiresAt).getTime() <= Date.now() ? 'EXPIRED' : item.state\n return {\n ...item,\n state,\n stateWords: t(`access-request.state.${state.toLowerCase()}`),\n needed: neededWords(t, item),\n grantedRoleName: item.grantedRole?.name || ''\n }\n })\n return { total: records.length, records }\n }\n}\n"]}
|
|
@@ -133,10 +133,18 @@ export declare class RolePrivilegePage extends RolePrivilegePage_base {
|
|
|
133
133
|
*
|
|
134
134
|
* It says what the role holds, nothing more: 「전부」 is not "this person can do the work" (another role, the
|
|
135
135
|
* data's own scope or an approval line decide that too), and 「일부」 is not a fault — a privilege several tasks
|
|
136
|
-
* share makes each of them 「일부」.
|
|
137
|
-
*
|
|
136
|
+
* share makes each of them 「일부」.
|
|
137
|
+
*
|
|
138
|
+
* A task can be added to the role or taken off it (the user, 2026-10-20). The role stores privileges, never tasks,
|
|
139
|
+
* so either is a set of privileges, shown before it is saved. Taking a task off keeps what another task the role
|
|
140
|
+
* holds whole still uses (`role-task-edit.ts`). Both save at once and read the coverage again, so they are not
|
|
141
|
+
* offered over unsaved changes - the coverage is the saved role's.
|
|
138
142
|
*/
|
|
139
143
|
private renderTasks;
|
|
144
|
+
/** 더하기 for a task the role lacks some or all of, 빼기 for one it holds some or all of. */
|
|
145
|
+
private taskEditButton;
|
|
146
|
+
/** Adds a task's missing privileges to the role, or takes its own off - after showing which - and saves. */
|
|
147
|
+
private editTask;
|
|
140
148
|
private renderTask;
|
|
141
149
|
/**
|
|
142
150
|
* **The role against a template the administrator picks** (ADR-0139 decision 11) — whatever the role is called.
|
|
@@ -14,6 +14,7 @@ import { PageView } from '@operato/shell';
|
|
|
14
14
|
import { CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
|
|
15
15
|
import { getDomain } from '@things-factory/auth-base/dist-client';
|
|
16
16
|
import { filterPrivilegeModules, selectedVisibleModule } from '../../components/role-privilege-picker-state.js';
|
|
17
|
+
import { pairOf, pairsToAdd, pairsToRemove } from '../../components/role-task-edit.js';
|
|
17
18
|
const GRANT_FIELDS = 'category axes';
|
|
18
19
|
/**
|
|
19
20
|
* 한 역할이 무엇을 할 수 있나 — **켜진 것이 문장으로 본문에 선다.**
|
|
@@ -795,8 +796,12 @@ let RolePrivilegePage = class RolePrivilegePage extends localize(i18next)(PageVi
|
|
|
795
796
|
*
|
|
796
797
|
* It says what the role holds, nothing more: 「전부」 is not "this person can do the work" (another role, the
|
|
797
798
|
* data's own scope or an approval line decide that too), and 「일부」 is not a fault — a privilege several tasks
|
|
798
|
-
* share makes each of them 「일부」.
|
|
799
|
-
*
|
|
799
|
+
* share makes each of them 「일부」.
|
|
800
|
+
*
|
|
801
|
+
* A task can be added to the role or taken off it (the user, 2026-10-20). The role stores privileges, never tasks,
|
|
802
|
+
* so either is a set of privileges, shown before it is saved. Taking a task off keeps what another task the role
|
|
803
|
+
* holds whole still uses (`role-task-edit.ts`). Both save at once and read the coverage again, so they are not
|
|
804
|
+
* offered over unsaved changes - the coverage is the saved role's.
|
|
800
805
|
*/
|
|
801
806
|
renderTasks() {
|
|
802
807
|
const tasks = this.coverage.tasks;
|
|
@@ -820,7 +825,7 @@ let RolePrivilegePage = class RolePrivilegePage extends localize(i18next)(PageVi
|
|
|
820
825
|
</h4>
|
|
821
826
|
${this.showUnheldTasks
|
|
822
827
|
? html `<ul tasks quiet>
|
|
823
|
-
${unheld.map(task => html `<li>${taskName(task.taskId)}</li>`)}
|
|
828
|
+
${unheld.map(task => html `<li>${taskName(task.taskId)} ${this.taskEditButton(task)}</li>`)}
|
|
824
829
|
</ul>`
|
|
825
830
|
: nothing}`
|
|
826
831
|
: nothing}
|
|
@@ -834,6 +839,59 @@ let RolePrivilegePage = class RolePrivilegePage extends localize(i18next)(PageVi
|
|
|
834
839
|
</div>
|
|
835
840
|
`;
|
|
836
841
|
}
|
|
842
|
+
/** 더하기 for a task the role lacks some or all of, 빼기 for one it holds some or all of. */
|
|
843
|
+
taskEditButton(task) {
|
|
844
|
+
if (this.inherited || task.status === 'broken')
|
|
845
|
+
return nothing;
|
|
846
|
+
const disabled = this.dirty || this.saving;
|
|
847
|
+
const why = this.dirty ? i18next.t('text.save before editing by task') : '';
|
|
848
|
+
return html `
|
|
849
|
+
${task.status !== 'all'
|
|
850
|
+
? html `<button quiet ?disabled=${disabled} title=${why} @click=${() => this.editTask(task, 'add')}>${i18next.t('button.add task')}</button>`
|
|
851
|
+
: nothing}
|
|
852
|
+
${task.status !== 'none'
|
|
853
|
+
? html `<button quiet ?disabled=${disabled} title=${why} @click=${() => this.editTask(task, 'remove')}>${i18next.t('button.remove task')}</button>`
|
|
854
|
+
: nothing}
|
|
855
|
+
`;
|
|
856
|
+
}
|
|
857
|
+
/** Adds a task's missing privileges to the role, or takes its own off - after showing which - and saves. */
|
|
858
|
+
async editTask(task, mode) {
|
|
859
|
+
if (this.dirty || this.saving || this.inherited)
|
|
860
|
+
return;
|
|
861
|
+
const name = taskName(task.taskId);
|
|
862
|
+
const { remove, kept } = mode === 'remove' ? pairsToRemove(task, this.coverage.tasks) : { remove: [], kept: [] };
|
|
863
|
+
const pairs = mode === 'add' ? pairsToAdd(task) : remove;
|
|
864
|
+
const words = (list) => list.map(pair => this.sentenceOf(pair.split(':')[0], pair.split(':')[1])).join(', ');
|
|
865
|
+
const keptLine = kept.length ? ` ${i18next.t('text.kept for other tasks', { list: words(kept) })}` : '';
|
|
866
|
+
if (!pairs.length) {
|
|
867
|
+
await OxPrompt.open({
|
|
868
|
+
type: 'info',
|
|
869
|
+
title: i18next.t('title.remove task'),
|
|
870
|
+
text: i18next.t('text.nothing to remove for task', { task: name }) + keptLine,
|
|
871
|
+
confirmButton: { text: i18next.t('button.confirm') }
|
|
872
|
+
});
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
const confirmed = await OxPrompt.open({
|
|
876
|
+
type: 'info',
|
|
877
|
+
title: i18next.t(mode === 'add' ? 'title.add task' : 'title.remove task'),
|
|
878
|
+
text: i18next.t(mode === 'add' ? 'text.add task privileges' : 'text.remove task privileges', { task: name, count: pairs.length, list: words(pairs) }) + keptLine,
|
|
879
|
+
confirmButton: { text: i18next.t(mode === 'add' ? 'button.add task' : 'button.remove task') },
|
|
880
|
+
cancelButton: { text: i18next.t('button.cancel') }
|
|
881
|
+
});
|
|
882
|
+
if (!confirmed)
|
|
883
|
+
return;
|
|
884
|
+
const idOf = new Map(this.modules.flatMap(module => module.cells.map(cell => [pairOf(module.category, cell.axis), cell.id])));
|
|
885
|
+
const next = new Set(this.assigned);
|
|
886
|
+
for (const pair of pairs) {
|
|
887
|
+
const id = idOf.get(pair);
|
|
888
|
+
if (id)
|
|
889
|
+
mode === 'add' ? next.add(id) : next.delete(id);
|
|
890
|
+
}
|
|
891
|
+
this.assigned = next;
|
|
892
|
+
this.dirty = true;
|
|
893
|
+
await this.onSave();
|
|
894
|
+
}
|
|
837
895
|
renderTask(task) {
|
|
838
896
|
const held = countOf(task.held);
|
|
839
897
|
const total = held + countOf(task.missing);
|
|
@@ -847,6 +905,7 @@ let RolePrivilegePage = class RolePrivilegePage extends localize(i18next)(PageVi
|
|
|
847
905
|
: task.status === 'all'
|
|
848
906
|
? html `<span state all>${i18next.t('text.task held whole')}</span>`
|
|
849
907
|
: html `<span state>${i18next.t('text.task held in part', { held, total })}</span>`}
|
|
908
|
+
${this.taskEditButton(task)}
|
|
850
909
|
</div>
|
|
851
910
|
${says ? html `<div task-says>${says}</div>` : nothing}
|
|
852
911
|
${task.status === 'some'
|