@things-factory/auth-ui 10.1.104 → 10.1.107

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 (31) hide show
  1. package/dist-client/bootstrap.js +22 -1
  2. package/dist-client/bootstrap.js.map +1 -1
  3. package/dist-client/components/access-decision-popup.d.ts +30 -0
  4. package/dist-client/components/access-decision-popup.js +228 -0
  5. package/dist-client/components/access-decision-popup.js.map +1 -0
  6. package/dist-client/components/access-request-popup.d.ts +32 -0
  7. package/dist-client/components/access-request-popup.js +211 -0
  8. package/dist-client/components/access-request-popup.js.map +1 -0
  9. package/dist-client/pages/access-request/access-requests.d.ts +51 -0
  10. package/dist-client/pages/access-request/access-requests.js +220 -0
  11. package/dist-client/pages/access-request/access-requests.js.map +1 -0
  12. package/dist-client/pages/access-request/my-access-requests.d.ts +26 -0
  13. package/dist-client/pages/access-request/my-access-requests.js +151 -0
  14. package/dist-client/pages/access-request/my-access-requests.js.map +1 -0
  15. package/dist-client/route.js +6 -0
  16. package/dist-client/route.js.map +1 -1
  17. package/dist-client/tsconfig.layout-check.tsbuildinfo +1 -0
  18. package/dist-client/tsconfig.tsbuildinfo +1 -1
  19. package/dist-client/utils/access-request.d.ts +49 -0
  20. package/dist-client/utils/access-request.js +67 -0
  21. package/dist-client/utils/access-request.js.map +1 -0
  22. package/dist-client/utils/access-request.test.d.ts +1 -0
  23. package/dist-client/utils/access-request.test.js +70 -0
  24. package/dist-client/utils/access-request.test.js.map +1 -0
  25. package/package.json +6 -6
  26. package/things-factory.config.js +3 -1
  27. package/translations/en.json +61 -1
  28. package/translations/ja.json +61 -1
  29. package/translations/ko.json +61 -1
  30. package/translations/ms.json +61 -1
  31. package/translations/zh.json +61 -1
@@ -0,0 +1,51 @@
1
+ import '@material/web/icon/icon.js';
2
+ import '@operato/data-grist/ox-grist.js';
3
+ import '../../components/access-decision-popup.js';
4
+ import type { FetchOption } from '@operato/data-grist';
5
+ import { PageView } from '@operato/shell';
6
+ declare const AccessRequestsPage_base: (new (...args: any[]) => {
7
+ __preferenceProviders: {
8
+ [element: string]: import("@operato/p13n").PagePreferenceProvider;
9
+ };
10
+ getPagePreferenceProvider(element: string): import("@operato/p13n").PagePreferenceProvider | undefined;
11
+ }) & (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
12
+ /**
13
+ * Who asked for what in this domain, and what became of it (ADR-0103).
14
+ *
15
+ * This list is where the people deciding receive requests - in every product, worklist or not. A
16
+ * notification may point here; when none went out the request is here all the same. The rows are the
17
+ * record and are never deleted: who decided, which role, why not.
18
+ */
19
+ export declare class AccessRequestsPage extends AccessRequestsPage_base {
20
+ static styles: import("lit").CSSResult[];
21
+ active: boolean;
22
+ config: any;
23
+ mode: 'CARD' | 'LIST' | 'GRID';
24
+ failed: boolean;
25
+ private grist;
26
+ get context(): {
27
+ title: string;
28
+ help: string;
29
+ search: {
30
+ handler: (search: string) => void;
31
+ value: string;
32
+ };
33
+ actions: {
34
+ title: string;
35
+ action: () => void;
36
+ icon: string;
37
+ }[];
38
+ };
39
+ render(): import("lit-html").TemplateResult<1>;
40
+ pageInitialized(): Promise<void>;
41
+ private decide;
42
+ pageUpdated(_changes: any, lifecycle: any): Promise<void>;
43
+ /** The request a link named, opened only while it waits - a decided one is just a row in the list. */
44
+ private opened?;
45
+ private openById;
46
+ fetchHandler({ page, limit, sortings, filters }: FetchOption): Promise<{
47
+ total: number;
48
+ records: any[];
49
+ }>;
50
+ }
51
+ export {};
@@ -0,0 +1,220 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/icon/icon.js';
3
+ import '@operato/data-grist/ox-grist.js';
4
+ import '../../components/access-decision-popup.js';
5
+ import gql from 'graphql-tag';
6
+ import { css, html } from 'lit';
7
+ import { customElement, property, query } from 'lit/decorators.js';
8
+ import { client, gqlContext } from '@operato/graphql';
9
+ import { i18next, localize } from '@operato/i18n';
10
+ import { openPopup } from '@operato/layout';
11
+ import { navigate, PageView } from '@operato/shell';
12
+ import { CommonHeaderStyles, CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
13
+ import { isMobileDevice } from '@operato/utils';
14
+ import { p13n } from '@operato/p13n';
15
+ import { privilegeWords } from '../../utils/access-request.js';
16
+ import { listOutcome, pageFromResponse } from '../../utils/list-result.js';
17
+ /**
18
+ * Who asked for what in this domain, and what became of it (ADR-0103).
19
+ *
20
+ * This list is where the people deciding receive requests - in every product, worklist or not. A
21
+ * notification may point here; when none went out the request is here all the same. The rows are the
22
+ * record and are never deleted: who decided, which role, why not.
23
+ */
24
+ let AccessRequestsPage = class AccessRequestsPage extends p13n(localize(i18next)(PageView)) {
25
+ constructor() {
26
+ super(...arguments);
27
+ this.active = false;
28
+ this.mode = isMobileDevice() ? 'CARD' : 'GRID';
29
+ this.failed = false;
30
+ }
31
+ static { this.styles = [
32
+ WorkSurfacePageStyles,
33
+ CommonGristStyles,
34
+ CommonHeaderStyles,
35
+ ScrollbarStyles,
36
+ css `
37
+ [failed] {
38
+ padding: var(--spacing-medium);
39
+ color: var(--md-sys-color-error);
40
+ font: var(--label-font, inherit);
41
+ }
42
+ `
43
+ ]; }
44
+ get context() {
45
+ return {
46
+ title: i18next.t('access-request.title.access requests'),
47
+ help: 'auth/user',
48
+ search: {
49
+ handler: (search) => {
50
+ this.grist.searchText = search;
51
+ },
52
+ value: this.grist?.searchText || ''
53
+ },
54
+ actions: [{ title: i18next.t('text.users'), action: () => navigate('users'), icon: 'group' }]
55
+ };
56
+ }
57
+ render() {
58
+ return html `
59
+ <ox-grist
60
+ class="page-fill"
61
+ .mode=${this.mode}
62
+ .config=${this.config}
63
+ .fetchHandler=${this.fetchHandler.bind(this)}
64
+ .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')}
65
+ ></ox-grist>
66
+ ${this.failed ? html `<div failed>${i18next.t('text.the list could not be loaded')}</div>` : ''}
67
+ `;
68
+ }
69
+ async pageInitialized() {
70
+ const t = i18next.t.bind(i18next);
71
+ this.config = {
72
+ rows: { appendable: false, selectable: { multiple: false } },
73
+ sorters: [{ name: 'createdAt', desc: true }],
74
+ columns: [
75
+ { type: 'gutter', gutterName: 'sequence' },
76
+ /* Deciding means something only while it waits - offered only there. */
77
+ {
78
+ type: 'gutter',
79
+ gutterName: 'button',
80
+ icon: 'gavel',
81
+ title: t('access-request.button.decide'),
82
+ handlers: { click: (_c, _d, _col, record) => record?.state === 'PENDING' && this.decide(record) }
83
+ },
84
+ { type: 'string', name: 'requesterName', header: t('access-request.field.requester'), record: { editable: false }, width: 140 },
85
+ { type: 'string', name: 'needed', header: t('access-request.field.needed'), record: { editable: false }, width: 260 },
86
+ { type: 'string', name: 'reason', header: t('access-request.field.reason'), record: { editable: false }, filter: 'search', width: 200 },
87
+ { type: 'string', name: 'stateWords', header: t('field.state'), record: { align: 'center', editable: false }, width: 100 },
88
+ { type: 'integer', name: 'count', header: t('access-request.field.count'), record: { align: 'right', editable: false }, width: 70 },
89
+ { type: 'datetime', name: 'createdAt', header: t('field.created at'), sortable: true, width: 170 },
90
+ { type: 'string', name: 'deciderName', header: t('access-request.field.decided by'), record: { editable: false }, width: 140 },
91
+ { type: 'string', name: 'grantedRoleName', header: t('access-request.field.granted role'), record: { editable: false }, width: 140 },
92
+ { type: 'string', name: 'decisionReason', header: t('access-request.field.decision reason'), record: { editable: false }, width: 200 },
93
+ { type: 'datetime', name: 'decidedAt', header: t('access-request.field.decided at'), sortable: true, width: 170 }
94
+ ]
95
+ };
96
+ }
97
+ decide(record) {
98
+ openPopup(html `<access-decision-popup .request=${record} @access-request-decided=${() => this.grist.fetch()}></access-decision-popup>`, { size: 'medium', title: i18next.t('access-request.title.decide') });
99
+ }
100
+ async pageUpdated(_changes, lifecycle) {
101
+ if (this.active) {
102
+ await this.updateComplete;
103
+ this.grist.fetch();
104
+ /* A notification links here with the request's id - its decision opens at once, if it still waits. */
105
+ const id = lifecycle?.params?.id;
106
+ if (id && id !== this.opened) {
107
+ this.opened = id;
108
+ await this.openById(id);
109
+ }
110
+ }
111
+ }
112
+ async openById(id) {
113
+ const response = await client.query({
114
+ query: gql `
115
+ query ($filters: [Filter!]) {
116
+ accessRequests(filters: $filters) {
117
+ items {
118
+ id
119
+ category
120
+ privilege
121
+ reason
122
+ state
123
+ requester {
124
+ id
125
+ name
126
+ email
127
+ }
128
+ }
129
+ }
130
+ }
131
+ `,
132
+ variables: { filters: [{ name: 'id', operator: 'eq', value: id }] },
133
+ context: gqlContext(),
134
+ fetchPolicy: 'network-only'
135
+ });
136
+ const request = pageFromResponse(response, 'accessRequests')?.items?.[0];
137
+ if (request?.state === 'PENDING')
138
+ this.decide(request);
139
+ }
140
+ async fetchHandler({ page, limit, sortings = [], filters = [] }) {
141
+ const response = await client.query({
142
+ query: gql `
143
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
144
+ accessRequests(filters: $filters, pagination: $pagination, sortings: $sortings) {
145
+ items {
146
+ id
147
+ category
148
+ privilege
149
+ operationName
150
+ reason
151
+ count
152
+ state
153
+ expiresAt
154
+ createdAt
155
+ decidedAt
156
+ decisionReason
157
+ requester {
158
+ id
159
+ name
160
+ email
161
+ }
162
+ decidedBy {
163
+ id
164
+ name
165
+ }
166
+ grantedRole {
167
+ id
168
+ name
169
+ }
170
+ }
171
+ total
172
+ }
173
+ }
174
+ `,
175
+ variables: { filters, pagination: { page, limit }, sortings },
176
+ context: gqlContext(),
177
+ fetchPolicy: 'network-only'
178
+ });
179
+ const { items, total, failed } = listOutcome(pageFromResponse(response, 'accessRequests'));
180
+ this.failed = failed;
181
+ const t = i18next.t.bind(i18next);
182
+ return {
183
+ total,
184
+ records: items.map((item) => ({
185
+ ...item,
186
+ /* A pending row past its time is expired - the same reading the review makes. */
187
+ state: item.state === 'PENDING' && item.expiresAt && new Date(item.expiresAt).getTime() <= Date.now() ? 'EXPIRED' : item.state,
188
+ requesterName: item.requester?.name || item.requester?.email || '',
189
+ needed: privilegeWords(t, item.category, item.privilege),
190
+ deciderName: item.decidedBy?.name || '',
191
+ grantedRoleName: item.grantedRole?.name || ''
192
+ })).map((record) => ({ ...record, stateWords: t(`access-request.state.${record.state.toLowerCase()}`) }))
193
+ };
194
+ }
195
+ };
196
+ __decorate([
197
+ property({ type: Boolean }),
198
+ __metadata("design:type", Boolean)
199
+ ], AccessRequestsPage.prototype, "active", void 0);
200
+ __decorate([
201
+ property({ type: Object }),
202
+ __metadata("design:type", Object)
203
+ ], AccessRequestsPage.prototype, "config", void 0);
204
+ __decorate([
205
+ property({ type: String }),
206
+ __metadata("design:type", String)
207
+ ], AccessRequestsPage.prototype, "mode", void 0);
208
+ __decorate([
209
+ property({ type: Boolean }),
210
+ __metadata("design:type", Boolean)
211
+ ], AccessRequestsPage.prototype, "failed", void 0);
212
+ __decorate([
213
+ query('ox-grist'),
214
+ __metadata("design:type", Function)
215
+ ], AccessRequestsPage.prototype, "grist", void 0);
216
+ AccessRequestsPage = __decorate([
217
+ customElement('access-requests-page')
218
+ ], AccessRequestsPage);
219
+ export { AccessRequestsPage };
220
+ //# sourceMappingURL=access-requests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-requests.js","sourceRoot":"","sources":["../../../client/pages/access-request/access-requests.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist/ox-grist.js'\nimport '../../components/access-decision-popup.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport type { DataGrist, FetchOption } from '@operato/data-grist'\nimport { client, gqlContext } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\nimport { navigate, PageView } from '@operato/shell'\nimport { CommonHeaderStyles, CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\nimport { p13n } from '@operato/p13n'\n\nimport { privilegeWords } from '../../utils/access-request.js'\nimport { listOutcome, pageFromResponse } from '../../utils/list-result.js'\n\n/**\n * Who asked for what in this domain, and what became of it (ADR-0103).\n *\n * This list is where the people deciding receive requests - in every product, worklist or not. A\n * notification may point here; when none went out the request is here all the same. The rows are the\n * record and are never deleted: who decided, which role, why not.\n */\n@customElement('access-requests-page')\nexport class AccessRequestsPage extends p13n(localize(i18next)(PageView)) {\n static styles = [\n WorkSurfacePageStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n [failed] {\n padding: var(--spacing-medium);\n color: var(--md-sys-color-error);\n font: var(--label-font, inherit);\n }\n `\n ]\n\n @property({ type: Boolean }) active: boolean = false\n @property({ type: Object }) config: any\n @property({ type: String }) mode: 'CARD' | 'LIST' | 'GRID' = isMobileDevice() ? 'CARD' : 'GRID'\n @property({ type: Boolean }) failed: boolean = false\n\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('access-request.title.access requests'),\n help: 'auth/user',\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n actions: [{ title: i18next.t('text.users'), action: () => navigate('users'), icon: 'group' }]\n }\n }\n\n render() {\n return html`\n <ox-grist\n class=\"page-fill\"\n .mode=${this.mode}\n .config=${this.config}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')!}\n ></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 rows: { appendable: false, selectable: { multiple: false } },\n sorters: [{ name: 'createdAt', desc: true }],\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n /* Deciding means something only while it waits - offered only there. */\n {\n type: 'gutter',\n gutterName: 'button',\n icon: 'gavel',\n title: t('access-request.button.decide'),\n handlers: { click: (_c: any, _d: any, _col: any, record: any) => record?.state === 'PENDING' && this.decide(record) }\n },\n { type: 'string', name: 'requesterName', header: t('access-request.field.requester'), record: { editable: false }, width: 140 },\n { type: 'string', name: 'needed', header: t('access-request.field.needed'), record: { editable: false }, width: 260 },\n { type: 'string', name: 'reason', header: t('access-request.field.reason'), record: { editable: false }, filter: 'search', width: 200 },\n { type: 'string', name: 'stateWords', header: t('field.state'), record: { align: 'center', editable: false }, width: 100 },\n { type: 'integer', name: 'count', header: t('access-request.field.count'), record: { align: 'right', editable: false }, width: 70 },\n { type: 'datetime', name: 'createdAt', header: t('field.created at'), sortable: true, width: 170 },\n { type: 'string', name: 'deciderName', header: t('access-request.field.decided by'), record: { editable: false }, width: 140 },\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: 200 },\n { type: 'datetime', name: 'decidedAt', header: t('access-request.field.decided at'), sortable: true, width: 170 }\n ]\n }\n }\n\n private decide(record: any) {\n openPopup(\n html`<access-decision-popup .request=${record} @access-request-decided=${() => this.grist.fetch()}></access-decision-popup>`,\n { size: 'medium', title: i18next.t('access-request.title.decide') }\n )\n }\n\n async pageUpdated(_changes: any, lifecycle: any) {\n if (this.active) {\n await this.updateComplete\n this.grist.fetch()\n /* A notification links here with the request's id - its decision opens at once, if it still waits. */\n const id = lifecycle?.params?.id\n if (id && id !== this.opened) {\n this.opened = id\n await this.openById(id)\n }\n }\n }\n\n /** The request a link named, opened only while it waits - a decided one is just a row in the list. */\n private opened?: string\n\n private async openById(id: string) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!]) {\n accessRequests(filters: $filters) {\n items {\n id\n category\n privilege\n reason\n state\n requester {\n id\n name\n email\n }\n }\n }\n }\n `,\n variables: { filters: [{ name: 'id', operator: 'eq', value: id }] },\n context: gqlContext(),\n fetchPolicy: 'network-only'\n })\n const request = pageFromResponse(response, 'accessRequests')?.items?.[0]\n if (request?.state === 'PENDING') this.decide(request)\n }\n\n async fetchHandler({ page, limit, sortings = [], filters = [] }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n accessRequests(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n category\n privilege\n operationName\n reason\n count\n state\n expiresAt\n createdAt\n decidedAt\n decisionReason\n requester {\n id\n name\n email\n }\n decidedBy {\n id\n name\n }\n grantedRole {\n id\n name\n }\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings },\n context: gqlContext(),\n fetchPolicy: 'network-only'\n })\n\n const { items, total, failed } = listOutcome(pageFromResponse(response, 'accessRequests'))\n this.failed = failed\n const t = i18next.t.bind(i18next)\n\n return {\n total,\n records: items.map((item: any) => ({\n ...item,\n /* A pending row past its time is expired - the same reading the review makes. */\n state: item.state === 'PENDING' && item.expiresAt && new Date(item.expiresAt).getTime() <= Date.now() ? 'EXPIRED' : item.state,\n requesterName: item.requester?.name || item.requester?.email || '',\n needed: privilegeWords(t, item.category, item.privilege),\n deciderName: item.decidedBy?.name || '',\n grantedRoleName: item.grantedRole?.name || ''\n })).map((record: any) => ({ ...record, stateWords: t(`access-request.state.${record.state.toLowerCase()}`) }))\n }\n }\n}\n"]}
@@ -0,0 +1,26 @@
1
+ import '@operato/data-grist/ox-grist.js';
2
+ import { PageView } from '@operato/shell';
3
+ declare const MyAccessRequestsPage_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
4
+ /**
5
+ * The person's own access requests - what became of each (ADR-0103). A notification may not reach them;
6
+ * this does.
7
+ */
8
+ export declare class MyAccessRequestsPage extends MyAccessRequestsPage_base {
9
+ static styles: import("lit").CSSResult[];
10
+ active: boolean;
11
+ config: any;
12
+ failed: boolean;
13
+ private grist;
14
+ get context(): {
15
+ title: string;
16
+ };
17
+ render(): import("lit-html").TemplateResult<1>;
18
+ pageInitialized(): Promise<void>;
19
+ pageUpdated(_changes: any, _lifecycle: any): Promise<void>;
20
+ private withdraw;
21
+ fetchHandler(): Promise<{
22
+ total: number;
23
+ records: any[];
24
+ }>;
25
+ }
26
+ export {};
@@ -0,0 +1,151 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@operato/data-grist/ox-grist.js';
3
+ import gql from 'graphql-tag';
4
+ import { css, html } from 'lit';
5
+ import { customElement, property, query } from 'lit/decorators.js';
6
+ import { client, gqlContext } from '@operato/graphql';
7
+ import { i18next, localize } from '@operato/i18n';
8
+ import { OxPrompt } from '@operato/popup/ox-prompt.js';
9
+ import { PageView } from '@operato/shell';
10
+ import { CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
11
+ import { isMobileDevice } from '@operato/utils';
12
+ import { privilegeWords } from '../../utils/access-request.js';
13
+ import { arrayFromResponse, listOutcome } from '../../utils/list-result.js';
14
+ /**
15
+ * The person's own access requests - what became of each (ADR-0103). A notification may not reach them;
16
+ * this does.
17
+ */
18
+ let MyAccessRequestsPage = class MyAccessRequestsPage extends localize(i18next)(PageView) {
19
+ constructor() {
20
+ super(...arguments);
21
+ this.active = false;
22
+ this.failed = false;
23
+ }
24
+ static { this.styles = [
25
+ WorkSurfacePageStyles,
26
+ CommonGristStyles,
27
+ ScrollbarStyles,
28
+ css `
29
+ [failed] {
30
+ padding: var(--spacing-medium);
31
+ color: var(--md-sys-color-error);
32
+ }
33
+ `
34
+ ]; }
35
+ get context() {
36
+ return { title: i18next.t('access-request.title.my access requests') };
37
+ }
38
+ render() {
39
+ return html `
40
+ <ox-grist class="page-fill" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.config} .fetchHandler=${this.fetchHandler.bind(this)}></ox-grist>
41
+ ${this.failed ? html `<div failed>${i18next.t('text.the list could not be loaded')}</div>` : ''}
42
+ `;
43
+ }
44
+ async pageInitialized() {
45
+ const t = i18next.t.bind(i18next);
46
+ this.config = {
47
+ pagination: { infinite: true },
48
+ rows: { appendable: false, selectable: false },
49
+ columns: [
50
+ {
51
+ type: 'gutter',
52
+ gutterName: 'button',
53
+ icon: 'undo',
54
+ title: t('access-request.button.withdraw'),
55
+ handlers: { click: (_c, _d, _col, record) => record?.state === 'PENDING' && this.withdraw(record) }
56
+ },
57
+ { type: 'string', name: 'needed', header: t('access-request.field.needed'), record: { editable: false }, width: 260 },
58
+ { type: 'string', name: 'stateWords', header: t('field.state'), record: { align: 'center', editable: false }, width: 100 },
59
+ { type: 'string', name: 'grantedRoleName', header: t('access-request.field.granted role'), record: { editable: false }, width: 140 },
60
+ { type: 'string', name: 'decisionReason', header: t('access-request.field.decision reason'), record: { editable: false }, width: 220 },
61
+ { type: 'datetime', name: 'createdAt', header: t('field.created at'), width: 170 }
62
+ ]
63
+ };
64
+ }
65
+ async pageUpdated(_changes, _lifecycle) {
66
+ if (this.active) {
67
+ await this.updateComplete;
68
+ this.grist.fetch();
69
+ }
70
+ }
71
+ async withdraw(record) {
72
+ const confirmed = await OxPrompt.open({
73
+ type: 'warning',
74
+ title: i18next.t('access-request.button.withdraw'),
75
+ text: record.needed,
76
+ confirmButton: { text: i18next.t('access-request.button.withdraw') },
77
+ cancelButton: { text: i18next.t('button.cancel') }
78
+ });
79
+ if (!confirmed)
80
+ return;
81
+ await client.mutate({
82
+ mutation: gql `
83
+ mutation ($id: String!) {
84
+ withdrawAccessRequest(id: $id) {
85
+ id
86
+ }
87
+ }
88
+ `,
89
+ variables: { id: record.id },
90
+ context: gqlContext()
91
+ });
92
+ this.grist.fetch();
93
+ }
94
+ async fetchHandler() {
95
+ const response = await client.query({
96
+ query: gql `
97
+ query {
98
+ myAccessRequests {
99
+ id
100
+ category
101
+ privilege
102
+ state
103
+ expiresAt
104
+ createdAt
105
+ decisionReason
106
+ grantedRole {
107
+ name
108
+ }
109
+ }
110
+ }
111
+ `,
112
+ context: gqlContext(),
113
+ fetchPolicy: 'network-only'
114
+ });
115
+ const { items, failed } = listOutcome(arrayFromResponse(response, 'myAccessRequests'));
116
+ this.failed = failed;
117
+ const t = i18next.t.bind(i18next);
118
+ const records = items.map((item) => {
119
+ const state = item.state === 'PENDING' && item.expiresAt && new Date(item.expiresAt).getTime() <= Date.now() ? 'EXPIRED' : item.state;
120
+ return {
121
+ ...item,
122
+ state,
123
+ stateWords: t(`access-request.state.${state.toLowerCase()}`),
124
+ needed: privilegeWords(t, item.category, item.privilege),
125
+ grantedRoleName: item.grantedRole?.name || ''
126
+ };
127
+ });
128
+ return { total: records.length, records };
129
+ }
130
+ };
131
+ __decorate([
132
+ property({ type: Boolean }),
133
+ __metadata("design:type", Boolean)
134
+ ], MyAccessRequestsPage.prototype, "active", void 0);
135
+ __decorate([
136
+ property({ type: Object }),
137
+ __metadata("design:type", Object)
138
+ ], MyAccessRequestsPage.prototype, "config", void 0);
139
+ __decorate([
140
+ property({ type: Boolean }),
141
+ __metadata("design:type", Boolean)
142
+ ], MyAccessRequestsPage.prototype, "failed", void 0);
143
+ __decorate([
144
+ query('ox-grist'),
145
+ __metadata("design:type", Function)
146
+ ], MyAccessRequestsPage.prototype, "grist", void 0);
147
+ MyAccessRequestsPage = __decorate([
148
+ customElement('my-access-requests-page')
149
+ ], MyAccessRequestsPage);
150
+ export { MyAccessRequestsPage };
151
+ //# sourceMappingURL=my-access-requests.js.map
@@ -0,0 +1 @@
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 { privilegeWords } 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 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: privilegeWords(t, item.category, item.privilege),\n grantedRoleName: item.grantedRole?.name || ''\n }\n })\n return { total: records.length, records }\n }\n}\n"]}
@@ -48,6 +48,12 @@ export default function route(page) {
48
48
  case 'domain-links':
49
49
  import('./pages/domain-link/domain-link-management.js');
50
50
  return page;
51
+ case 'access-requests':
52
+ import('./pages/access-request/access-requests.js');
53
+ return page;
54
+ case 'my-access-requests':
55
+ import('./pages/access-request/my-access-requests.js');
56
+ return page;
51
57
  }
52
58
  }
53
59
  //# sourceMappingURL=route.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"route.js","sourceRoot":"","sources":["../client/route.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAI;IAChC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,MAAM;YACJ,2BAA2B;YAC3B,iCAAiC;YACjC,oBAAoB,CACrB,CAAA;YACD,OAAO,IAAI,CAAA;QAEb,KAAK,cAAc;YACjB,MAAM,CAAC,kCAAkC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QAEb,KAAK,cAAc;YACjB,MAAM,CAAC,kCAAkC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QAEb,KAAK,gBAAgB;YACnB,MAAM,CAAC,wBAAwB,CAAC,CAAA;YAChC,OAAO,IAAI,CAAA;QAEb,KAAK,OAAO;YACV,MAAM,CAAC,6BAA6B,CAAC,CAAA;YACrC,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,kCAAkC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QAEb,KAAK,OAAO;YACV,MAAM,CAAC,6BAA6B,CAAC,CAAA;YACrC,OAAO,IAAI,CAAA;QAEb,KAAK,aAAa;YAChB,MAAM,CAAC,gCAAgC,CAAC,CAAA;YACxC,OAAO,IAAI,CAAA;QAEb,KAAK,UAAU;YACb,MAAM,CAAC,oCAAoC,CAAC,CAAA;YAC5C,OAAO,IAAI,CAAA;QAEb,KAAK,SAAS;YACZ,MAAM,CAAC,kCAAkC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QAEb,KAAK,eAAe;YAClB,MAAM,CAAC,8CAA8C,CAAC,CAAA;YACtD,OAAO,IAAI,CAAA;QAEb,KAAK,UAAU;YACb,MAAM,CAAC,mCAAmC,CAAC,CAAA;YAC3C,OAAO,IAAI,CAAA;QAEb,KAAK,YAAY;YACf,MAAM,CAAC,+CAA+C,CAAC,CAAA;YACvD,OAAO,IAAI,CAAA;QAEb,KAAK,gBAAgB;YACnB,MAAM,CAAC,mDAAmD,CAAC,CAAA;YAC3D,OAAO,IAAI,CAAA;QAEb,KAAK,cAAc;YACjB,MAAM,CAAC,+CAA+C,CAAC,CAAA;YACvD,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC","sourcesContent":["export default function route(page) {\n switch (page) {\n case 'profile':\n import(\n /* webpackPrefetch: true */\n /* webpackChunkName: \"profile\" */\n './pages/profile.js'\n )\n return page\n\n case 'applications':\n import('./pages/application/applications')\n return page\n\n case 'app-bindings':\n import('./pages/app-binding/app-bindings')\n return page\n\n case 'appliance-home':\n import('./pages/appliance/home')\n return page\n\n case 'roles':\n import('./pages/role/role-list-page')\n return page\n\n case 'role-privileges':\n import('./pages/role/role-privilege-page')\n return page\n\n case 'users':\n import('./pages/user/user-list-page')\n return page\n\n case 'invitations':\n import('./pages/invitation/invitations')\n return page\n\n case 'partners':\n import('./pages/partner/partner-management')\n return page\n\n case 'domains':\n import('./pages/domain/domain-management')\n return page\n\n case 'domain-owners':\n import('./pages/domain-owner/domain-owner-management')\n return page\n\n case 'env-vars':\n import('./pages/env-var/env-var-list-page')\n return page\n\n case 'attributes':\n import('./pages/attribute/attribute-set-management.js')\n return page\n\n case 'auth-providers':\n import('./pages/auth-provider/auth-provider-management.js')\n return page\n\n case 'domain-links':\n import('./pages/domain-link/domain-link-management.js')\n return page\n }\n}\n"]}
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../client/route.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAI;IAChC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,MAAM;YACJ,2BAA2B;YAC3B,iCAAiC;YACjC,oBAAoB,CACrB,CAAA;YACD,OAAO,IAAI,CAAA;QAEb,KAAK,cAAc;YACjB,MAAM,CAAC,kCAAkC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QAEb,KAAK,cAAc;YACjB,MAAM,CAAC,kCAAkC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QAEb,KAAK,gBAAgB;YACnB,MAAM,CAAC,wBAAwB,CAAC,CAAA;YAChC,OAAO,IAAI,CAAA;QAEb,KAAK,OAAO;YACV,MAAM,CAAC,6BAA6B,CAAC,CAAA;YACrC,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,kCAAkC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QAEb,KAAK,OAAO;YACV,MAAM,CAAC,6BAA6B,CAAC,CAAA;YACrC,OAAO,IAAI,CAAA;QAEb,KAAK,aAAa;YAChB,MAAM,CAAC,gCAAgC,CAAC,CAAA;YACxC,OAAO,IAAI,CAAA;QAEb,KAAK,UAAU;YACb,MAAM,CAAC,oCAAoC,CAAC,CAAA;YAC5C,OAAO,IAAI,CAAA;QAEb,KAAK,SAAS;YACZ,MAAM,CAAC,kCAAkC,CAAC,CAAA;YAC1C,OAAO,IAAI,CAAA;QAEb,KAAK,eAAe;YAClB,MAAM,CAAC,8CAA8C,CAAC,CAAA;YACtD,OAAO,IAAI,CAAA;QAEb,KAAK,UAAU;YACb,MAAM,CAAC,mCAAmC,CAAC,CAAA;YAC3C,OAAO,IAAI,CAAA;QAEb,KAAK,YAAY;YACf,MAAM,CAAC,+CAA+C,CAAC,CAAA;YACvD,OAAO,IAAI,CAAA;QAEb,KAAK,gBAAgB;YACnB,MAAM,CAAC,mDAAmD,CAAC,CAAA;YAC3D,OAAO,IAAI,CAAA;QAEb,KAAK,cAAc;YACjB,MAAM,CAAC,+CAA+C,CAAC,CAAA;YACvD,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,2CAA2C,CAAC,CAAA;YACnD,OAAO,IAAI,CAAA;QAEb,KAAK,oBAAoB;YACvB,MAAM,CAAC,8CAA8C,CAAC,CAAA;YACtD,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC","sourcesContent":["export default function route(page) {\n switch (page) {\n case 'profile':\n import(\n /* webpackPrefetch: true */\n /* webpackChunkName: \"profile\" */\n './pages/profile.js'\n )\n return page\n\n case 'applications':\n import('./pages/application/applications')\n return page\n\n case 'app-bindings':\n import('./pages/app-binding/app-bindings')\n return page\n\n case 'appliance-home':\n import('./pages/appliance/home')\n return page\n\n case 'roles':\n import('./pages/role/role-list-page')\n return page\n\n case 'role-privileges':\n import('./pages/role/role-privilege-page')\n return page\n\n case 'users':\n import('./pages/user/user-list-page')\n return page\n\n case 'invitations':\n import('./pages/invitation/invitations')\n return page\n\n case 'partners':\n import('./pages/partner/partner-management')\n return page\n\n case 'domains':\n import('./pages/domain/domain-management')\n return page\n\n case 'domain-owners':\n import('./pages/domain-owner/domain-owner-management')\n return page\n\n case 'env-vars':\n import('./pages/env-var/env-var-list-page')\n return page\n\n case 'attributes':\n import('./pages/attribute/attribute-set-management.js')\n return page\n\n case 'auth-providers':\n import('./pages/auth-provider/auth-provider-management.js')\n return page\n\n case 'domain-links':\n import('./pages/domain-link/domain-link-management.js')\n return page\n\n case 'access-requests':\n import('./pages/access-request/access-requests.js')\n return page\n\n case 'my-access-requests':\n import('./pages/access-request/my-access-requests.js')\n return page\n }\n}\n"]}