@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.
- package/dist-client/bootstrap.js +2 -2
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/components/access-decision-popup.d.ts +9 -8
- package/dist-client/components/access-decision-popup.js +46 -58
- package/dist-client/components/access-decision-popup.js.map +1 -1
- package/dist-client/components/access-request-popup.d.ts +13 -8
- package/dist-client/components/access-request-popup.js +78 -102
- package/dist-client/components/access-request-popup.js.map +1 -1
- package/dist-client/components/app-binding-detail.d.ts +7 -5
- package/dist-client/components/app-binding-detail.js +62 -82
- package/dist-client/components/app-binding-detail.js.map +1 -1
- package/dist-client/components/appliance-editor.d.ts +10 -9
- package/dist-client/components/appliance-editor.js +87 -138
- package/dist-client/components/appliance-editor.js.map +1 -1
- package/dist-client/components/application-editor.d.ts +7 -5
- package/dist-client/components/application-editor.js +58 -92
- package/dist-client/components/application-editor.js.map +1 -1
- package/dist-client/components/my-login-history.js +18 -40
- package/dist-client/components/my-login-history.js.map +1 -1
- package/dist-client/components/my-passkeys.d.ts +4 -3
- package/dist-client/components/my-passkeys.js +29 -51
- package/dist-client/components/my-passkeys.js.map +1 -1
- package/dist-client/components/my-roles.d.ts +3 -4
- package/dist-client/components/my-roles.js +36 -55
- package/dist-client/components/my-roles.js.map +1 -1
- package/dist-client/components/partner-role-editor.js +27 -50
- package/dist-client/components/partner-role-editor.js.map +1 -1
- package/dist-client/components/profile-component.d.ts +2 -2
- package/dist-client/components/profile-component.js +18 -26
- package/dist-client/components/profile-component.js.map +1 -1
- package/dist-client/components/role-template-picker.d.ts +3 -3
- package/dist-client/components/role-template-picker.js +28 -42
- package/dist-client/components/role-template-picker.js.map +1 -1
- package/dist-client/components/user-detail.d.ts +23 -22
- package/dist-client/components/user-detail.js +125 -179
- package/dist-client/components/user-detail.js.map +1 -1
- package/dist-client/components/user-invite.d.ts +8 -6
- package/dist-client/components/user-invite.js +106 -141
- package/dist-client/components/user-invite.js.map +1 -1
- package/dist-client/components/user-popups-standard.test.js +1 -1
- package/dist-client/components/user-popups-standard.test.js.map +1 -1
- package/dist-client/components/user-role-editor.js +72 -122
- package/dist-client/components/user-role-editor.js.map +1 -1
- package/dist-client/entity360/person-360.d.ts +8 -11
- package/dist-client/entity360/person-360.js +49 -68
- package/dist-client/entity360/person-360.js.map +1 -1
- package/dist-client/entries/oauth2/oauth2-decision-page.js +13 -25
- package/dist-client/entries/oauth2/oauth2-decision-page.js.map +1 -1
- package/dist-client/identity-confirmation/identity-confirmation.d.ts +13 -14
- package/dist-client/identity-confirmation/identity-confirmation.js +39 -45
- package/dist-client/identity-confirmation/identity-confirmation.js.map +1 -1
- package/dist-client/pages/audit/audit-page.d.ts +4 -4
- package/dist-client/pages/audit/audit-page.js +28 -39
- package/dist-client/pages/audit/audit-page.js.map +1 -1
- package/dist-client/pages/domain-link/domain-link-management.js +1 -1
- package/dist-client/pages/domain-link/domain-link-management.js.map +1 -1
- package/dist-client/pages/partner/partner-management.js +30 -68
- package/dist-client/pages/partner/partner-management.js.map +1 -1
- package/dist-client/pages/role/role-extra-removal.test.d.mts +1 -0
- package/dist-client/pages/role/role-extra-removal.test.mjs +73 -0
- package/dist-client/pages/role/role-extra-removal.test.mjs.map +1 -0
- package/dist-client/pages/role/role-list-page.js +20 -22
- package/dist-client/pages/role/role-list-page.js.map +1 -1
- package/dist-client/pages/role/role-privilege-page.d.ts +36 -8
- package/dist-client/pages/role/role-privilege-page.js +216 -158
- package/dist-client/pages/role/role-privilege-page.js.map +1 -1
- package/dist-client/pages/role/role-task-review.test.js +20 -16
- package/dist-client/pages/role/role-task-review.test.js.map +1 -1
- package/dist-client/pages/role/role-template-gap.test.js +8 -3
- package/dist-client/pages/role/role-template-gap.test.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/helps/auth/roles.en.md +13 -49
- package/helps/auth/roles.ko.md +13 -32
- package/package.json +11 -10
- package/tests/page-state.test.ts +2 -1
- package/tests/password-rule-shown.test.ts +2 -2
- package/tests/person-360-sections.test.ts +9 -5
- package/translations/en.json +5 -1
- package/translations/es.json +5 -1
- package/translations/ja.json +5 -1
- package/translations/ko.json +5 -1
- package/translations/ms.json +5 -1
- package/translations/zh.json +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"my-passkeys.js","sourceRoot":"","sources":["../../client/components/my-passkeys.ts"],"names":[],"mappings":";AAAA,OAAO,qCAAqC,CAAA;AAC5C,OAAO,4BAA4B,CAAA;AACnC,OAAO,yCAAyC,CAAA;AAEhD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AACjC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAE3D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAEtD,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAA;AAIpE;;;GAGG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAAtD;;QA4DI,aAAQ,GAAc,EAAE,CAAA;QAGzB,cAAS,GAAG,qBAAqB,IAAI,MAAM,CAAA;IAqKrD,CAAC;aAnOQ,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDlB,AAzDY,CAyDZ;IAOD,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,OAAO,CAAA;QAEnC,OAAO,IAAI,CAAA;QACP,IAAI,CAAC,QAAQ,CAAC,MAAM;YACpB,CAAC,CAAC,IAAI,CAAA;;gBAEE,IAAI,CAAC,QAAQ,CAAC,GAAG,CACjB,OAAO,CAAC,EAAE,CAAC,IAAI,CAAA;;;wBAGP,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE;gBAC5B,CAAC,CAAC,IAAI,CAAA;yCACW,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;qCAClC,OAAO,CAAC,IAAI,IAAI,EAAE;;uCAEhB,CAAC,CAAgB,EAAE,EAAE;oBAC9B,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO;wBAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAG,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,CAAA;oBACjF,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ;wBAAE,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAA;gBACnD,CAAC;oCACO,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAG,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC;6BACpF;gBACL,CAAC,CAAC,IAAI,CAAA,qBAAqB,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ;0CAC3D,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;;4CAEhB,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;;;4CAGtE,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;;;;iBAIjG,CACF;;WAEJ;YACH,CAAC,CAAC,IAAI,CAAA,mBAAmB,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,MAAM;;+BAExC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE;gDACJ,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC;;KAE1E,CAAA;IACH,CAAC;IAED,YAAY;QACV,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,KAAK,EAAE,CAAA;IAClC,CAAC;IAEO,IAAI,CAAC,OAAgB;QAC3B,MAAM,IAAI,GAAG,CAAC,KAAqB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAC3G,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,uBAAuB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;QAElF,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,2BAA2B,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAC9H,CAAC;IAEO,KAAK,CAAC,KAAK;QACjB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;YAClC,KAAK,EAAE,GAAG,CAAA;;;;;;;;;OAST;YACD,WAAW,EAAE,UAAU;SACxB,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,oBAAoB,CAAA;QACpD,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,mCAAmC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;YAC5F,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAA;YAEzD,MAAM,YAAY,GAAG,MAAM,gBAAgB,CACzC,MAAM,KAAK,CAAC,2BAA2B,EAAE;gBACvC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;aAC3E,CAAC,CACH,CAAA;YAED,IAAI,YAAY,CAAC,OAAO,KAAK,YAAY,EAAE,CAAC;gBAC1C,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,8CAA8C,CAAC,EAAE,CAAC,CAAA;gBAC7F,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;gBAClB,OAAM;YACR,CAAC;YAED,6FAA6F;YAC7F,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,YAAY,CAAC,MAAM,CAAC,CAAA;YACnE,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,gDAAgD,CAAC,EAAE,CAAC,CAAA;QAClG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,YAAY,CAAC,KAAK,CAAC;gBAAE,OAAM;YAE/B,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAA;YACpD,MAAM,CAAC;gBACL,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;gBAClD,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,2CAA2C,CAAC;aACnI,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,OAAgB;QAC1C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,EAAE,CAAA;QAC1B,MAAM,IAAI,CAAC,cAAc,CAAA;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAA4B,CAAA;QACrF,KAAK,EAAE,KAAK,EAAE,CAAA;QACd,KAAK,EAAE,MAAM,EAAE,CAAA;IACjB,CAAC;IAED,+FAA+F;IACvF,KAAK,CAAC,MAAM,CAAC,OAAgB,EAAE,KAAa;QAClD,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE;YAAE,OAAM;QACxC,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAA;QAEzB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;QACzB,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,OAAO,CAAC,IAAI;YAAE,OAAM;QAE1C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;YACnC,QAAQ,EAAE,GAAG,CAAA;;;;;;OAMZ;YACD,SAAS,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE;SACpC,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM;YAAE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;IAClD,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,OAAgB;QAC1C,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;YACpC,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC;YACxC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,qCAAqC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC;YAC5G,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE;YACnD,YAAY,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE;SACnD,CAAC,CAAA;QACF,IAAI,CAAC,SAAS;YAAE,OAAM;QAEtB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;YACnC,QAAQ,EAAE,GAAG,CAAA;;;;OAIZ;YACD,SAAS,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE;SAC9B,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM;YAAE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;IAClD,CAAC;;AAvKQ;IAAR,KAAK,EAAE;;4CAAyB;AACxB;IAAR,KAAK,EAAE;;4CAAkB;AA7Df,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CAoOtB","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
|
|
13
|
-
private
|
|
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
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
2
|
import gql from 'graphql-tag';
|
|
3
3
|
import { css, html, LitElement, nothing } from 'lit';
|
|
4
|
-
import { customElement
|
|
5
|
-
import {
|
|
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.
|
|
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":";AAAA,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,
|
|
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.
|
|
16
|
-
|
|
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":";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,MAAM,kBAAkB,CAAA;
|
|
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, 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
|
-
|
|
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 {
|
|
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.
|
|
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
|
-
|
|
130
|
-
|
|
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
|
-
|
|
41
|
-
private
|
|
39
|
+
private offered;
|
|
40
|
+
private get templates();
|
|
41
|
+
updated(): void;
|
|
42
42
|
render(): import("lit-html").TemplateResult<1>;
|
|
43
43
|
/**
|
|
44
44
|
* 「추가」가 무엇을 하는지 단추 줄에서 말한다. 이 창에서는 업무 · 권한을 고칠 수 없어 사람이 의아해한다 — 템플릿과
|