@things-factory/auth-ui 10.1.46 → 10.1.79
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/bootstrap.js +3 -0
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/entity360/person-360.d.ts +22 -0
- package/dist-client/entity360/person-360.js +98 -0
- package/dist-client/entity360/person-360.js.map +1 -0
- package/dist-client/tsconfig.chk.tsbuildinfo +1 -0
- package/dist-client/tsconfig.p360.tsbuildinfo +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/tests/person-360-sections.test.ts +85 -0
- package/translations/en.json +0 -15
- package/translations/ja.json +69 -13
- package/translations/ko.json +0 -14
- package/translations/ms.json +71 -16
- package/translations/zh.json +69 -14
package/dist-client/bootstrap.js
CHANGED
|
@@ -9,7 +9,10 @@ import { OxGristEditorPrivilege } from '@operato/app/grist-editor/ox-grist-edito
|
|
|
9
9
|
import { registerEditor as registerGristEditor, registerRenderer as registerGristRenderer, OxGristRendererJson5 } from '@operato/data-grist';
|
|
10
10
|
import { auth } from '@things-factory/auth-base/dist-client/auth.js';
|
|
11
11
|
import { ADD_MORENDA } from '@things-factory/more-base/client';
|
|
12
|
+
import { registerPersonKind } from './entity360/person-360.js';
|
|
12
13
|
export default async function bootstrap() {
|
|
14
|
+
/* the person 360 - a User value anywhere opens it (ADR-0067) */
|
|
15
|
+
registerPersonKind();
|
|
13
16
|
registerGristEditor('privilege', OxGristEditorPrivilege);
|
|
14
17
|
registerGristRenderer('privilege', OxGristRendererJson5);
|
|
15
18
|
/* add user profile morenda */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,0BAA0B,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,iCAAiC,CAAA,CAAC,sDAAsD;AAE/F,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAE/B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,wDAAwD,CAAA;AAC/F,OAAO,EACL,cAAc,IAAI,mBAAmB,EACrC,gBAAgB,IAAI,qBAAqB,EACzC,oBAAoB,EACrB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,IAAI,EAAE,MAAM,+CAA+C,CAAA;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAE9D,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,SAAS;IACrC,mBAAmB,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAA;IACxD,qBAAqB,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAA;IAExD,8BAA8B;IAC9B,KAAK,CAAC,QAAQ,CAAC;QACb,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE;YACP,IAAI,EAAE,IAAI,CAAA,qCAAqC;YAC/C,IAAI,EAAE,IAAI,CAAA,iDAAiD;YAC3D,QAAQ,EAAE,aAAa,CAAC,SAAS;YACjC,MAAM,EAAE,GAAG,EAAE;gBACX,QAAQ,CAAC,SAAS,CAAC,CAAA;YACrB,CAAC;SACF;KACF,CAAC,CAAA;IAEF,0BAA0B;IAC1B,KAAK,CAAC,QAAQ,CAAC;QACb,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE;YACP,IAAI,EAAE,IAAI,CAAA,kCAAkC;YAC5C,IAAI,EAAE,IAAI,CAAA,8CAA8C;YACxD,QAAQ,EAAE,aAAa,CAAC,SAAS;YACjC,MAAM,EAAE,GAAG,EAAE;gBACX,IAAI,CAAC;oBACH,IAAI,OAAO,YAAY,KAAK,WAAW,EAAE,CAAC;wBACxC,YAAY,CAAC,UAAU,CAAC,YAAY,CAAC,CAAA;wBACrC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;oBACpC,CAAC;oBAED,CAAC;oBAAA,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;wBACxC,IAAI,CAAC;4BACH,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,mDAAmD,CAAA;wBAC9E,CAAC;wBAAC,OAAO,CAAC,EAAE,CAAC;4BACX,SAAS;wBACX,CAAC;oBACH,CAAC,CAAC,CAAA;gBACJ,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,SAAS;gBACX,CAAC;gBAED,IAAI,CAAC,OAAO,EAAE,CAAA;YAChB,CAAC;SACF;KACF,CAAC,CAAA;IAEF,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;QACpC,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;YACpC,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;QAC3C,CAAC;IACH,CAAC,CAAC,CAAA;IAEF;;;;MAIE;IACF,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;AACtB,CAAC","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/i18n/ox-i18n.js'\nimport { i18next } from '@operato/i18n'\nimport '@operato/attribute/grist-editor' /* for register data-grist editor type 'attributes' */\n\nimport { html } from 'lit-html'\n\nimport { navigate, store } from '@operato/shell'\nimport { TOOL_POSITION } from '@operato/layout'\nimport { OxGristEditorPrivilege } from '@operato/app/grist-editor/ox-grist-editor-privilege.js'\nimport {\n registerEditor as registerGristEditor,\n registerRenderer as registerGristRenderer,\n OxGristRendererJson5\n} from '@operato/data-grist'\n\nimport { auth } from '@things-factory/auth-base/dist-client/auth.js'\nimport { ADD_MORENDA } from '@things-factory/more-base/client'\n\nexport default async function bootstrap() {\n registerGristEditor('privilege', OxGristEditorPrivilege)\n registerGristRenderer('privilege', OxGristRendererJson5)\n\n /* add user profile morenda */\n store.dispatch({\n type: ADD_MORENDA,\n morenda: {\n icon: html` <md-icon>account_circle</md-icon> `,\n name: html` <ox-i18n msgid=\"text.auth profile\"></ox-i18n> `,\n position: TOOL_POSITION.FRONT_END,\n action: () => {\n navigate('profile')\n }\n }\n })\n\n /* add sign-out morenda */\n store.dispatch({\n type: ADD_MORENDA,\n morenda: {\n icon: html` <md-icon>exit_to_app</md-icon> `,\n name: html` <ox-i18n msgid=\"field.sign out\"></ox-i18n> `,\n position: TOOL_POSITION.FRONT_END,\n action: () => {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem('i18nextLng')\n localStorage.removeItem('i18next')\n }\n\n ;['i18next', 'i18nextLng'].forEach(name => {\n try {\n document.cookie = `${name}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT;`\n } catch (e) {\n // ignore\n }\n })\n } catch (e) {\n // ignore\n }\n\n auth.signout()\n }\n }\n })\n\n auth.on('profile', ({ credential }) => {\n if (credential && credential.locale) {\n i18next.changeLanguage(credential.locale)\n }\n })\n\n /* \n Get user profile information from server. \n As soon as response received, auth.on('profile', ...) handlers start to work.\n It's very important point to build UI for the user.\n */\n await auth.profile()\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,0BAA0B,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,iCAAiC,CAAA,CAAC,sDAAsD;AAE/F,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAE/B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,wDAAwD,CAAA;AAC/F,OAAO,EACL,cAAc,IAAI,mBAAmB,EACrC,gBAAgB,IAAI,qBAAqB,EACzC,oBAAoB,EACrB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,IAAI,EAAE,MAAM,+CAA+C,CAAA;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAE9D,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,SAAS;IACrC,gEAAgE;IAChE,kBAAkB,EAAE,CAAA;IAEpB,mBAAmB,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAA;IACxD,qBAAqB,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAA;IAExD,8BAA8B;IAC9B,KAAK,CAAC,QAAQ,CAAC;QACb,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE;YACP,IAAI,EAAE,IAAI,CAAA,qCAAqC;YAC/C,IAAI,EAAE,IAAI,CAAA,iDAAiD;YAC3D,QAAQ,EAAE,aAAa,CAAC,SAAS;YACjC,MAAM,EAAE,GAAG,EAAE;gBACX,QAAQ,CAAC,SAAS,CAAC,CAAA;YACrB,CAAC;SACF;KACF,CAAC,CAAA;IAEF,0BAA0B;IAC1B,KAAK,CAAC,QAAQ,CAAC;QACb,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE;YACP,IAAI,EAAE,IAAI,CAAA,kCAAkC;YAC5C,IAAI,EAAE,IAAI,CAAA,8CAA8C;YACxD,QAAQ,EAAE,aAAa,CAAC,SAAS;YACjC,MAAM,EAAE,GAAG,EAAE;gBACX,IAAI,CAAC;oBACH,IAAI,OAAO,YAAY,KAAK,WAAW,EAAE,CAAC;wBACxC,YAAY,CAAC,UAAU,CAAC,YAAY,CAAC,CAAA;wBACrC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;oBACpC,CAAC;oBAED,CAAC;oBAAA,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;wBACxC,IAAI,CAAC;4BACH,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,mDAAmD,CAAA;wBAC9E,CAAC;wBAAC,OAAO,CAAC,EAAE,CAAC;4BACX,SAAS;wBACX,CAAC;oBACH,CAAC,CAAC,CAAA;gBACJ,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,SAAS;gBACX,CAAC;gBAED,IAAI,CAAC,OAAO,EAAE,CAAA;YAChB,CAAC;SACF;KACF,CAAC,CAAA;IAEF,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;QACpC,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;YACpC,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;QAC3C,CAAC;IACH,CAAC,CAAC,CAAA;IAEF;;;;MAIE;IACF,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;AACtB,CAAC","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/i18n/ox-i18n.js'\nimport { i18next } from '@operato/i18n'\nimport '@operato/attribute/grist-editor' /* for register data-grist editor type 'attributes' */\n\nimport { html } from 'lit-html'\n\nimport { navigate, store } from '@operato/shell'\nimport { TOOL_POSITION } from '@operato/layout'\nimport { OxGristEditorPrivilege } from '@operato/app/grist-editor/ox-grist-editor-privilege.js'\nimport {\n registerEditor as registerGristEditor,\n registerRenderer as registerGristRenderer,\n OxGristRendererJson5\n} from '@operato/data-grist'\n\nimport { auth } from '@things-factory/auth-base/dist-client/auth.js'\nimport { ADD_MORENDA } from '@things-factory/more-base/client'\nimport { registerPersonKind } from './entity360/person-360.js'\n\nexport default async function bootstrap() {\n /* the person 360 - a User value anywhere opens it (ADR-0067) */\n registerPersonKind()\n\n registerGristEditor('privilege', OxGristEditorPrivilege)\n registerGristRenderer('privilege', OxGristRendererJson5)\n\n /* add user profile morenda */\n store.dispatch({\n type: ADD_MORENDA,\n morenda: {\n icon: html` <md-icon>account_circle</md-icon> `,\n name: html` <ox-i18n msgid=\"text.auth profile\"></ox-i18n> `,\n position: TOOL_POSITION.FRONT_END,\n action: () => {\n navigate('profile')\n }\n }\n })\n\n /* add sign-out morenda */\n store.dispatch({\n type: ADD_MORENDA,\n morenda: {\n icon: html` <md-icon>exit_to_app</md-icon> `,\n name: html` <ox-i18n msgid=\"field.sign out\"></ox-i18n> `,\n position: TOOL_POSITION.FRONT_END,\n action: () => {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem('i18nextLng')\n localStorage.removeItem('i18next')\n }\n\n ;['i18next', 'i18nextLng'].forEach(name => {\n try {\n document.cookie = `${name}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT;`\n } catch (e) {\n // ignore\n }\n })\n } catch (e) {\n // ignore\n }\n\n auth.signout()\n }\n }\n })\n\n auth.on('profile', ({ credential }) => {\n if (credential && credential.locale) {\n i18next.changeLanguage(credential.locale)\n }\n })\n\n /* \n Get user profile information from server. \n As soon as response received, auth.on('profile', ...) handlers start to work.\n It's very important point to build UI for the user.\n */\n await auth.profile()\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { type Entity360DoorAnswer, type Entity360Subject } from '@operato/layout';
|
|
3
|
+
/**
|
|
4
|
+
* The person 360 (ADR-0067, design/ui/entity360-person.md): a `User` value anywhere - a grid's
|
|
5
|
+
* `updater`, a request's author - opens it. auth-ui declares the kind because the account is its
|
|
6
|
+
* fact; organization and worklist hang their own sections on it with their own doors.
|
|
7
|
+
*
|
|
8
|
+
* This section is identity and the roles held on this site. `userRoles` answers this domain's roles
|
|
9
|
+
* only (and its parent's) - `User.roles` answers every domain's and must not be used here.
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerPersonKind(): void;
|
|
12
|
+
export declare class PersonRolesSection extends LitElement {
|
|
13
|
+
static styles: import("lit").CSSResult;
|
|
14
|
+
subject?: Entity360Subject;
|
|
15
|
+
answer?: Entity360DoorAnswer<{
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
}[]>;
|
|
19
|
+
updated(changed: Map<string, unknown>): void;
|
|
20
|
+
private read;
|
|
21
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import gql from 'graphql-tag';
|
|
3
|
+
import { css, html, LitElement } from 'lit';
|
|
4
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
5
|
+
import { client } from '@operato/graphql';
|
|
6
|
+
import { i18next } from '@operato/i18n';
|
|
7
|
+
import { readEntity360Door, registerEntity360Kind, registerEntity360Section } from '@operato/layout';
|
|
8
|
+
/**
|
|
9
|
+
* The person 360 (ADR-0067, design/ui/entity360-person.md): a `User` value anywhere - a grid's
|
|
10
|
+
* `updater`, a request's author - opens it. auth-ui declares the kind because the account is its
|
|
11
|
+
* fact; organization and worklist hang their own sections on it with their own doors.
|
|
12
|
+
*
|
|
13
|
+
* This section is identity and the roles held on this site. `userRoles` answers this domain's roles
|
|
14
|
+
* only (and its parent's) - `User.roles` answers every domain's and must not be used here.
|
|
15
|
+
*/
|
|
16
|
+
export function registerPersonKind() {
|
|
17
|
+
registerEntity360Kind({
|
|
18
|
+
kind: 'person',
|
|
19
|
+
typenames: ['User'],
|
|
20
|
+
title: ({ value }) => value.name || value.email || '',
|
|
21
|
+
context: ({ value }) => (value.name && value.email ? value.email : '')
|
|
22
|
+
});
|
|
23
|
+
registerEntity360Section('person', {
|
|
24
|
+
name: 'roles',
|
|
25
|
+
order: 30,
|
|
26
|
+
render: subject => html `<person-roles-section .subject=${subject}></person-roles-section>`
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
let PersonRolesSection = class PersonRolesSection extends LitElement {
|
|
30
|
+
static { this.styles = css `
|
|
31
|
+
ul {
|
|
32
|
+
margin: 0;
|
|
33
|
+
padding: 0;
|
|
34
|
+
list-style: none;
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-wrap: wrap;
|
|
37
|
+
gap: 6px;
|
|
38
|
+
}
|
|
39
|
+
li {
|
|
40
|
+
padding: 2px 8px;
|
|
41
|
+
border-radius: var(--md-sys-shape-corner-small, 8px);
|
|
42
|
+
background: var(--md-sys-color-surface-container-high);
|
|
43
|
+
color: var(--md-sys-color-on-surface);
|
|
44
|
+
font: 13px/1.5 sans-serif;
|
|
45
|
+
}
|
|
46
|
+
`; }
|
|
47
|
+
updated(changed) {
|
|
48
|
+
if (changed.has('subject'))
|
|
49
|
+
this.read();
|
|
50
|
+
}
|
|
51
|
+
async read() {
|
|
52
|
+
const id = this.subject?.id;
|
|
53
|
+
this.answer = undefined;
|
|
54
|
+
if (!id)
|
|
55
|
+
return;
|
|
56
|
+
const response = await client.query({
|
|
57
|
+
query: gql `
|
|
58
|
+
query ($userId: String!) {
|
|
59
|
+
userRoles(userId: $userId) {
|
|
60
|
+
id
|
|
61
|
+
name
|
|
62
|
+
assigned
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
`,
|
|
66
|
+
variables: { userId: id }
|
|
67
|
+
});
|
|
68
|
+
/* A later subject may have arrived while this one was being read. */
|
|
69
|
+
if (this.subject?.id !== id)
|
|
70
|
+
return;
|
|
71
|
+
this.answer = readEntity360Door(response, data => (data?.userRoles || []).filter((role) => role.assigned));
|
|
72
|
+
}
|
|
73
|
+
render() {
|
|
74
|
+
const answer = this.answer;
|
|
75
|
+
return html `<ox-entity360-section
|
|
76
|
+
.heading=${i18next.t('field.roles', { defaultValue: 'roles' })}
|
|
77
|
+
.state=${answer?.state ?? 'loading'}
|
|
78
|
+
.message=${answer?.message ?? ''}
|
|
79
|
+
>
|
|
80
|
+
<ul>
|
|
81
|
+
${(answer?.data || []).map(role => html `<li>${role.name}</li>`)}
|
|
82
|
+
</ul>
|
|
83
|
+
</ox-entity360-section>`;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
__decorate([
|
|
87
|
+
property({ attribute: false }),
|
|
88
|
+
__metadata("design:type", Object)
|
|
89
|
+
], PersonRolesSection.prototype, "subject", void 0);
|
|
90
|
+
__decorate([
|
|
91
|
+
state(),
|
|
92
|
+
__metadata("design:type", Object)
|
|
93
|
+
], PersonRolesSection.prototype, "answer", void 0);
|
|
94
|
+
PersonRolesSection = __decorate([
|
|
95
|
+
customElement('person-roles-section')
|
|
96
|
+
], PersonRolesSection);
|
|
97
|
+
export { PersonRolesSection };
|
|
98
|
+
//# sourceMappingURL=person-360.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"person-360.js","sourceRoot":"","sources":["../../client/entity360/person-360.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport {\n readEntity360Door,\n registerEntity360Kind,\n registerEntity360Section,\n type Entity360DoorAnswer,\n type Entity360Subject\n} from '@operato/layout'\n\n/**\n * The person 360 (ADR-0067, design/ui/entity360-person.md): a `User` value anywhere - a grid's\n * `updater`, a request's author - opens it. auth-ui declares the kind because the account is its\n * fact; organization and worklist hang their own sections on it with their own doors.\n *\n * This section is identity and the roles held on this site. `userRoles` answers this domain's roles\n * only (and its parent's) - `User.roles` answers every domain's and must not be used here.\n */\n\nexport function registerPersonKind() {\n registerEntity360Kind({\n kind: 'person',\n typenames: ['User'],\n title: ({ value }) => value.name || value.email || '',\n context: ({ value }) => (value.name && value.email ? value.email : '')\n })\n\n registerEntity360Section('person', {\n name: 'roles',\n order: 30,\n render: subject => html`<person-roles-section .subject=${subject}></person-roles-section>`\n })\n}\n\n@customElement('person-roles-section')\nexport class PersonRolesSection extends LitElement {\n static styles = css`\n ul {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n li {\n padding: 2px 8px;\n border-radius: var(--md-sys-shape-corner-small, 8px);\n background: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface);\n font: 13px/1.5 sans-serif;\n }\n `\n\n @property({ attribute: false }) subject?: Entity360Subject\n @state() answer?: Entity360DoorAnswer<{ id: string; name: string }[]>\n\n updated(changed: Map<string, unknown>) {\n if (changed.has('subject')) this.read()\n }\n\n private async read() {\n const id = this.subject?.id\n this.answer = undefined\n if (!id) return\n\n const response = await client.query({\n query: gql`\n query ($userId: String!) {\n userRoles(userId: $userId) {\n id\n name\n assigned\n }\n }\n `,\n variables: { userId: id }\n })\n\n /* A later subject may have arrived while this one was being read. */\n if (this.subject?.id !== id) return\n this.answer = readEntity360Door(response, data => (data?.userRoles || []).filter((role: any) => role.assigned))\n }\n\n render() {\n const answer = this.answer\n return html`<ox-entity360-section\n .heading=${i18next.t('field.roles', { defaultValue: 'roles' })}\n .state=${answer?.state ?? 'loading'}\n .message=${answer?.message ?? ''}\n >\n <ul>\n ${(answer?.data || []).map(role => html`<li>${role.name}</li>`)}\n </ul>\n </ox-entity360-section>`\n }\n}\n"]}
|