@things-factory/auth-ui 10.1.256 → 10.1.258

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 (83) hide show
  1. package/dist-client/bootstrap.js +2 -2
  2. package/dist-client/bootstrap.js.map +1 -1
  3. package/dist-client/components/access-decision-popup.d.ts +9 -8
  4. package/dist-client/components/access-decision-popup.js +46 -58
  5. package/dist-client/components/access-decision-popup.js.map +1 -1
  6. package/dist-client/components/access-request-popup.d.ts +13 -8
  7. package/dist-client/components/access-request-popup.js +78 -102
  8. package/dist-client/components/access-request-popup.js.map +1 -1
  9. package/dist-client/components/app-binding-detail.d.ts +7 -5
  10. package/dist-client/components/app-binding-detail.js +62 -82
  11. package/dist-client/components/app-binding-detail.js.map +1 -1
  12. package/dist-client/components/appliance-editor.d.ts +10 -9
  13. package/dist-client/components/appliance-editor.js +87 -138
  14. package/dist-client/components/appliance-editor.js.map +1 -1
  15. package/dist-client/components/application-editor.d.ts +7 -5
  16. package/dist-client/components/application-editor.js +58 -92
  17. package/dist-client/components/application-editor.js.map +1 -1
  18. package/dist-client/components/my-login-history.js +18 -40
  19. package/dist-client/components/my-login-history.js.map +1 -1
  20. package/dist-client/components/my-passkeys.d.ts +4 -3
  21. package/dist-client/components/my-passkeys.js +29 -51
  22. package/dist-client/components/my-passkeys.js.map +1 -1
  23. package/dist-client/components/my-roles.d.ts +3 -4
  24. package/dist-client/components/my-roles.js +36 -55
  25. package/dist-client/components/my-roles.js.map +1 -1
  26. package/dist-client/components/partner-role-editor.js +27 -50
  27. package/dist-client/components/partner-role-editor.js.map +1 -1
  28. package/dist-client/components/profile-component.d.ts +2 -2
  29. package/dist-client/components/profile-component.js +18 -26
  30. package/dist-client/components/profile-component.js.map +1 -1
  31. package/dist-client/components/role-template-picker.d.ts +3 -3
  32. package/dist-client/components/role-template-picker.js +28 -42
  33. package/dist-client/components/role-template-picker.js.map +1 -1
  34. package/dist-client/components/user-detail.d.ts +23 -22
  35. package/dist-client/components/user-detail.js +125 -179
  36. package/dist-client/components/user-detail.js.map +1 -1
  37. package/dist-client/components/user-invite.d.ts +8 -6
  38. package/dist-client/components/user-invite.js +106 -141
  39. package/dist-client/components/user-invite.js.map +1 -1
  40. package/dist-client/components/user-popups-standard.test.js +1 -1
  41. package/dist-client/components/user-popups-standard.test.js.map +1 -1
  42. package/dist-client/components/user-role-editor.js +72 -122
  43. package/dist-client/components/user-role-editor.js.map +1 -1
  44. package/dist-client/entity360/person-360.d.ts +8 -11
  45. package/dist-client/entity360/person-360.js +49 -68
  46. package/dist-client/entity360/person-360.js.map +1 -1
  47. package/dist-client/entries/oauth2/oauth2-decision-page.js +13 -25
  48. package/dist-client/entries/oauth2/oauth2-decision-page.js.map +1 -1
  49. package/dist-client/identity-confirmation/identity-confirmation.d.ts +13 -14
  50. package/dist-client/identity-confirmation/identity-confirmation.js +39 -45
  51. package/dist-client/identity-confirmation/identity-confirmation.js.map +1 -1
  52. package/dist-client/pages/audit/audit-page.d.ts +4 -4
  53. package/dist-client/pages/audit/audit-page.js +28 -39
  54. package/dist-client/pages/audit/audit-page.js.map +1 -1
  55. package/dist-client/pages/domain-link/domain-link-management.js +1 -1
  56. package/dist-client/pages/domain-link/domain-link-management.js.map +1 -1
  57. package/dist-client/pages/partner/partner-management.js +30 -68
  58. package/dist-client/pages/partner/partner-management.js.map +1 -1
  59. package/dist-client/pages/role/role-extra-removal.test.d.mts +1 -0
  60. package/dist-client/pages/role/role-extra-removal.test.mjs +73 -0
  61. package/dist-client/pages/role/role-extra-removal.test.mjs.map +1 -0
  62. package/dist-client/pages/role/role-list-page.js +20 -22
  63. package/dist-client/pages/role/role-list-page.js.map +1 -1
  64. package/dist-client/pages/role/role-privilege-page.d.ts +36 -8
  65. package/dist-client/pages/role/role-privilege-page.js +216 -158
  66. package/dist-client/pages/role/role-privilege-page.js.map +1 -1
  67. package/dist-client/pages/role/role-task-review.test.js +20 -16
  68. package/dist-client/pages/role/role-task-review.test.js.map +1 -1
  69. package/dist-client/pages/role/role-template-gap.test.js +8 -3
  70. package/dist-client/pages/role/role-template-gap.test.js.map +1 -1
  71. package/dist-client/tsconfig.tsbuildinfo +1 -1
  72. package/helps/auth/roles.en.md +13 -49
  73. package/helps/auth/roles.ko.md +13 -32
  74. package/package.json +11 -10
  75. package/tests/page-state.test.ts +2 -1
  76. package/tests/password-rule-shown.test.ts +2 -2
  77. package/tests/person-360-sections.test.ts +9 -5
  78. package/translations/en.json +5 -1
  79. package/translations/es.json +5 -1
  80. package/translations/ja.json +5 -1
  81. package/translations/ko.json +5 -1
  82. package/translations/ms.json +5 -1
  83. package/translations/zh.json +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"my-passkeys.js","sourceRoot":"","sources":["../../client/components/my-passkeys.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@material/web/iconbutton/icon-button.js'\n\nimport { gql } from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { startRegistration } from '@simplewebauthn/browser'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\n\nimport { alreadyRegistered, deviceLabel, wasCancelled } from '../utils/passkey.js'\nimport { readVerification } from '../utils/webauthn-verification.js'\n\ntype Passkey = { id: string; name?: string | null; createdAt?: string; lastUsedAt?: string | null }\n\n/**\n * The person's own passkeys on the profile: what is registered, when it was last used, a name to\n * tell them apart, and removal for a device that is lost (ADR-0156 decision 6).\n */\n@customElement('my-passkeys')\nexport class MyPasskeys extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n }\n\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n li {\n display: flex;\n align-items: center;\n gap: var(--spacing-small);\n padding: var(--spacing-small) 0;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n\n .what {\n flex: 1;\n min-width: 0;\n }\n\n .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--md-sys-color-on-background);\n }\n\n .when {\n font-size: 12px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .none {\n margin: var(--spacing-small) 0;\n font-size: 14px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .what input {\n width: 100%;\n box-sizing: border-box;\n padding: 4px 6px;\n font: inherit;\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-container-highest);\n border: 1px solid var(--md-sys-color-outline);\n border-radius: var(--border-radius);\n }\n\n md-icon-button {\n --md-icon-button-icon-size: 20px;\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n\n @state() passkeys: Passkey[] = []\n @state() renaming?: string\n\n private supported = 'PublicKeyCredential' in window\n\n render() {\n if (!this.supported) return nothing\n\n return html`\n ${this.passkeys.length\n ? html`\n <ul>\n ${this.passkeys.map(\n passkey => html`\n <li>\n <div class=\"what\">\n ${this.renaming === passkey.id\n ? html`<input\n aria-label=${i18next.t('text.passkey name')}\n .value=${passkey.name || ''}\n maxlength=\"64\"\n @keydown=${(e: KeyboardEvent) => {\n if (e.key === 'Enter') this.rename(passkey, (e.target as HTMLInputElement).value)\n if (e.key === 'Escape') this.renaming = undefined\n }}\n @blur=${(e: FocusEvent) => this.rename(passkey, (e.target as HTMLInputElement).value)}\n />`\n : html`<div class=\"name\">${passkey.name || i18next.t('label.passkey')}</div>`}\n <div class=\"when\">${this.when(passkey)}</div>\n </div>\n <md-icon-button title=${i18next.t('button.rename')} @click=${() => this.startRenaming(passkey)}>\n <md-icon>edit</md-icon>\n </md-icon-button>\n <md-icon-button title=${i18next.t('button.delete')} @click=${() => this.removePasskey(passkey)}>\n <md-icon>delete</md-icon>\n </md-icon-button>\n </li>\n `\n )}\n </ul>\n `\n : html`<p class=\"none\">${i18next.t('text.no passkey yet')}</p>`}\n\n <md-text-button @click=${() => this.register()}>\n <md-icon slot=\"icon\">passkey</md-icon>${i18next.t('button.add passkey')}\n </md-text-button>\n `\n }\n\n firstUpdated() {\n if (this.supported) this.fetch()\n }\n\n private when(passkey: Passkey) {\n const date = (value?: string | null) => (value ? new Date(value).toLocaleDateString(i18next.language) : '')\n const made = i18next.t('text.passkey added on', { date: date(passkey.createdAt) })\n\n return passkey.lastUsedAt ? `${made} · ${i18next.t('text.passkey last used on', { date: date(passkey.lastUsedAt) })}` : made\n }\n\n private async fetch() {\n const response = await client.query({\n query: gql`\n query {\n myWebAuthCredentials {\n id\n name\n createdAt\n lastUsedAt\n }\n }\n `,\n fetchPolicy: 'no-cache'\n })\n\n if (!response.errors?.length) {\n this.passkeys = response.data.myWebAuthCredentials\n }\n }\n\n /*\n * The three endings stay apart (see `utils/webauthn-verification.ts`): registered, refused by the\n * server, or never got there - and a prompt the person closed is not reported at all.\n */\n async register() {\n try {\n const optionsJSON = await fetch('/auth/register-webauthn/challenge').then(res => res.json())\n const response = await startRegistration({ optionsJSON })\n\n const verification = await readVerification(\n await fetch('/auth/verify-registration', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ response, name: deviceLabel(navigator.userAgent) })\n })\n )\n\n if (verification.outcome === 'registered') {\n notify({ level: 'info', message: i18next.t('text.user credential registered successfully') })\n await this.fetch()\n return\n }\n\n /* The server's own words, in English, for whoever reads the console - not for the screen. */\n console.error('passkey registration refused:', verification.reason)\n notify({ level: 'error', message: i18next.t('error.user credential registration not allowed') })\n } catch (error) {\n if (wasCancelled(error)) return\n\n console.error('passkey registration failed:', error)\n notify({\n level: alreadyRegistered(error) ? 'info' : 'error',\n message: i18next.t(alreadyRegistered(error) ? 'text.passkey already on this device' : 'error.user credential registration failed')\n })\n }\n }\n\n private async startRenaming(passkey: Passkey) {\n this.renaming = passkey.id\n await this.updateComplete\n const input = this.renderRoot.querySelector('.what input') as HTMLInputElement | null\n input?.focus()\n input?.select()\n }\n\n /** Enter or leaving the field keeps the name; an empty or unchanged name keeps the old one. */\n private async rename(passkey: Passkey, value: string) {\n if (this.renaming !== passkey.id) return\n this.renaming = undefined\n\n const name = value.trim()\n if (!name || name === passkey.name) return\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $name: String!) {\n updateMyWebAuthCredential(id: $id, name: $name) {\n id\n }\n }\n `,\n variables: { id: passkey.id, name }\n })\n\n if (!response.errors?.length) await this.fetch()\n }\n\n private async removePasskey(passkey: Passkey) {\n const confirmed = await OxPrompt.open({\n type: 'warning',\n title: i18next.t('title.remove passkey'),\n text: i18next.t('text.removed passkey cannot sign in', { name: passkey.name || i18next.t('label.passkey') }),\n confirmButton: { text: i18next.t('button.delete') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n if (!confirmed) return\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!) {\n deleteMyWebAuthCredential(id: $id)\n }\n `,\n variables: { id: passkey.id }\n })\n\n if (!response.errors?.length) await this.fetch()\n }\n}\n"]}
1
+ {"version":3,"file":"my-passkeys.js","sourceRoot":"","sources":["../../client/components/my-passkeys.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@material/web/iconbutton/icon-button.js'\n\nimport { gql } from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { startRegistration } from '@simplewebauthn/browser'\n\nimport { MutationController, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\n\nimport { alreadyRegistered, deviceLabel, wasCancelled } from '../utils/passkey.js'\nimport { readVerification } from '../utils/webauthn-verification.js'\n\ntype Passkey = { id: string; name?: string | null; createdAt?: string; lastUsedAt?: string | null }\n\n/**\n * The person's own passkeys on the profile: what is registered, when it was last used, a name to\n * tell them apart, and removal for a device that is lost (ADR-0156 decision 6).\n */\n@customElement('my-passkeys')\nexport class MyPasskeys extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n }\n\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n li {\n display: flex;\n align-items: center;\n gap: var(--spacing-small);\n padding: var(--spacing-small) 0;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n\n .what {\n flex: 1;\n min-width: 0;\n }\n\n .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--md-sys-color-on-background);\n }\n\n .when {\n font-size: 12px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .none {\n margin: var(--spacing-small) 0;\n font-size: 14px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .what input {\n width: 100%;\n box-sizing: border-box;\n padding: 4px 6px;\n font: inherit;\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-container-highest);\n border: 1px solid var(--md-sys-color-outline);\n border-radius: var(--border-radius);\n }\n\n md-icon-button {\n --md-icon-button-icon-size: 20px;\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n\n @state() renaming?: string\n\n private supported = 'PublicKeyCredential' in window\n\n private credentials = new QueryController(\n this,\n gql`\n query {\n myWebAuthCredentials {\n id\n name\n createdAt\n lastUsedAt\n }\n }\n `,\n { variables: () => (this.supported ? {} : undefined) }\n )\n\n private renameCredential = new MutationController(\n this,\n gql`\n mutation ($id: String!, $name: String!) {\n updateMyWebAuthCredential(id: $id, name: $name) {\n id\n }\n }\n `,\n { refetch: () => [this.credentials] }\n )\n\n private deleteCredential = new MutationController(\n this,\n gql`\n mutation ($id: String!) {\n deleteMyWebAuthCredential(id: $id)\n }\n `,\n { refetch: () => [this.credentials] }\n )\n\n get passkeys(): Passkey[] {\n return this.credentials.data?.myWebAuthCredentials ?? []\n }\n\n render() {\n if (!this.supported) return nothing\n\n return html`\n ${this.passkeys.length\n ? html`\n <ul>\n ${this.passkeys.map(\n passkey => html`\n <li>\n <div class=\"what\">\n ${this.renaming === passkey.id\n ? html`<input\n aria-label=${i18next.t('text.passkey name')}\n .value=${passkey.name || ''}\n maxlength=\"64\"\n @keydown=${(e: KeyboardEvent) => {\n if (e.key === 'Enter') this.rename(passkey, (e.target as HTMLInputElement).value)\n if (e.key === 'Escape') this.renaming = undefined\n }}\n @blur=${(e: FocusEvent) => this.rename(passkey, (e.target as HTMLInputElement).value)}\n />`\n : html`<div class=\"name\">${passkey.name || i18next.t('label.passkey')}</div>`}\n <div class=\"when\">${this.when(passkey)}</div>\n </div>\n <md-icon-button title=${i18next.t('button.rename')} @click=${() => this.startRenaming(passkey)}>\n <md-icon>edit</md-icon>\n </md-icon-button>\n <md-icon-button title=${i18next.t('button.delete')} @click=${() => this.removePasskey(passkey)}>\n <md-icon>delete</md-icon>\n </md-icon-button>\n </li>\n `\n )}\n </ul>\n `\n : html`<p class=\"none\">${i18next.t('text.no passkey yet')}</p>`}\n\n <md-text-button @click=${() => this.register()}>\n <md-icon slot=\"icon\">passkey</md-icon>${i18next.t('button.add passkey')}\n </md-text-button>\n `\n }\n\n private when(passkey: Passkey) {\n const date = (value?: string | null) => (value ? new Date(value).toLocaleDateString(i18next.language) : '')\n const made = i18next.t('text.passkey added on', { date: date(passkey.createdAt) })\n\n return passkey.lastUsedAt ? `${made} · ${i18next.t('text.passkey last used on', { date: date(passkey.lastUsedAt) })}` : made\n }\n\n /*\n * The three endings stay apart (see `utils/webauthn-verification.ts`): registered, refused by the\n * server, or never got there - and a prompt the person closed is not reported at all.\n */\n async register() {\n try {\n const optionsJSON = await fetch('/auth/register-webauthn/challenge').then(res => res.json())\n const response = await startRegistration({ optionsJSON })\n\n const verification = await readVerification(\n await fetch('/auth/verify-registration', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ response, name: deviceLabel(navigator.userAgent) })\n })\n )\n\n if (verification.outcome === 'registered') {\n notify({ level: 'info', message: i18next.t('text.user credential registered successfully') })\n await this.credentials.refetch()\n return\n }\n\n /* The server's own words, in English, for whoever reads the console - not for the screen. */\n console.error('passkey registration refused:', verification.reason)\n notify({ level: 'error', message: i18next.t('error.user credential registration not allowed') })\n } catch (error) {\n if (wasCancelled(error)) return\n\n console.error('passkey registration failed:', error)\n notify({\n level: alreadyRegistered(error) ? 'info' : 'error',\n message: i18next.t(alreadyRegistered(error) ? 'text.passkey already on this device' : 'error.user credential registration failed')\n })\n }\n }\n\n private async startRenaming(passkey: Passkey) {\n this.renaming = passkey.id\n await this.updateComplete\n const input = this.renderRoot.querySelector('.what input') as HTMLInputElement | null\n input?.focus()\n input?.select()\n }\n\n /** Enter or leaving the field keeps the name; an empty or unchanged name keeps the old one. */\n private async rename(passkey: Passkey, value: string) {\n if (this.renaming !== passkey.id) return\n this.renaming = undefined\n\n const name = value.trim()\n if (!name || name === passkey.name) return\n\n await this.renameCredential.run({ id: passkey.id, name })\n }\n\n private async removePasskey(passkey: Passkey) {\n const confirmed = await OxPrompt.open({\n type: 'warning',\n title: i18next.t('title.remove passkey'),\n text: i18next.t('text.removed passkey cannot sign in', { name: passkey.name || i18next.t('label.passkey') }),\n confirmButton: { text: i18next.t('button.delete') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n if (!confirmed) return\n\n await this.deleteCredential.run({ id: passkey.id })\n }\n}\n"]}
@@ -9,10 +9,9 @@ import { LitElement, nothing } from 'lit';
9
9
  */
10
10
  export declare class MyRoles extends LitElement {
11
11
  static styles: import("lit").CSSResult[];
12
- private roles?;
13
- private failed;
12
+ private mine;
13
+ private get roles();
14
+ private get failed();
14
15
  render(): import("lit-html").TemplateResult<1> | typeof nothing;
15
16
  private renderTask;
16
- firstUpdated(): void;
17
- private fetch;
18
17
  }
@@ -1,8 +1,8 @@
1
- import { __decorate, __metadata } from "tslib";
1
+ import { __decorate } from "tslib";
2
2
  import gql from 'graphql-tag';
3
3
  import { css, html, LitElement, nothing } from 'lit';
4
- import { customElement, state } from 'lit/decorators.js';
5
- import { client } from '@operato/graphql';
4
+ import { customElement } from 'lit/decorators.js';
5
+ import { QueryController } from '@operato/graphql';
6
6
  import { i18next } from '@operato/i18n';
7
7
  import { store } from '@operato/shell';
8
8
  import { workOfRoles } from './my-role-tasks.js';
@@ -18,7 +18,33 @@ import { axisLabel } from '../utils/privilege-axis.js';
18
18
  let MyRoles = class MyRoles extends LitElement {
19
19
  constructor() {
20
20
  super(...arguments);
21
- this.failed = false;
21
+ this.mine = new QueryController(this, gql `
22
+ query {
23
+ myRoles {
24
+ id
25
+ name
26
+ description
27
+ taskCoverage {
28
+ tasks {
29
+ taskId
30
+ status
31
+ held {
32
+ category
33
+ axes
34
+ }
35
+ missing {
36
+ category
37
+ axes
38
+ }
39
+ }
40
+ unclassified {
41
+ category
42
+ axes
43
+ }
44
+ }
45
+ }
46
+ }
47
+ `);
22
48
  }
23
49
  static { this.styles = [
24
50
  css `
@@ -100,6 +126,12 @@ let MyRoles = class MyRoles extends LitElement {
100
126
  }
101
127
  `
102
128
  ]; }
129
+ get roles() {
130
+ return this.mine.data?.myRoles ?? undefined;
131
+ }
132
+ get failed() {
133
+ return !!this.mine.error || (!this.mine.loading && !!this.mine.data && !this.mine.data.myRoles);
134
+ }
103
135
  render() {
104
136
  if (this.failed)
105
137
  return html `<div failed>${i18next.t('text.the list could not be loaded')}</div>`;
@@ -152,58 +184,7 @@ let MyRoles = class MyRoles extends LitElement {
152
184
  ${says ? html `<div quiet>${says}</div>` : nothing}
153
185
  </li>`;
154
186
  }
155
- firstUpdated() {
156
- this.fetch();
157
- }
158
- async fetch() {
159
- try {
160
- const response = await client.query({
161
- query: gql `
162
- query {
163
- myRoles {
164
- id
165
- name
166
- description
167
- taskCoverage {
168
- tasks {
169
- taskId
170
- status
171
- held {
172
- category
173
- axes
174
- }
175
- missing {
176
- category
177
- axes
178
- }
179
- }
180
- unclassified {
181
- category
182
- axes
183
- }
184
- }
185
- }
186
- }
187
- `,
188
- fetchPolicy: 'no-cache'
189
- });
190
- if (response.errors?.length || !response.data?.myRoles)
191
- throw new Error();
192
- this.roles = response.data.myRoles;
193
- }
194
- catch {
195
- this.failed = true;
196
- }
197
- }
198
187
  };
199
- __decorate([
200
- state(),
201
- __metadata("design:type", Array)
202
- ], MyRoles.prototype, "roles", void 0);
203
- __decorate([
204
- state(),
205
- __metadata("design:type", Object)
206
- ], MyRoles.prototype, "failed", void 0);
207
188
  MyRoles = __decorate([
208
189
  customElement('my-roles')
209
190
  ], MyRoles);
@@ -1 +1 @@
1
- {"version":3,"file":"my-roles.js","sourceRoot":"","sources":["../../client/components/my-roles.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { store } from '@operato/shell'\n\nimport { workOfRoles, type MyRoleRef, type MyWork } from './my-role-tasks.js'\nimport { axisLabel } from '../utils/privilege-axis.js'\n\ntype MyRole = MyRoleRef & { id: string; description?: string }\n\n/**\n * 내 역할과 업무 권한 — the roles one holds and the work they give, the body of its page (`my-roles`, ADR-0139 §11-11).\n * Read only: a role is given by whoever manages roles, and one asks for more through an access request (ADR-0103).\n *\n * The roles first, each in a line; then the work, one list across them with the roles that give each; what every role\n * gives last, once. A task is said in the words of the module that declares it (`task.<id>.name` · `.description`); a\n * privilege no task names, by the sentence written for it (`privilege.allows.<category>.<axis>`), else by its code.\n */\n@customElement('my-roles')\nexport class MyRoles extends LitElement {\n static styles = [\n css`\n :host {\n display: block;\n font-size: var(--ui-t-body, 13px);\n line-height: 1.55;\n }\n\n section + section {\n margin-top: var(--spacing-large);\n padding-top: var(--spacing-large);\n border-top: 1px solid var(--md-sys-color-outline-variant);\n }\n\n h3 {\n margin: 0 0 var(--spacing-small);\n font-size: 0.95rem;\n }\n\n [quiet] {\n color: var(--md-sys-color-on-surface-variant);\n }\n\n p {\n margin: 0 0 var(--spacing-small);\n }\n\n ul {\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n li + li {\n margin-top: var(--spacing-medium);\n }\n\n dl {\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: var(--spacing-small) var(--spacing-medium);\n margin: 0;\n }\n\n dt {\n font-weight: 600;\n }\n\n dd {\n margin: 0;\n }\n\n [task-head] {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--spacing-small);\n }\n\n [task-name] {\n font-weight: 600;\n }\n\n [from] {\n padding: 0 6px;\n border-radius: 999px;\n background-color: var(--md-sys-color-surface-variant);\n color: var(--md-sys-color-on-surface-variant);\n font-size: 0.8rem;\n }\n\n code {\n font-size: 0.9em;\n }\n\n [failed] {\n color: var(--md-sys-color-error);\n }\n `\n ]\n\n @state() private roles?: MyRole[]\n @state() private failed = false\n\n render() {\n if (this.failed) return html`<div failed>${i18next.t('text.the list could not be loaded')}</div>`\n if (!this.roles) return nothing\n\n const owner = (store.getState() as any).auth?.user?.owner\n if (!this.roles.length) return html`<p quiet>${owner ? i18next.t('text.my roles owner') : i18next.t('text.my roles none')}</p>`\n\n const { own, shared, alone } = workOfRoles(this.roles)\n /* Which roles give it - said only when they are not all of mine (then it would say nothing). */\n const from = (roles: string[]) => (this.roles!.length > 1 && roles.length < this.roles!.length ? roles.map(name => html`<span from>${name}</span>`) : nothing)\n\n return html`\n <section>\n <h3>${i18next.t('text.my roles count', { count: this.roles.length })}</h3>\n ${owner ? html`<p quiet>${i18next.t('text.my roles owner')}</p>` : nothing}\n <dl>\n ${this.roles.map(role => html`<dt>${role.name}</dt><dd quiet>${role.description || ''}</dd>`)}\n </dl>\n </section>\n\n ${\n own.length || alone.length\n ? html`<section>\n <h3>${i18next.t('text.my role tasks')}</h3>\n <ul>\n ${own.map(task => this.renderTask(task, from(task.roles)))}\n ${alone.map(one => {\n const says = i18next.t(`privilege.allows.${one.category}.${one.axis}`, { defaultValue: '' })\n return html`<li>\n <div task-head>${says ? html`<span>${says}</span>` : html`<span><code>${one.category}</code> · ${axisLabel(one.axis)}</span>`} ${from(one.roles)}</div>\n </li>`\n })}\n </ul>\n </section>`\n : nothing\n }\n\n ${\n shared.length\n ? html`<section>\n <h3>${i18next.t('text.my roles shared tasks')}</h3>\n <ul>\n ${shared.map(task => this.renderTask(task, nothing))}\n </ul>\n </section>`\n : nothing\n }\n `\n }\n\n private renderTask(task: MyWork, from: unknown) {\n const says = i18next.t(`task.${task.taskId}.description`, { defaultValue: '' })\n return html`<li>\n <div task-head><span task-name>${i18next.t(`task.${task.taskId}.name`, { defaultValue: task.taskId })}</span> ${from}</div>\n ${says ? html`<div quiet>${says}</div>` : nothing}\n </li>`\n }\n\n firstUpdated() {\n this.fetch()\n }\n\n private async fetch() {\n try {\n const response = await client.query({\n query: gql`\n query {\n myRoles {\n id\n name\n description\n taskCoverage {\n tasks {\n taskId\n status\n held {\n category\n axes\n }\n missing {\n category\n axes\n }\n }\n unclassified {\n category\n axes\n }\n }\n }\n }\n `,\n fetchPolicy: 'no-cache'\n })\n if (response.errors?.length || !response.data?.myRoles) throw new Error()\n this.roles = response.data.myRoles\n } catch {\n this.failed = true\n }\n }\n}\n"]}
1
+ {"version":3,"file":"my-roles.js","sourceRoot":"","sources":["../../client/components/my-roles.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement } from 'lit/decorators.js'\n\nimport { QueryController } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { store } from '@operato/shell'\n\nimport { workOfRoles, type MyRoleRef, type MyWork } from './my-role-tasks.js'\nimport { axisLabel } from '../utils/privilege-axis.js'\n\ntype MyRole = MyRoleRef & { id: string; description?: string }\n\n/**\n * 내 역할과 업무 권한 — the roles one holds and the work they give, the body of its page (`my-roles`, ADR-0139 §11-11).\n * Read only: a role is given by whoever manages roles, and one asks for more through an access request (ADR-0103).\n *\n * The roles first, each in a line; then the work, one list across them with the roles that give each; what every role\n * gives last, once. A task is said in the words of the module that declares it (`task.<id>.name` · `.description`); a\n * privilege no task names, by the sentence written for it (`privilege.allows.<category>.<axis>`), else by its code.\n */\n@customElement('my-roles')\nexport class MyRoles extends LitElement {\n static styles = [\n css`\n :host {\n display: block;\n font-size: var(--ui-t-body, 13px);\n line-height: 1.55;\n }\n\n section + section {\n margin-top: var(--spacing-large);\n padding-top: var(--spacing-large);\n border-top: 1px solid var(--md-sys-color-outline-variant);\n }\n\n h3 {\n margin: 0 0 var(--spacing-small);\n font-size: 0.95rem;\n }\n\n [quiet] {\n color: var(--md-sys-color-on-surface-variant);\n }\n\n p {\n margin: 0 0 var(--spacing-small);\n }\n\n ul {\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n li + li {\n margin-top: var(--spacing-medium);\n }\n\n dl {\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: var(--spacing-small) var(--spacing-medium);\n margin: 0;\n }\n\n dt {\n font-weight: 600;\n }\n\n dd {\n margin: 0;\n }\n\n [task-head] {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--spacing-small);\n }\n\n [task-name] {\n font-weight: 600;\n }\n\n [from] {\n padding: 0 6px;\n border-radius: 999px;\n background-color: var(--md-sys-color-surface-variant);\n color: var(--md-sys-color-on-surface-variant);\n font-size: 0.8rem;\n }\n\n code {\n font-size: 0.9em;\n }\n\n [failed] {\n color: var(--md-sys-color-error);\n }\n `\n ]\n\n private mine = new QueryController(\n this,\n gql`\n query {\n myRoles {\n id\n name\n description\n taskCoverage {\n tasks {\n taskId\n status\n held {\n category\n axes\n }\n missing {\n category\n axes\n }\n }\n unclassified {\n category\n axes\n }\n }\n }\n }\n `\n )\n\n private get roles(): MyRole[] | undefined {\n return this.mine.data?.myRoles ?? undefined\n }\n\n private get failed() {\n return !!this.mine.error || (!this.mine.loading && !!this.mine.data && !this.mine.data.myRoles)\n }\n\n render() {\n if (this.failed) return html`<div failed>${i18next.t('text.the list could not be loaded')}</div>`\n if (!this.roles) return nothing\n\n const owner = (store.getState() as any).auth?.user?.owner\n if (!this.roles.length) return html`<p quiet>${owner ? i18next.t('text.my roles owner') : i18next.t('text.my roles none')}</p>`\n\n const { own, shared, alone } = workOfRoles(this.roles)\n /* Which roles give it - said only when they are not all of mine (then it would say nothing). */\n const from = (roles: string[]) => (this.roles!.length > 1 && roles.length < this.roles!.length ? roles.map(name => html`<span from>${name}</span>`) : nothing)\n\n return html`\n <section>\n <h3>${i18next.t('text.my roles count', { count: this.roles.length })}</h3>\n ${owner ? html`<p quiet>${i18next.t('text.my roles owner')}</p>` : nothing}\n <dl>\n ${this.roles.map(role => html`<dt>${role.name}</dt><dd quiet>${role.description || ''}</dd>`)}\n </dl>\n </section>\n\n ${\n own.length || alone.length\n ? html`<section>\n <h3>${i18next.t('text.my role tasks')}</h3>\n <ul>\n ${own.map(task => this.renderTask(task, from(task.roles)))}\n ${alone.map(one => {\n const says = i18next.t(`privilege.allows.${one.category}.${one.axis}`, { defaultValue: '' })\n return html`<li>\n <div task-head>${says ? html`<span>${says}</span>` : html`<span><code>${one.category}</code> · ${axisLabel(one.axis)}</span>`} ${from(one.roles)}</div>\n </li>`\n })}\n </ul>\n </section>`\n : nothing\n }\n\n ${\n shared.length\n ? html`<section>\n <h3>${i18next.t('text.my roles shared tasks')}</h3>\n <ul>\n ${shared.map(task => this.renderTask(task, nothing))}\n </ul>\n </section>`\n : nothing\n }\n `\n }\n\n private renderTask(task: MyWork, from: unknown) {\n const says = i18next.t(`task.${task.taskId}.description`, { defaultValue: '' })\n return html`<li>\n <div task-head><span task-name>${i18next.t(`task.${task.taskId}.name`, { defaultValue: task.taskId })}</span> ${from}</div>\n ${says ? html`<div quiet>${says}</div>` : nothing}\n </li>`\n }\n}\n"]}
@@ -4,7 +4,7 @@ import './role-selector.js';
4
4
  import gql from 'graphql-tag';
5
5
  import { css, html, LitElement } from 'lit';
6
6
  import { customElement, property, query } from 'lit/decorators.js';
7
- import { client, gqlContext } from '@operato/graphql';
7
+ import { client, gqlContext, QueryController } from '@operato/graphql';
8
8
  import { i18next, localize } from '@operato/i18n';
9
9
  import { OxPrompt } from '@operato/popup/ox-prompt.js';
10
10
  import { ButtonContainerStyles } from '@operato/styles';
@@ -12,8 +12,26 @@ import { RoleSelector } from './role-selector.js';
12
12
  let PartnerRoleEditor = class PartnerRoleEditor extends localize(i18next)(LitElement) {
13
13
  constructor() {
14
14
  super(...arguments);
15
- this.roles = [];
16
- this.grantingRoles = [];
15
+ this.granted = new QueryController(this, gql `
16
+ query roles($customerId: String!) {
17
+ roles {
18
+ items {
19
+ id
20
+ name
21
+ description
22
+ }
23
+ total
24
+ }
25
+ grantingRoles(customerId: $customerId) {
26
+ id
27
+ role {
28
+ id
29
+ name
30
+ description
31
+ }
32
+ }
33
+ }
34
+ `, { variables: () => (this.customer?.id ? { customerId: this.customer.id } : undefined), context: gqlContext() });
17
35
  }
18
36
  static { this.styles = [
19
37
  ButtonContainerStyles,
@@ -33,6 +51,12 @@ let PartnerRoleEditor = class PartnerRoleEditor extends localize(i18next)(LitEle
33
51
  }
34
52
  `
35
53
  ]; }
54
+ get roles() {
55
+ return this.granted.data?.roles?.items ?? [];
56
+ }
57
+ get grantingRoles() {
58
+ return (this.granted.data?.grantingRoles ?? []).map(grantingRole => grantingRole.role);
59
+ }
36
60
  render() {
37
61
  const roles = this.roles || [];
38
62
  const grantingRoles = this.grantingRoles || [];
@@ -47,45 +71,6 @@ let PartnerRoleEditor = class PartnerRoleEditor extends localize(i18next)(LitEle
47
71
  </div>
48
72
  `;
49
73
  }
50
- updated(changes) {
51
- if (changes.has('customer')) {
52
- this.refreshRoles();
53
- }
54
- }
55
- async refreshRoles() {
56
- const response = await client.query({
57
- query: gql `
58
- query roles($customerId: String!) {
59
- roles {
60
- items {
61
- id
62
- name
63
- description
64
- }
65
- total
66
- }
67
- grantingRoles(customerId: $customerId) {
68
- id
69
- role {
70
- id
71
- name
72
- description
73
- }
74
- }
75
- }
76
- `,
77
- variables: { customerId: this.customer.id },
78
- context: gqlContext()
79
- });
80
- if (!response.errors?.length) {
81
- this.roles = response.data.roles.items;
82
- this.grantingRoles = response.data.grantingRoles.map(grantingRole => grantingRole.role);
83
- }
84
- else {
85
- this.roles = [];
86
- this.grantingRoles = [];
87
- }
88
- }
89
74
  async onSave() {
90
75
  const roles = this.roleSelector.selectedRoles();
91
76
  const response = await client.mutate({
@@ -137,14 +122,6 @@ __decorate([
137
122
  property({ type: Object }),
138
123
  __metadata("design:type", Object)
139
124
  ], PartnerRoleEditor.prototype, "customer", void 0);
140
- __decorate([
141
- property({ type: Array }),
142
- __metadata("design:type", Array)
143
- ], PartnerRoleEditor.prototype, "roles", void 0);
144
- __decorate([
145
- property({ type: Array }),
146
- __metadata("design:type", Array)
147
- ], PartnerRoleEditor.prototype, "grantingRoles", void 0);
148
125
  __decorate([
149
126
  query('role-selector'),
150
127
  __metadata("design:type", RoleSelector)
@@ -1 +1 @@
1
- {"version":3,"file":"partner-role-editor.js","sourceRoot":"","sources":["../../client/components/partner-role-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/elevated-button.js'\nimport './role-selector.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { client, gqlContext } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { ButtonContainerStyles } from '@operato/styles'\n\nimport { RoleSelector } from './role-selector.js'\n\n@customElement('partner-role-editor')\nclass PartnerRoleEditor extends localize(i18next)(LitElement) {\n static styles = [\n ButtonContainerStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n border: 1px solid var(--md-sys-color-primary);\n padding: var(--spacing-medium);\n font: normal 15px var(--theme-font);\n color: var(--md-sys-color-secondary);\n }\n\n md-elevated-button {\n margin-right: var(--spacing-small);\n }\n `\n ]\n\n @property({ type: Object }) customer: any\n @property({ type: Array }) roles: any[] = []\n @property({ type: Array }) grantingRoles: any[] = []\n\n @query('role-selector') roleSelector!: RoleSelector\n\n render() {\n const roles = this.roles || []\n const grantingRoles = this.grantingRoles || []\n\n return html`\n <role-selector .roles=\"${roles}\" .userRoles=\"${grantingRoles}\"></role-selector>\n\n <div class=\"button-container\">\n <md-elevated-button @click=${this.onSave}>${i18next.t('button.save')}</md-elevated-button>\n <md-elevated-button @click=${this.onTerminateContract} danger\n >${i18next.t('button.terminate contract')}</md-elevated-button\n >\n </div>\n `\n }\n\n updated(changes) {\n if (changes.has('customer')) {\n this.refreshRoles()\n }\n }\n\n async refreshRoles() {\n const response = await client.query({\n query: gql`\n query roles($customerId: String!) {\n roles {\n items {\n id\n name\n description\n }\n total\n }\n grantingRoles(customerId: $customerId) {\n id\n role {\n id\n name\n description\n }\n }\n }\n `,\n variables: { customerId: this.customer.id },\n context: gqlContext()\n })\n\n if (!response.errors?.length) {\n this.roles = response.data.roles.items\n this.grantingRoles = response.data.grantingRoles.map(grantingRole => grantingRole.role)\n } else {\n this.roles = []\n this.grantingRoles = []\n }\n }\n\n async onSave() {\n const roles = this.roleSelector.selectedRoles()\n\n const response = await client.mutate({\n mutation: gql`\n mutation grantRoles($customerId: String!, $roles: [RolePatch!]!) {\n grantRoles(customerId: $customerId, roles: $roles)\n }\n `,\n variables: { customerId: this.customer.id, roles },\n context: gqlContext()\n })\n\n if (!response.errors?.length) {\n this.showToast(i18next.t('text.data_updated_successfully'))\n }\n }\n\n async onTerminateContract() {\n if (\n await OxPrompt.open({\n title: i18next.t('text.are_you_sure'),\n text: i18next.t('text.are_you_sure_to_terminate_contract'),\n confirmButton: { text: i18next.t('button.terminate contract') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n ) {\n const response = await client.mutate({\n mutation: gql`\n mutation terminateContract($partnerName: String!) {\n terminateContract(partnerName: $partnerName)\n }\n `,\n variables: { partnerName: this.customer.name },\n context: gqlContext()\n })\n\n if (!response.errors?.length) {\n const answer = this.dispatchEvent(new CustomEvent('contractTerminated'))\n\n if (answer) {\n await OxPrompt.open({\n type: 'success',\n title: i18next.t('text.completed'),\n confirmButton: { text: i18next.t('button.confirm') }\n })\n }\n }\n }\n }\n\n showToast(message) {\n document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))\n }\n}\n"]}
1
+ {"version":3,"file":"partner-role-editor.js","sourceRoot":"","sources":["../../client/components/partner-role-editor.ts"],"names":[],"mappings":";AAAA,OAAO,yCAAyC,CAAA;AAChD,OAAO,oBAAoB,CAAA;AAE3B,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACtE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGjD,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAA7D;;QAsBU,YAAO,GAAG,IAAI,eAAe,CACnC,IAAI,EACJ,GAAG,CAAA;;;;;;;;;;;;;;;;;;;KAmBF,EACD,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAC/G,CAAA;IAkFH,CAAC;aA9HQ,WAAM,GAAG;QACd,qBAAqB;QACrB,GAAG,CAAA;;;;;;;;;;;;;;KAcF;KACF,AAjBY,CAiBZ;IA6BD,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,CAAA;IAC9C,CAAC;IAED,IAAI,aAAa;QACf,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IACxF,CAAC;IAID,MAAM;QACJ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;QAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,EAAE,CAAA;QAE9C,OAAO,IAAI,CAAA;+BACgB,KAAK,iBAAiB,aAAa;;;qCAG7B,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;qCACvC,IAAI,CAAC,mBAAmB;aAChD,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;;;KAG9C,CAAA;IACH,CAAC;IAED,KAAK,CAAC,MAAM;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAA;QAE/C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;YACnC,QAAQ,EAAE,GAAG,CAAA;;;;OAIZ;YACD,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE;YAClD,OAAO,EAAE,UAAU,EAAE;SACtB,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAA;QAC7D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,IACE,MAAM,QAAQ,CAAC,IAAI,CAAC;YAClB,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;YACrC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,yCAAyC,CAAC;YAC1D,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC,EAAE;YAC/D,YAAY,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE;SACnD,CAAC,EACF,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;gBACnC,QAAQ,EAAE,GAAG,CAAA;;;;SAIZ;gBACD,SAAS,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;gBAC9C,OAAO,EAAE,UAAU,EAAE;aACtB,CAAC,CAAA;YAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;gBAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,oBAAoB,CAAC,CAAC,CAAA;gBAExE,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,QAAQ,CAAC,IAAI,CAAC;wBAClB,IAAI,EAAE,SAAS;wBACf,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC;wBAClC,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE;qBACrD,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,CAAC,OAAO;QACf,QAAQ,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;IACrG,CAAC;;AA1G2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;mDAAc;AAmCjB;IAAvB,KAAK,CAAC,eAAe,CAAC;8BAAgB,YAAY;uDAAA;AAvD/C,iBAAiB;IADtB,aAAa,CAAC,qBAAqB,CAAC;GAC/B,iBAAiB,CA+HtB","sourcesContent":["import '@material/web/button/elevated-button.js'\nimport './role-selector.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { client, gqlContext, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { ButtonContainerStyles } from '@operato/styles'\n\nimport { RoleSelector } from './role-selector.js'\n\n@customElement('partner-role-editor')\nclass PartnerRoleEditor extends localize(i18next)(LitElement) {\n static styles = [\n ButtonContainerStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n border: 1px solid var(--md-sys-color-primary);\n padding: var(--spacing-medium);\n font: normal 15px var(--theme-font);\n color: var(--md-sys-color-secondary);\n }\n\n md-elevated-button {\n margin-right: var(--spacing-small);\n }\n `\n ]\n\n @property({ type: Object }) customer: any\n\n private granted = new QueryController(\n this,\n gql`\n query roles($customerId: String!) {\n roles {\n items {\n id\n name\n description\n }\n total\n }\n grantingRoles(customerId: $customerId) {\n id\n role {\n id\n name\n description\n }\n }\n }\n `,\n { variables: () => (this.customer?.id ? { customerId: this.customer.id } : undefined), context: gqlContext() }\n )\n\n get roles(): any[] {\n return this.granted.data?.roles?.items ?? []\n }\n\n get grantingRoles(): any[] {\n return (this.granted.data?.grantingRoles ?? []).map(grantingRole => grantingRole.role)\n }\n\n @query('role-selector') roleSelector!: RoleSelector\n\n render() {\n const roles = this.roles || []\n const grantingRoles = this.grantingRoles || []\n\n return html`\n <role-selector .roles=\"${roles}\" .userRoles=\"${grantingRoles}\"></role-selector>\n\n <div class=\"button-container\">\n <md-elevated-button @click=${this.onSave}>${i18next.t('button.save')}</md-elevated-button>\n <md-elevated-button @click=${this.onTerminateContract} danger\n >${i18next.t('button.terminate contract')}</md-elevated-button\n >\n </div>\n `\n }\n\n async onSave() {\n const roles = this.roleSelector.selectedRoles()\n\n const response = await client.mutate({\n mutation: gql`\n mutation grantRoles($customerId: String!, $roles: [RolePatch!]!) {\n grantRoles(customerId: $customerId, roles: $roles)\n }\n `,\n variables: { customerId: this.customer.id, roles },\n context: gqlContext()\n })\n\n if (!response.errors?.length) {\n this.showToast(i18next.t('text.data_updated_successfully'))\n }\n }\n\n async onTerminateContract() {\n if (\n await OxPrompt.open({\n title: i18next.t('text.are_you_sure'),\n text: i18next.t('text.are_you_sure_to_terminate_contract'),\n confirmButton: { text: i18next.t('button.terminate contract') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n ) {\n const response = await client.mutate({\n mutation: gql`\n mutation terminateContract($partnerName: String!) {\n terminateContract(partnerName: $partnerName)\n }\n `,\n variables: { partnerName: this.customer.name },\n context: gqlContext()\n })\n\n if (!response.errors?.length) {\n const answer = this.dispatchEvent(new CustomEvent('contractTerminated'))\n\n if (answer) {\n await OxPrompt.open({\n type: 'success',\n title: i18next.t('text.completed'),\n confirmButton: { text: i18next.t('button.confirm') }\n })\n }\n }\n }\n }\n\n showToast(message) {\n document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))\n }\n}\n"]}
@@ -15,7 +15,8 @@ export declare class ProfileComponent extends ProfileComponent_base {
15
15
  code: string;
16
16
  display: string;
17
17
  }[];
18
- passwordRule: {
18
+ private rule;
19
+ get passwordRule(): {
19
20
  lowerCase?: boolean;
20
21
  upperCase?: boolean;
21
22
  digit?: boolean;
@@ -30,7 +31,6 @@ export declare class ProfileComponent extends ProfileComponent_base {
30
31
  nameEl: HTMLInputElement;
31
32
  emailEl: HTMLInputElement;
32
33
  localeEl: HTMLInputElement;
33
- connectedCallback(): Promise<void>;
34
34
  firstUpdated(): Promise<void>;
35
35
  setCredential(credential: any): void;
36
36
  render(): import("lit-html").TemplateResult<1>;
@@ -8,7 +8,7 @@ import './my-passkeys.js';
8
8
  import { gql } from 'graphql-tag';
9
9
  import { css, html, LitElement, nothing } from 'lit';
10
10
  import { customElement, property, query, state } from 'lit/decorators.js';
11
- import { client } from '@operato/graphql';
11
+ import { QueryController } from '@operato/graphql';
12
12
  import { i18next, localize } from '@operato/i18n';
13
13
  import { notify, openPopup } from '@operato/layout';
14
14
  import { FormFieldStyles } from '@operato/styles';
@@ -18,7 +18,21 @@ let ProfileComponent = class ProfileComponent extends localize(i18next)(LitEleme
18
18
  constructor() {
19
19
  super(...arguments);
20
20
  this.languages = [];
21
- this.passwordRule = {};
21
+ this.rule = new QueryController(this, gql `
22
+ query {
23
+ passwordRule {
24
+ lowerCase
25
+ upperCase
26
+ digit
27
+ specialCharacter
28
+ allowRepeat
29
+ useTightPattern
30
+ useLoosePattern
31
+ tightCharacterLength
32
+ looseCharacterLength
33
+ }
34
+ }
35
+ `);
22
36
  }
23
37
  static { this.styles = [
24
38
  FormFieldStyles,
@@ -126,26 +140,8 @@ let ProfileComponent = class ProfileComponent extends localize(i18next)(LitEleme
126
140
  }
127
141
  `
128
142
  ]; }
129
- async connectedCallback() {
130
- super.connectedCallback();
131
- const response = await client.query({
132
- query: gql `
133
- query {
134
- passwordRule {
135
- lowerCase
136
- upperCase
137
- digit
138
- specialCharacter
139
- allowRepeat
140
- useTightPattern
141
- useLoosePattern
142
- tightCharacterLength
143
- looseCharacterLength
144
- }
145
- }
146
- `
147
- });
148
- this.passwordRule = response.data?.passwordRule;
143
+ get passwordRule() {
144
+ return this.rule.data?.passwordRule ?? {};
149
145
  }
150
146
  async firstUpdated() {
151
147
  auth.on('profile', ({ credential }) => {
@@ -343,10 +339,6 @@ __decorate([
343
339
  state(),
344
340
  __metadata("design:type", Array)
345
341
  ], ProfileComponent.prototype, "languages", void 0);
346
- __decorate([
347
- state(),
348
- __metadata("design:type", Object)
349
- ], ProfileComponent.prototype, "passwordRule", void 0);
350
342
  __decorate([
351
343
  query('#username'),
352
344
  __metadata("design:type", HTMLInputElement)
@@ -1 +1 @@
1
- {"version":3,"file":"profile-component.js","sourceRoot":"","sources":["../../client/components/profile-component.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/i18n/ox-i18n.js'\nimport '@operato/i18n/ox-i18n-selector.js'\nimport './change-password.js'\nimport './delete-user-popup.js'\nimport './my-login-history.js'\nimport './my-passkeys.js'\n\nimport { gql } from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { FormFieldStyles } from '@operato/styles'\nimport { auth, getLanguages } from '@things-factory/auth-base/dist-client'\n\nconst isAvailableWebauthn = 'PublicKeyCredential' in window\n@customElement('profile-component')\nexport class ProfileComponent extends localize(i18next)(LitElement) {\n static styles = [\n FormFieldStyles,\n css`\n :host {\n display: block;\n background-color: var(--md-sys-color-background);\n padding: 15px 0;\n }\n .wrap {\n max-width: var(--profile-wrap-max-width, 400px);\n margin: auto;\n display: grid;\n grid-template-columns: 1fr 1fr;\n }\n\n * {\n box-sizing: border-box;\n }\n\n *:focus {\n outline: none;\n }\n\n /* 색·테두리·모서리·포커스·placeholder 는 FormFieldStyles 가 담당하고, 여기서는 치수만 둔다 */\n input {\n margin: var(--spacing-small) 0;\n padding: 9px;\n border-radius: var(--border-radius);\n font: var(--auth-input-field-font);\n width: var(--auth-input-field-width);\n }\n\n .user {\n background: url(/assets/images/icon-profile.png) center top no-repeat;\n margin: var(--profile-icon-margin);\n padding: 180px 20px 20px 20px;\n color: var(--md-sys-color-secondary);\n font: var(--header-bar-title);\n text-align: center;\n }\n\n hr {\n width: 100%;\n /* rgba(0,0,0,.1) 은 다크 배경에서 보이지 않는다 */\n border: dotted 1px var(--md-sys-color-outline-variant);\n }\n\n .wrap * {\n grid-column: span 2;\n }\n\n label {\n font: bold 14px var(--theme-font);\n color: var(--md-sys-color-primary);\n text-transform: capitalize;\n grid-column: 1;\n }\n\n .wrap *.inline {\n grid-column: unset;\n }\n\n /*\n * 언어 select 는 ox-i18n-selector 의 shadow root 안에 있어 위 input 규칙이 닿지 않는다.\n * 높이가 어긋나지 않도록 인풋과 **같은 값**을 토큰으로 넘긴다(padding 9px, 16px 글자).\n */\n ox-i18n-selector {\n --i18n-selector-field-width: var(--auth-input-field-width);\n /* 여백은 호스트에만 준다 — 내부에도 주면 두 번 더해져 인풋보다 벌어진다 */\n --i18n-selector-field-margin: 0;\n --i18n-selector-field-padding: 9px;\n --i18n-selector-field-border-radius: var(--border-radius);\n --i18n-selector-field-font: var(--auth-input-field-font);\n /* ox-i18n-selector 가 font 뒤에 font-size(기본 15px)를 다시 선언하므로 크기도 넘겨야 한다 */\n --i18n-selector-field-font-size: var(--profile-field-font-size, 16px);\n --i18n-selector-field-border: var(--input-field-border, 1px solid var(--md-sys-color-outline));\n --i18n-selector-field-background-color: var(\n --input-field-background,\n var(--md-sys-color-surface-container-highest)\n );\n --i18n-selector-field-color: var(--input-field-color, var(--md-sys-color-on-surface));\n margin: var(--spacing-small) 0;\n }\n\n md-text-button {\n text-transform: capitalize;\n }\n\n footer {\n padding: 20px;\n text-align: center;\n }\n\n footer p {\n font-size: 14px;\n margin-bottom: 5px;\n color: var(--md-sys-color-on-background);\n }\n\n footer a {\n color: var(--md-sys-color-primary);\n text-decoration: none;\n font-weight: bold;\n }\n `\n ]\n\n @property({ type: String }) username?: string\n @property({ type: String }) email?: string\n @property({ type: String }) name?: string\n\n @state() languages: { code: string; display: string }[] = []\n @state() passwordRule: {\n lowerCase?: boolean\n upperCase?: boolean\n digit?: boolean\n specialCharacter?: boolean\n allowRepeat?: boolean\n useTightPattern?: boolean\n useLoosePattern?: boolean\n tightCharacterLength?: number\n looseCharacterLength?: number\n } = {}\n\n @query('#username') usernameEl!: HTMLInputElement\n @query('#name') nameEl!: HTMLInputElement\n @query('#email') emailEl!: HTMLInputElement\n @query('#locale') localeEl!: HTMLInputElement\n\n async connectedCallback(): Promise<void> {\n super.connectedCallback()\n\n const response = await client.query({\n query: gql`\n query {\n passwordRule {\n lowerCase\n upperCase\n digit\n specialCharacter\n allowRepeat\n useTightPattern\n useLoosePattern\n tightCharacterLength\n looseCharacterLength\n }\n }\n `\n })\n\n this.passwordRule = response.data?.passwordRule\n }\n\n async firstUpdated() {\n auth.on('profile', ({ credential }) => {\n this.setCredential(credential)\n })\n\n this.setCredential(auth.credential)\n\n this.languages = await getLanguages()\n }\n\n setCredential(credential) {\n if (credential) {\n this.username = credential.username\n this.name = credential.name\n this.email = credential.email\n } else {\n this.username = ''\n this.name = ''\n this.email = ''\n }\n }\n\n render() {\n return html`\n <div class=\"wrap\">\n <div class=\"user\">${this.username || ''}</div>\n\n <label for=\"username\"><ox-i18n slot=\"title\" msgid=\"label.user-id\"></ox-i18n></label>\n <input id=\"username\" @change=${e => this.onUsernameChanged(e.target.value)} .value=${this.username || ''} />\n\n <hr />\n\n <label for=\"name\"><ox-i18n slot=\"title\" msgid=\"label.name\"></ox-i18n></label>\n <input id=\"name\" @change=${e => this.onNameChanged(e.target.value)} .value=${this.name || ''} />\n\n <hr />\n\n <label for=\"email\"><ox-i18n slot=\"title\" msgid=\"label.email\"></ox-i18n></label>\n <input id=\"email\" type=\"email\" @change=${e => this.onEmailChanged(e.target.value)} .value=${this.email || ''} />\n\n <hr />\n\n <label for=\"locale\"><ox-i18n slot=\"title\" msgid=\"label.language\"></ox-i18n></label>\n <ox-i18n-selector\n id=\"locale\"\n @change=${e => this.onLocaleChanged(e.detail)}\n value=${i18next.language || 'en-US'}\n .languages=${this.languages}\n ></ox-i18n-selector>\n\n <hr />\n\n <label for=\"change-password\">\n <ox-i18n msgid=\"label.password\"></ox-i18n>\n </label>\n\n <change-password id=\"change-password\" .passwordRule=${this.passwordRule}></change-password>\n\n ${\n isAvailableWebauthn\n ? html`\n <hr />\n <label for=\"passkeys\"><ox-i18n msgid=\"label.passkey\"></ox-i18n></label>\n <my-passkeys id=\"passkeys\"></my-passkeys>\n `\n : nothing\n }\n\n <footer>\n <p>\n ${i18next.t('text.click login history')}\n <a href=\"javascript:void(0);\" @click=${this.openLoginHistory.bind(this)}\n >${i18next.t('label.login_history')}</a\n >\n </p>\n </footer>\n </div>\n `\n }\n\n async onUsernameChanged(username) {\n if (!username) return\n\n var oldUsername = this.username\n\n try {\n const message = await auth.updateProfile({\n username\n })\n\n notify({\n level: 'info',\n message\n })\n } catch (e: any) {\n this.usernameEl.value = oldUsername || ''\n\n notify({\n level: 'error',\n message: 'message' in e ? e.message : e\n })\n }\n }\n\n async onNameChanged(name) {\n if (!name) return\n\n var oldName = this.name\n\n try {\n const message = await auth.updateProfile({\n name\n })\n\n notify({\n level: 'info',\n message\n })\n } catch (e: any) {\n this.nameEl.value = oldName || ''\n\n notify({\n level: 'error',\n message: 'message' in e ? e.message : e\n })\n }\n }\n\n async onEmailChanged(email) {\n if (!email) return\n\n var oldEmail = this.email\n\n try {\n const message = await auth.updateProfile({\n email\n })\n\n notify({\n level: 'info',\n message\n })\n } catch (e: any) {\n this.emailEl.value = oldEmail || ''\n\n notify({\n level: 'error',\n message: 'message' in e ? e.message : e\n })\n }\n }\n\n async onLocaleChanged(value) {\n if (!value) return\n\n var oldLocale = i18next.language\n\n try {\n const message = await auth.updateProfile({\n locale: value\n })\n\n i18next.changeLanguage(value)\n\n notify({\n level: 'info',\n message\n })\n } catch (e: any) {\n this.localeEl.value = oldLocale\n\n notify({\n level: 'error',\n message: 'message' in e ? e.message : e\n })\n }\n }\n\n openLoginHistory() {\n openPopup(html` <my-login-history></my-login-history> `, {\n title: i18next.t('label.login_history')\n })\n }\n\n deleteUser() {\n openPopup(html` <delete-user-popup></delete-user-popup> `, {\n title: i18next.t('label.delete account')\n })\n }\n\n\n\n get applicationMeta() {\n var iconLink: HTMLLinkElement | null = document.querySelector('link[rel=\"application-icon\"]')\n var titleMeta: HTMLMetaElement | null = document.querySelector('meta[name=\"application-name\"]')\n var descriptionMeta: HTMLMetaElement | null = document.querySelector('meta[name=\"application-description\"]')\n\n return {\n icon: iconLink?.href || '',\n title: titleMeta?.content || 'Things Factory',\n description: descriptionMeta?.content || 'Reimagining Software'\n }\n }\n}\n"]}
1
+ {"version":3,"file":"profile-component.js","sourceRoot":"","sources":["../../client/components/profile-component.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/i18n/ox-i18n.js'\nimport '@operato/i18n/ox-i18n-selector.js'\nimport './change-password.js'\nimport './delete-user-popup.js'\nimport './my-login-history.js'\nimport './my-passkeys.js'\n\nimport { gql } from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { FormFieldStyles } from '@operato/styles'\nimport { auth, getLanguages } from '@things-factory/auth-base/dist-client'\n\nconst isAvailableWebauthn = 'PublicKeyCredential' in window\n@customElement('profile-component')\nexport class ProfileComponent extends localize(i18next)(LitElement) {\n static styles = [\n FormFieldStyles,\n css`\n :host {\n display: block;\n background-color: var(--md-sys-color-background);\n padding: 15px 0;\n }\n .wrap {\n max-width: var(--profile-wrap-max-width, 400px);\n margin: auto;\n display: grid;\n grid-template-columns: 1fr 1fr;\n }\n\n * {\n box-sizing: border-box;\n }\n\n *:focus {\n outline: none;\n }\n\n /* 색·테두리·모서리·포커스·placeholder 는 FormFieldStyles 가 담당하고, 여기서는 치수만 둔다 */\n input {\n margin: var(--spacing-small) 0;\n padding: 9px;\n border-radius: var(--border-radius);\n font: var(--auth-input-field-font);\n width: var(--auth-input-field-width);\n }\n\n .user {\n background: url(/assets/images/icon-profile.png) center top no-repeat;\n margin: var(--profile-icon-margin);\n padding: 180px 20px 20px 20px;\n color: var(--md-sys-color-secondary);\n font: var(--header-bar-title);\n text-align: center;\n }\n\n hr {\n width: 100%;\n /* rgba(0,0,0,.1) 은 다크 배경에서 보이지 않는다 */\n border: dotted 1px var(--md-sys-color-outline-variant);\n }\n\n .wrap * {\n grid-column: span 2;\n }\n\n label {\n font: bold 14px var(--theme-font);\n color: var(--md-sys-color-primary);\n text-transform: capitalize;\n grid-column: 1;\n }\n\n .wrap *.inline {\n grid-column: unset;\n }\n\n /*\n * 언어 select 는 ox-i18n-selector 의 shadow root 안에 있어 위 input 규칙이 닿지 않는다.\n * 높이가 어긋나지 않도록 인풋과 **같은 값**을 토큰으로 넘긴다(padding 9px, 16px 글자).\n */\n ox-i18n-selector {\n --i18n-selector-field-width: var(--auth-input-field-width);\n /* 여백은 호스트에만 준다 — 내부에도 주면 두 번 더해져 인풋보다 벌어진다 */\n --i18n-selector-field-margin: 0;\n --i18n-selector-field-padding: 9px;\n --i18n-selector-field-border-radius: var(--border-radius);\n --i18n-selector-field-font: var(--auth-input-field-font);\n /* ox-i18n-selector 가 font 뒤에 font-size(기본 15px)를 다시 선언하므로 크기도 넘겨야 한다 */\n --i18n-selector-field-font-size: var(--profile-field-font-size, 16px);\n --i18n-selector-field-border: var(--input-field-border, 1px solid var(--md-sys-color-outline));\n --i18n-selector-field-background-color: var(\n --input-field-background,\n var(--md-sys-color-surface-container-highest)\n );\n --i18n-selector-field-color: var(--input-field-color, var(--md-sys-color-on-surface));\n margin: var(--spacing-small) 0;\n }\n\n md-text-button {\n text-transform: capitalize;\n }\n\n footer {\n padding: 20px;\n text-align: center;\n }\n\n footer p {\n font-size: 14px;\n margin-bottom: 5px;\n color: var(--md-sys-color-on-background);\n }\n\n footer a {\n color: var(--md-sys-color-primary);\n text-decoration: none;\n font-weight: bold;\n }\n `\n ]\n\n @property({ type: String }) username?: string\n @property({ type: String }) email?: string\n @property({ type: String }) name?: string\n\n @state() languages: { code: string; display: string }[] = []\n\n private rule = new QueryController(\n this,\n gql`\n query {\n passwordRule {\n lowerCase\n upperCase\n digit\n specialCharacter\n allowRepeat\n useTightPattern\n useLoosePattern\n tightCharacterLength\n looseCharacterLength\n }\n }\n `\n )\n\n get passwordRule(): {\n lowerCase?: boolean\n upperCase?: boolean\n digit?: boolean\n specialCharacter?: boolean\n allowRepeat?: boolean\n useTightPattern?: boolean\n useLoosePattern?: boolean\n tightCharacterLength?: number\n looseCharacterLength?: number\n } {\n return this.rule.data?.passwordRule ?? {}\n }\n\n @query('#username') usernameEl!: HTMLInputElement\n @query('#name') nameEl!: HTMLInputElement\n @query('#email') emailEl!: HTMLInputElement\n @query('#locale') localeEl!: HTMLInputElement\n\n async firstUpdated() {\n auth.on('profile', ({ credential }) => {\n this.setCredential(credential)\n })\n\n this.setCredential(auth.credential)\n\n this.languages = await getLanguages()\n }\n\n setCredential(credential) {\n if (credential) {\n this.username = credential.username\n this.name = credential.name\n this.email = credential.email\n } else {\n this.username = ''\n this.name = ''\n this.email = ''\n }\n }\n\n render() {\n return html`\n <div class=\"wrap\">\n <div class=\"user\">${this.username || ''}</div>\n\n <label for=\"username\"><ox-i18n slot=\"title\" msgid=\"label.user-id\"></ox-i18n></label>\n <input id=\"username\" @change=${e => this.onUsernameChanged(e.target.value)} .value=${this.username || ''} />\n\n <hr />\n\n <label for=\"name\"><ox-i18n slot=\"title\" msgid=\"label.name\"></ox-i18n></label>\n <input id=\"name\" @change=${e => this.onNameChanged(e.target.value)} .value=${this.name || ''} />\n\n <hr />\n\n <label for=\"email\"><ox-i18n slot=\"title\" msgid=\"label.email\"></ox-i18n></label>\n <input id=\"email\" type=\"email\" @change=${e => this.onEmailChanged(e.target.value)} .value=${this.email || ''} />\n\n <hr />\n\n <label for=\"locale\"><ox-i18n slot=\"title\" msgid=\"label.language\"></ox-i18n></label>\n <ox-i18n-selector\n id=\"locale\"\n @change=${e => this.onLocaleChanged(e.detail)}\n value=${i18next.language || 'en-US'}\n .languages=${this.languages}\n ></ox-i18n-selector>\n\n <hr />\n\n <label for=\"change-password\">\n <ox-i18n msgid=\"label.password\"></ox-i18n>\n </label>\n\n <change-password id=\"change-password\" .passwordRule=${this.passwordRule}></change-password>\n\n ${\n isAvailableWebauthn\n ? html`\n <hr />\n <label for=\"passkeys\"><ox-i18n msgid=\"label.passkey\"></ox-i18n></label>\n <my-passkeys id=\"passkeys\"></my-passkeys>\n `\n : nothing\n }\n\n <footer>\n <p>\n ${i18next.t('text.click login history')}\n <a href=\"javascript:void(0);\" @click=${this.openLoginHistory.bind(this)}\n >${i18next.t('label.login_history')}</a\n >\n </p>\n </footer>\n </div>\n `\n }\n\n async onUsernameChanged(username) {\n if (!username) return\n\n var oldUsername = this.username\n\n try {\n const message = await auth.updateProfile({\n username\n })\n\n notify({\n level: 'info',\n message\n })\n } catch (e: any) {\n this.usernameEl.value = oldUsername || ''\n\n notify({\n level: 'error',\n message: 'message' in e ? e.message : e\n })\n }\n }\n\n async onNameChanged(name) {\n if (!name) return\n\n var oldName = this.name\n\n try {\n const message = await auth.updateProfile({\n name\n })\n\n notify({\n level: 'info',\n message\n })\n } catch (e: any) {\n this.nameEl.value = oldName || ''\n\n notify({\n level: 'error',\n message: 'message' in e ? e.message : e\n })\n }\n }\n\n async onEmailChanged(email) {\n if (!email) return\n\n var oldEmail = this.email\n\n try {\n const message = await auth.updateProfile({\n email\n })\n\n notify({\n level: 'info',\n message\n })\n } catch (e: any) {\n this.emailEl.value = oldEmail || ''\n\n notify({\n level: 'error',\n message: 'message' in e ? e.message : e\n })\n }\n }\n\n async onLocaleChanged(value) {\n if (!value) return\n\n var oldLocale = i18next.language\n\n try {\n const message = await auth.updateProfile({\n locale: value\n })\n\n i18next.changeLanguage(value)\n\n notify({\n level: 'info',\n message\n })\n } catch (e: any) {\n this.localeEl.value = oldLocale\n\n notify({\n level: 'error',\n message: 'message' in e ? e.message : e\n })\n }\n }\n\n openLoginHistory() {\n openPopup(html` <my-login-history></my-login-history> `, {\n title: i18next.t('label.login_history')\n })\n }\n\n deleteUser() {\n openPopup(html` <delete-user-popup></delete-user-popup> `, {\n title: i18next.t('label.delete account')\n })\n }\n\n\n\n get applicationMeta() {\n var iconLink: HTMLLinkElement | null = document.querySelector('link[rel=\"application-icon\"]')\n var titleMeta: HTMLMetaElement | null = document.querySelector('meta[name=\"application-name\"]')\n var descriptionMeta: HTMLMetaElement | null = document.querySelector('meta[name=\"application-description\"]')\n\n return {\n icon: iconLink?.href || '',\n title: titleMeta?.content || 'Things Factory',\n description: descriptionMeta?.content || 'Reimagining Software'\n }\n }\n}\n"]}
@@ -31,14 +31,14 @@ declare const RoleTemplatePicker_base: (new (...args: any[]) => LitElement) & ty
31
31
  export declare class RoleTemplatePicker extends RoleTemplatePicker_base {
32
32
  static styles: CSSResultGroup;
33
33
  page?: any;
34
- private templates;
35
34
  private selected?;
36
35
  /** `undefined` means "the blank door" — name the seat yourself. */
37
36
  private scratch;
38
37
  private name;
39
38
  private description;
40
- connectedCallback(): Promise<void>;
41
- private fetchTemplates;
39
+ private offered;
40
+ private get templates();
41
+ updated(): void;
42
42
  render(): import("lit-html").TemplateResult<1>;
43
43
  /**
44
44
  * 「추가」가 무엇을 하는지 단추 줄에서 말한다. 이 창에서는 업무 · 권한을 고칠 수 없어 사람이 의아해한다 — 템플릿과