@things-factory/organization 10.1.226 → 10.1.228
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/pages/employee-profile/employee-profile-files.d.ts +23 -0
- package/dist-client/pages/employee-profile/employee-profile-files.js +50 -0
- package/dist-client/pages/employee-profile/employee-profile-files.js.map +1 -0
- package/dist-client/pages/employee-profile/employee-profile-form.d.ts +42 -10
- package/dist-client/pages/employee-profile/employee-profile-form.js +68 -22
- package/dist-client/pages/employee-profile/employee-profile-form.js.map +1 -1
- package/dist-client/pages/employee-profile/employee-profile-list-page.d.ts +19 -5
- package/dist-client/pages/employee-profile/employee-profile-list-page.js +89 -46
- package/dist-client/pages/employee-profile/employee-profile-list-page.js.map +1 -1
- package/dist-client/pages/employee-profile/employee-profile-preview.d.ts +28 -0
- package/dist-client/pages/employee-profile/employee-profile-preview.js +179 -0
- package/dist-client/pages/employee-profile/employee-profile-preview.js.map +1 -0
- package/dist-client/pages/employee-profile/my-employee-profile-page.d.ts +20 -2
- package/dist-client/pages/employee-profile/my-employee-profile-page.js +467 -93
- package/dist-client/pages/employee-profile/my-employee-profile-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/ai-entry/employee-profile-entry.d.ts +10 -0
- package/dist-server/ai-entry/employee-profile-entry.js +88 -0
- package/dist-server/ai-entry/employee-profile-entry.js.map +1 -0
- package/dist-server/ai-entry/entry-target-shape.d.ts +11 -1
- package/dist-server/ai-entry/entry-target-shape.js.map +1 -1
- package/dist-server/ai-entry/organization-entry-targets.d.ts +8 -0
- package/dist-server/ai-entry/organization-entry-targets.js +26 -1
- package/dist-server/ai-entry/organization-entry-targets.js.map +1 -1
- package/dist-server/service/employee-profile/employee-profile-document.d.ts +122 -0
- package/dist-server/service/employee-profile/employee-profile-document.js +439 -0
- package/dist-server/service/employee-profile/employee-profile-document.js.map +1 -0
- package/dist-server/service/employee-profile/employee-profile-mutation.d.ts +1 -0
- package/dist-server/service/employee-profile/employee-profile-mutation.js +29 -0
- package/dist-server/service/employee-profile/employee-profile-mutation.js.map +1 -1
- package/dist-server/service/employee-profile/employee-profile-query.d.ts +9 -1
- package/dist-server/service/employee-profile/employee-profile-query.js +83 -4
- package/dist-server/service/employee-profile/employee-profile-query.js.map +1 -1
- package/dist-server/service/employee-profile/employee-profile-rules.d.ts +6 -0
- package/dist-server/service/employee-profile/employee-profile-rules.js +24 -0
- package/dist-server/service/employee-profile/employee-profile-rules.js.map +1 -1
- package/dist-server/service/employee-profile/employee-profile-type.d.ts +11 -0
- package/dist-server/service/employee-profile/employee-profile-type.js +30 -1
- package/dist-server/service/employee-profile/employee-profile-type.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/tests/employee-profile-db.test.ts +65 -4
- package/tests/employee-profile-document.test.ts +219 -0
- package/tests/employee-profile-entry.test.ts +72 -0
- package/tests/employee-profile-rules.test.ts +33 -6
- package/translations/en.json +43 -3
- package/translations/es.json +43 -3
- package/translations/ja.json +43 -3
- package/translations/ko.json +43 -3
- package/translations/ms.json +43 -3
- package/translations/zh.json +43 -3
- package/dist-client/pages/employee-profile/employee-profile-workbook.d.ts +0 -33
- package/dist-client/pages/employee-profile/employee-profile-workbook.js +0 -87
- package/dist-client/pages/employee-profile/employee-profile-workbook.js.map +0 -1
- package/tests/employee-profile-workbook.test.ts +0 -89
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"my-employee-profile-page.js","sourceRoot":"","sources":["../../../client/pages/employee-profile/my-employee-profile-page.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,sCAAsC,CAAA;AAC7C,OAAO,sCAAsC,CAAA;AAE7C,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAExD,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,gBAAgB,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEnF,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAA+D,MAAM,yBAAyB,CAAA;AAEtJ,MAAM,cAAc,GAAG;;;;;;;;;CAStB,CAAA;AAED;;;;GAIG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;IAA/D;;QA2EI,SAAI,GAAgB,aAAa,CAAC,IAAI,CAAC,CAAA;QAChD,gFAAgF;QACvE,WAAM,GAAmB,IAAI,CAAA;QAC7B,YAAO,GAAG,KAAK,CAAA;QACf,UAAK,GAAY,IAAI,CAAA;QACrB,SAAI,GAAG,KAAK,CAAA;IAuJvB,CAAC;aAtOQ,WAAM,GAAG;QACd,eAAe;QACf,YAAY;QACZ,kBAAkB;QAClB,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmEF;KACF,AAxEY,CAwEZ;IASD,IAAI,OAAO;QACT,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;YAC7C,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;SACrJ,CAAA;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAY;QAC5B,IAAK,IAAY,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,EAAE,CAAA;IACzD,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;gBAClC,KAAK,EAAE,GAAG,CAAA;;;kCAGgB,cAAc;;SAEvC;gBACD,WAAW,EAAE,UAAU;aACxB,CAAC,CAAA;YACF,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAE,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;YACrD,IAAI,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;YAC3D,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAA;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QACpB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;YACpB,IAAI,CAAC,aAAa,EAAE,CAAA;QACtB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,aAAa,EAAE,CAAA;QACpB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;gBACnC,QAAQ,EAAE,GAAG,CAAA;;yDAEoC,cAAc;;SAE9D;gBACD,SAAS,EAAE,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aAClD,CAAC,CAAA;YACF,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAE,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;YACrD,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAA;YAC9D,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;QAC9C,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtE,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;YACjB,IAAI,CAAC,aAAa,EAAE,CAAA;QACtB,CAAC;IACH,CAAC;IAED,MAAM;QACJ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,MAAM,GAAG,GAAG,CAAC,KAA2B,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;QAEhF,OAAO,IAAI,CAAA,2BAA2B,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,WAAW,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE;QACrJ,IAAI,CAAC,MAAM,KAAK,KAAK;YACrB,CAAC,CAAC,IAAI,CAAA;;oBAEM,OAAO,CAAC,CAAC,CAAC,wCAAwC,CAAC;0BAC7C,OAAO,CAAC,CAAC,CAAC,8CAA8C,CAAC;4BACvD;YACpB,CAAC,CAAC,IAAI,CAAC,MAAM;gBACX,CAAC,CAAC,IAAI,CAAA;;0DAE0C,OAAO,CAAC,CAAC,CAAC,gCAAgC,CAAC;;;+BAGtE,OAAO,CAAC,CAAC,CAAC,gCAAgC,CAAC;2BAC/C,IAAI,CAAC,OAAO;8BACT,IAAI,CAAC,IAAI;2BACZ,CAAC,CAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;;;;;0DAKb,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;;+BAErE,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;2BAC9C,IAAI,CAAC,MAAM;8BACR,IAAI,CAAC,IAAI;2BACZ,CAAC,CAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;;qCAEjC,OAAO,CAAC,CAAC,CAAC,mCAAmC,CAAC;;;gBAGnE,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;mBAC5F;gBACT,CAAC,CAAC,OAAO;qBACE,CAAA;IACnB,CAAC;IAEO,aAAa,CAAC,GAAsB,EAAE,KAAa,EAAE,MAAsB;QACjF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC3B,MAAM,OAAO,GAAG,CAAC,IAAiB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;QAClF,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,IAAY,EAAE,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QAC/I,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;QAE7E,OAAO,IAAI,CAAA;;cAED,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;;8BAEA,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,0BAA0B,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;;;QAG5H,IAAI,CAAC,MAAM;YACX,CAAC,CAAC,IAAI,CAAC,GAAG,CACN,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAA;;kBAEd,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CACnB,KAAK,CAAC,KAAK,KAAK,UAAU;gBACxB,CAAC,CAAC,IAAI,CAAA;2BACC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;2CACN,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,IAAI,CAAC,IAAI,WAAW,CAAC,CAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;+BACxH;gBACX,CAAC,CAAC,IAAI,CAAA;2BACC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;;iCAEhB,KAAK,CAAC,KAAK,IAAI,MAAM;mCACnB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE;sCAClB,IAAI,CAAC,IAAI;mCACZ,CAAC,CAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;;+BAEzD,CACd;;;;;wBAKO,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;6BACrB,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;4BAC3B,IAAI,CAAC,IAAI;yBACZ,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;;;;mBAIzD,CACR;YACH,CAAC,CAAC,IAAI,CAAA,oBAAoB,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC,MAAM;eACnE,CAAA;IACb,CAAC;;AA3JQ;IAAR,KAAK,EAAE;;mDAAwC;AAEvC;IAAR,KAAK,EAAE;;qDAA8B;AAC7B;IAAR,KAAK,EAAE;;sDAAgB;AACf;IAAR,KAAK,EAAE;;oDAAsB;AACrB;IAAR,KAAK,EAAE;;mDAAa;AAhFV,qBAAqB;IADjC,aAAa,CAAC,0BAA0B,CAAC;GAC7B,qBAAqB,CAuOjC","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/list-state/ox-empty-note.js'\nimport '@operato/list-state/ox-page-state.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { ButtonStyles, DocumentPageStyles, FormFieldStyles } from '@operato/styles'\n\nimport { PROFILE_SECTIONS, profileFormOf, profileInputOf, type ProfileField, type ProfileForm, type ProfileSectionKey } from './employee-profile-form'\n\nconst PROFILE_FIELDS = `\n id\n summary\n skills\n educations { school major degree startedOn endedOn }\n certificates { name issuer acquiredOn }\n careers { company department position startedOn endedOn duties }\n projects { name client startedOn endedOn role duties technologies }\n updatedAt\n`\n\n/**\n * 내 프로필 — the employee writes their own career profile: a summary, skills, and the rows of education,\n * certificates, past jobs and projects; sales attaches it to quotations (ADR-0169 decisions 2 · 5). Saved whole.\n * An account not linked to an employee record has no profile to write, and is told so before anything is typed.\n */\n@customElement('my-employee-profile-page')\nexport class MyEmployeeProfilePage extends localize(i18next)(PageView) {\n static styles = [\n FormFieldStyles,\n ButtonStyles,\n DocumentPageStyles,\n css`\n label {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small, 4px);\n font-size: var(--ui-t-micro, 11px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n label > :is(input, textarea) {\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n input,\n textarea {\n box-sizing: border-box;\n width: 100%;\n font-family: inherit;\n }\n input {\n height: var(--form-element-height-medium, 32px);\n }\n textarea {\n min-height: 72px;\n resize: vertical;\n }\n textarea.summary {\n min-height: 120px;\n }\n .hint {\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n /* A row of a section: its fields in a grid, the button that takes it away at its end. */\n .row {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: var(--spacing-large, 12px);\n align-items: start;\n padding: var(--spacing-large, 12px) 0;\n border-top: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n }\n .row:first-of-type {\n border-top: 0;\n padding-top: 0;\n }\n .fields {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n }\n .fields .wide {\n grid-column: 1 / -1;\n }\n .row > button {\n margin-top: 18px;\n }\n .empty {\n margin: 0;\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n @media (pointer: coarse) {\n input,\n textarea {\n font-size: 16px;\n }\n }\n `\n ]\n\n @state() form: ProfileForm = profileFormOf(null)\n /** Whether the account is linked to an employee record - unknown until read. */\n @state() linked: boolean | null = null\n @state() loading = false\n @state() error: unknown = null\n @state() busy = false\n\n get context() {\n return {\n title: i18next.t('title.my-employee-profile'),\n frame: 'document',\n actions: this.linked && !this.busy ? [{ title: i18next.t('button.save'), icon: 'save', emphasis: { raised: true }, action: () => this.save() }] : []\n }\n }\n\n async pageUpdated(changes: any) {\n if ((this as any).active && changes.active) this.load()\n }\n\n private async load() {\n this.loading = true\n this.error = null\n try {\n const response = await client.query({\n query: gql`\n query {\n myEmployees { id }\n myEmployeeProfile { ${PROFILE_FIELDS} }\n }\n `,\n fetchPolicy: 'no-cache'\n })\n if (response.errors?.length) throw response.errors[0]\n this.linked = (response.data?.myEmployees ?? []).length > 0\n this.form = profileFormOf(response.data?.myEmployeeProfile)\n } catch (error) {\n this.error = error\n } finally {\n this.loading = false\n this.updateContext()\n }\n }\n\n private async save() {\n this.busy = true\n this.updateContext()\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($profile: EmployeeProfileInput!) {\n saveMyEmployeeProfile(profile: $profile) { ${PROFILE_FIELDS} }\n }\n `,\n variables: { profile: profileInputOf(this.form) }\n })\n if (response.errors?.length) throw response.errors[0]\n this.form = profileFormOf(response.data.saveMyEmployeeProfile)\n notify({ message: i18next.t('text.saved') })\n } catch (error: any) {\n notify({ level: 'error', message: error?.message ?? String(error) })\n } finally {\n this.busy = false\n this.updateContext()\n }\n }\n\n render() {\n const form = this.form\n const set = (patch: Partial<ProfileForm>) => (this.form = { ...form, ...patch })\n\n return html`<ox-page-state .loading=${this.loading && this.linked === null} .error=${this.linked === null ? this.error : null} @retry=${() => this.load()}>\n ${this.linked === false\n ? html`<ox-empty-note\n icon=\"badge\"\n title=${i18next.t('text.employee-profile-not-linked-title')}\n description=${i18next.t('text.employee-profile-not-linked-description')}\n ></ox-empty-note>`\n : this.linked\n ? html`<div class=\"page\">\n <section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('label.employee-profile-summary')}</h3></header>\n <textarea\n class=\"summary\"\n aria-label=${i18next.t('label.employee-profile-summary')}\n .value=${form.summary}\n ?disabled=${this.busy}\n @input=${(e: any) => set({ summary: e.target.value })}\n ></textarea>\n </section>\n\n <section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('label.employee-profile-skills')}</h3></header>\n <input\n aria-label=${i18next.t('label.employee-profile-skills')}\n .value=${form.skills}\n ?disabled=${this.busy}\n @input=${(e: any) => set({ skills: e.target.value })}\n />\n <span class=\"hint\">${i18next.t('text.employee-profile-skills-hint')}</span>\n </section>\n\n ${PROFILE_SECTIONS.map(section => this.renderSection(section.key, section.title, section.fields))}\n </div>`\n : nothing}\n </ox-page-state>`\n }\n\n private renderSection(key: ProfileSectionKey, title: string, fields: ProfileField[]) {\n const rows = this.form[key]\n const setRows = (next: typeof rows) => (this.form = { ...this.form, [key]: next })\n const change = (index: number, name: string, value: string) => setRows(rows.map((row, at) => (at === index ? { ...row, [name]: value } : row)))\n const blank = () => Object.fromEntries(fields.map(field => [field.name, '']))\n\n return html`<section class=\"page-section\">\n <header class=\"page-section-header\">\n <h3>${i18next.t(title)}</h3>\n <div class=\"page-section-actions\">\n <button ?disabled=${this.busy} @click=${() => setRows([...rows, blank()])}><md-icon>add</md-icon>${i18next.t('button.add')}</button>\n </div>\n </header>\n ${rows.length\n ? rows.map(\n (row, index) => html`<div class=\"row\">\n <div class=\"fields\">\n ${fields.map(field =>\n field.input === 'textarea'\n ? html`<label class=\"wide\"\n >${i18next.t(field.label)}\n <textarea .value=${row[field.name] ?? ''} ?disabled=${this.busy} @input=${(e: any) => change(index, field.name, e.target.value)}></textarea>\n </label>`\n : html`<label\n >${i18next.t(field.label)}\n <input\n type=${field.input ?? 'text'}\n .value=${row[field.name] ?? ''}\n ?disabled=${this.busy}\n @input=${(e: any) => change(index, field.name, e.target.value)}\n />\n </label>`\n )}\n </div>\n <button\n quiet\n icon-only\n title=${i18next.t('button.delete')}\n aria-label=${i18next.t('button.delete')}\n ?disabled=${this.busy}\n @click=${() => setRows(rows.filter((_, at) => at !== index))}\n >\n <md-icon>close</md-icon>\n </button>\n </div>`\n )\n : html`<p class=\"empty\">${i18next.t('text.employee-profile-no-rows')}</p>`}\n </section>`\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"my-employee-profile-page.js","sourceRoot":"","sources":["../../../client/pages/employee-profile/my-employee-profile-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/list-state/ox-empty-note.js'\nimport '@operato/list-state/ox-page-state.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { ButtonStyles, DocumentPageStyles, FormFieldStyles } from '@operato/styles'\nimport { getLanguages } from '@things-factory/auth-base/dist-client'\n\nimport {\n addSkills,\n blankRow,\n completenessOf,\n headlineOf,\n periodLabelOf,\n PROFILE_SECTIONS,\n profileFormOf,\n profileInputOf,\n type ProfileField,\n type ProfileForm,\n type ProfileRow,\n type ProfileSection\n} from './employee-profile-form'\nimport { readerLanguageOf, type Language } from './employee-profile-files'\nimport { openProfilePreview } from './employee-profile-preview'\n\nconst PROFILE_FIELDS = `\n id\n summary\n skills\n educations { school major degree startedOn endedOn }\n certificates { name issuer acquiredOn }\n careers { company department position startedOn endedOn duties }\n projects { name client startedOn endedOn role duties technologies }\n updatedAt\n`\n\nconst SUMMARY_LIMIT = 500\n\n/**\n * 내 프로필 — the employee writes their own career profile: a summary, skills, and the rows of education,\n * certificates, past jobs and projects; sales attaches it to quotations (ADR-0169 decisions 2 · 5). Saved whole.\n *\n * The page is built to be filled in: who it is about and how complete it is stand at the top, each missing essential a\n * click away; each row is a card whose headline reads like the document's line; a section with nothing yet says what\n * it is for; and the document itself is one click away (PDF), as sales will hand it in. An account not linked to an\n * employee record has no profile to write, and is told so before anything is typed.\n */\n@customElement('my-employee-profile-page')\nexport class MyEmployeeProfilePage extends localize(i18next)(PageView) {\n static styles = [\n FormFieldStyles,\n ButtonStyles,\n DocumentPageStyles,\n css`\n label {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small, 4px);\n min-width: 0;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n label > :is(input, textarea) {\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n input,\n textarea {\n box-sizing: border-box;\n width: 100%;\n font-family: inherit;\n }\n input:not([type='checkbox']) {\n height: var(--form-element-height-medium, 32px);\n }\n textarea {\n min-height: 72px;\n resize: vertical;\n line-height: 1.5;\n }\n .muted {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n /* ── Who it is about, and how far along ─────────────────────────────── */\n .hero {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(240px, 340px);\n gap: var(--spacing-huge, 24px);\n align-items: center;\n }\n .who {\n display: flex;\n align-items: center;\n gap: var(--spacing-large, 12px);\n min-width: 0;\n }\n .avatar {\n flex: none;\n display: grid;\n place-items: center;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--md-sys-color-primary-container);\n color: var(--md-sys-color-on-primary-container);\n font-size: 22px;\n font-weight: 700;\n }\n .who h2 {\n margin: 0;\n font-size: var(--ui-t-headline, 20px);\n font-weight: 700;\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n .who p {\n margin: 2px 0 0;\n font-size: var(--ui-t-body, 13px);\n }\n .progress {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small, 4px);\n }\n .progress-head {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n font-size: var(--ui-t-small, 11.5px);\n }\n .progress-head strong {\n font-size: var(--ui-t-title, 15px);\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n .bar {\n height: 8px;\n border-radius: 4px;\n background: var(--md-sys-color-surface-container-high);\n overflow: hidden;\n }\n .bar > span {\n display: block;\n height: 100%;\n border-radius: 4px;\n background: var(--md-sys-color-primary);\n transition: width 0.3s ease;\n }\n .missing {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-small, 4px);\n margin-top: var(--spacing-small, 4px);\n font-size: var(--ui-t-small, 11.5px);\n }\n .hero-foot {\n grid-column: 1 / -1;\n display: flex;\n align-items: center;\n gap: var(--spacing-medium, 8px);\n padding-top: var(--spacing-large, 12px);\n border-top: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n font-size: var(--ui-t-small, 11.5px);\n }\n .hero-foot .unsaved {\n color: var(--md-sys-color-tertiary, var(--md-sys-color-primary));\n font-weight: 600;\n }\n .hero-foot button {\n margin-left: auto;\n }\n\n /* ── A section ─────────────────────────────────────────────────────── */\n .page-section-header h3 {\n display: flex;\n align-items: center;\n gap: var(--spacing-medium, 8px);\n }\n .page-section-header h3 md-icon {\n --md-icon-size: 20px;\n color: var(--md-sys-color-primary);\n }\n .count {\n min-width: 20px;\n padding: 1px 7px;\n border-radius: 10px;\n background: var(--md-sys-color-surface-container-high);\n font-size: var(--ui-t-small, 11.5px);\n font-weight: 600;\n text-align: center;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .counter {\n margin-left: auto;\n font-size: var(--ui-t-small, 11.5px);\n }\n .summary textarea {\n min-height: 132px;\n }\n\n /* Skills as chips, the field to add more inside the same box. */\n .chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-small, 4px);\n min-height: 88px;\n align-content: flex-start;\n box-sizing: border-box;\n padding: var(--spacing-medium, 8px);\n border: 1px solid var(--md-sys-color-outline);\n border-radius: var(--input-field-border-radius, var(--md-sys-shape-corner-small, 4px));\n background: var(--md-sys-color-surface-container-highest);\n }\n .chips:focus-within {\n border-color: var(--md-sys-color-primary);\n }\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n height: 26px;\n padding: 0 4px 0 10px;\n border-radius: 13px;\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n font-size: var(--ui-t-body, 13px);\n }\n .chip button {\n height: 20px;\n width: 20px;\n padding: 0;\n border: 0;\n background: transparent;\n }\n .chip button md-icon {\n --md-icon-size: 14px;\n color: inherit;\n }\n .chips input {\n flex: 1 1 140px;\n width: auto;\n height: 26px;\n border: 0;\n padding: 0 4px;\n background: transparent;\n outline: none;\n }\n\n /* A row of a section is a card: its line as the document reads it, then its fields. */\n .entries {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n .entry {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-large, 12px);\n }\n .entry-head {\n display: flex;\n align-items: center;\n gap: var(--spacing-medium, 8px);\n min-width: 0;\n }\n .entry-head strong {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n .entry-head strong.untitled {\n font-weight: 400;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .entry-head .period {\n flex: none;\n font-size: var(--ui-t-small, 11.5px);\n }\n .entry-head button {\n margin-left: auto;\n }\n .fields {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n }\n .fields .wide {\n grid-column: 1 / -1;\n }\n .fields .start {\n grid-column-start: 1;\n }\n .end {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: var(--spacing-medium, 8px);\n align-items: end;\n min-width: 0;\n }\n .ongoing {\n flex-direction: row;\n align-items: center;\n gap: var(--spacing-small, 4px);\n height: var(--form-element-height-medium, 32px);\n font-size: var(--ui-t-body, 13px);\n white-space: nowrap;\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n .ongoing input {\n width: auto;\n }\n\n /* A section with nothing yet: what it is for, and the way to begin. */\n .empty-slot {\n display: flex;\n align-items: center;\n gap: var(--spacing-large, 12px);\n padding: var(--spacing-large, 12px) 16px;\n border: 1px dashed var(--md-sys-color-outline-variant);\n border-radius: var(--ui-r, 10px);\n font-size: var(--ui-t-body, 13px);\n }\n .empty-slot button {\n margin-left: auto;\n }\n\n @media (max-width: 720px) {\n .hero {\n grid-template-columns: 1fr;\n }\n .empty-slot {\n flex-direction: column;\n align-items: flex-start;\n }\n .empty-slot button {\n margin-left: 0;\n }\n }\n @media (pointer: coarse) {\n input,\n textarea {\n font-size: 16px;\n }\n }\n `\n ]\n\n @state() form: ProfileForm = profileFormOf(null)\n /** Who the profile is about - the employee record's basics. */\n @state() me: any = null\n /** Whether the account is linked to an employee record - unknown until read. */\n @state() linked: boolean | null = null\n @state() loading = false\n @state() error: unknown = null\n @state() busy = false\n @state() updatedAt: string | null = null\n /** The form as last read or saved - what is written differs from it until saved. */\n private saved = JSON.stringify(profileInputOf(profileFormOf(null)))\n\n private get dirty() {\n return JSON.stringify(profileInputOf(this.form)) !== this.saved\n }\n\n get context() {\n return {\n title: i18next.t('title.my-employee-profile'),\n frame: 'document',\n actions: this.linked ? [{ title: i18next.t('button.save'), icon: 'save', emphasis: { raised: true }, action: () => this.save() }] : []\n }\n }\n\n async pageUpdated(changes: any) {\n if ((this as any).active && changes.active) this.load()\n }\n\n private async load() {\n this.loading = true\n this.error = null\n try {\n const response = await client.query({\n query: gql`\n query {\n myEmployees { id name jobPosition jobResponsibility hiredOn department { name } }\n myEmployeeProfile { ${PROFILE_FIELDS} }\n }\n `,\n fetchPolicy: 'no-cache'\n })\n if (response.errors?.length) throw response.errors[0]\n this.me = response.data?.myEmployees?.[0] ?? null\n this.linked = !!this.me\n this.hold(response.data?.myEmployeeProfile)\n } catch (error) {\n this.error = error\n } finally {\n this.loading = false\n this.updateContext()\n }\n }\n\n private hold(profile: any) {\n this.form = profileFormOf(profile)\n this.saved = JSON.stringify(profileInputOf(this.form))\n this.updatedAt = profile?.updatedAt ?? null\n }\n\n private async save(): Promise<boolean> {\n if (this.busy) return false\n this.busy = true\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($profile: EmployeeProfileInput!) {\n saveMyEmployeeProfile(profile: $profile) { ${PROFILE_FIELDS} }\n }\n `,\n variables: { profile: profileInputOf(this.form) }\n })\n if (response.errors?.length) throw response.errors[0]\n this.hold(response.data.saveMyEmployeeProfile)\n notify({ message: i18next.t('text.saved') })\n return true\n } catch (error: any) {\n notify({ level: 'error', message: error?.message ?? String(error) })\n return false\n } finally {\n this.busy = false\n }\n }\n\n /** The document as sales will hand it in - what is written is saved first, so the preview shows it. */\n private async preview() {\n if (this.dirty && !(await this.save())) return\n const languages = ((await getLanguages()) ?? []) as Language[]\n openProfilePreview({ own: true }, languages, readerLanguageOf(languages))\n }\n\n private goTo(key: string) {\n const section = this.renderRoot.querySelector<HTMLElement>(`#${key}`)\n section?.scrollIntoView({ behavior: 'smooth', block: 'start' })\n section?.querySelector<HTMLElement>('textarea, input:not([type=\"checkbox\"])')?.focus({ preventScroll: true })\n }\n\n render() {\n return html`<ox-page-state .loading=${this.loading && this.linked === null} .error=${this.linked === null ? this.error : null} @retry=${() => this.load()}>\n ${this.linked === false\n ? html`<ox-empty-note\n icon=\"badge\"\n title=${i18next.t('text.employee-profile-not-linked-title')}\n description=${i18next.t('text.employee-profile-not-linked-description')}\n ></ox-empty-note>`\n : this.linked\n ? html`<div class=\"page\">\n ${this.renderHero()}\n <div class=\"page-section-grid\">${this.renderSummary()} ${this.renderSkills()}</div>\n ${PROFILE_SECTIONS.map(section => this.renderSection(section))}\n </div>`\n : nothing}\n </ox-page-state>`\n }\n\n private renderHero() {\n const me = this.me ?? {}\n const { percent, missing } = completenessOf(this.form)\n const role = [me.jobPosition, me.jobResponsibility].filter(Boolean).join(' / ')\n const day = (value?: string | null) => (value ? String(value).slice(0, 10).replace(/-/g, '.') : '')\n\n return html`<section class=\"hero page-card\">\n <div class=\"who\">\n <div class=\"avatar\" aria-hidden=\"true\">${(me.name ?? '?').trim().slice(0, 1)}</div>\n <div>\n <h2>${me.name ?? ''}</h2>\n <p class=\"muted\">${[me.department?.name, role].filter(Boolean).join(' · ')}</p>\n ${me.hiredOn ? html`<p class=\"muted\">${i18next.t('label.hired-on')} ${day(me.hiredOn)}</p>` : nothing}\n </div>\n </div>\n\n <div class=\"progress\">\n <div class=\"progress-head\">\n <span class=\"muted\">${i18next.t('text.employee-profile-completeness')}</span>\n <strong>${percent}%</strong>\n </div>\n <div class=\"bar\" role=\"progressbar\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=${percent}><span style=\"width:${percent}%\"></span></div>\n ${missing.length\n ? html`<div class=\"missing\">\n <span class=\"muted\">${i18next.t('text.employee-profile-to-fill')}</span>\n ${missing.map(key => html`<button small quiet @click=${() => this.goTo(key)}>${i18next.t(`label.employee-profile-${key}`)}</button>`)}\n </div>`\n : html`<div class=\"missing muted\">${i18next.t('text.employee-profile-ready')}</div>`}\n </div>\n\n <div class=\"hero-foot\">\n ${this.dirty\n ? html`<span class=\"unsaved\">${i18next.t('text.employee-profile-unsaved')}</span>`\n : this.updatedAt\n ? html`<span class=\"muted\">${i18next.t('label.employee-profile-updated-at')} ${day(this.updatedAt)}</span>`\n : nothing}\n <button ?disabled=${this.busy} @click=${() => this.preview()}><md-icon>preview</md-icon>${i18next.t('button.employee-profile-preview')}</button>\n </div>\n </section>`\n }\n\n private renderSummary() {\n const summary = this.form.summary\n return html`<section id=\"summary\" class=\"page-section summary\">\n <header class=\"page-section-header\">\n <h3><md-icon>person</md-icon>${i18next.t('label.employee-profile-summary')}</h3>\n <span class=\"counter muted\">${summary.length} / ${SUMMARY_LIMIT}</span>\n </header>\n <textarea\n aria-label=${i18next.t('label.employee-profile-summary')}\n maxlength=${SUMMARY_LIMIT}\n placeholder=${i18next.t('text.employee-profile-summary-example')}\n .value=${summary}\n @input=${(e: any) => (this.form = { ...this.form, summary: e.target.value })}\n ></textarea>\n </section>`\n }\n\n private renderSkills() {\n const skills = this.form.skills\n const add = (input: HTMLInputElement) => {\n this.form = { ...this.form, skills: addSkills(skills, input.value) }\n input.value = ''\n }\n\n return html`<section id=\"skills\" class=\"page-section\">\n <header class=\"page-section-header\">\n <h3><md-icon>construction</md-icon>${i18next.t('label.employee-profile-skills')}</h3>\n ${skills.length ? html`<span class=\"count\">${skills.length}</span>` : nothing}\n </header>\n <div class=\"chips\" @click=${(e: Event) => (e.currentTarget as HTMLElement).querySelector('input')?.focus()}>\n ${skills.map(\n skill => html`<span class=\"chip\"\n >${skill}\n <button\n unstyled\n title=${i18next.t('button.delete')}\n aria-label=${`${i18next.t('button.delete')} ${skill}`}\n @click=${() => (this.form = { ...this.form, skills: skills.filter(one => one !== skill) })}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n <input\n aria-label=${i18next.t('label.employee-profile-skills')}\n placeholder=${i18next.t('text.employee-profile-skill-placeholder')}\n @keydown=${(e: KeyboardEvent) => {\n const input = e.target as HTMLInputElement\n if ((e.key === 'Enter' || e.key === ',') && !e.isComposing) {\n e.preventDefault()\n add(input)\n } else if (e.key === 'Backspace' && !input.value && skills.length) {\n this.form = { ...this.form, skills: skills.slice(0, -1) }\n }\n }}\n @blur=${(e: Event) => add(e.target as HTMLInputElement)}\n />\n </div>\n </section>`\n }\n\n private renderSection(section: ProfileSection) {\n const rows = this.form[section.key]\n /* Each change reads the rows as they are now - two inputs before a render must not undo each other. */\n const current = () => this.form[section.key]\n const setRows = (next: ProfileRow[]) => (this.form = { ...this.form, [section.key]: next })\n const change = (index: number, patch: ProfileRow) => setRows(current().map((row, at) => (at === index ? { ...row, ...patch } : row)))\n const remove = (index: number) => setRows(current().filter((_, at) => at !== index))\n /* The newest first, as the document is read; its first field takes the cursor. */\n const add = async () => {\n setRows([blankRow(section), ...current()])\n await this.updateComplete\n this.renderRoot.querySelector<HTMLInputElement>(`#${section.key} .entry input`)?.focus()\n }\n\n return html`<section id=${section.key} class=\"page-section\">\n <header class=\"page-section-header\">\n <h3><md-icon>${section.icon}</md-icon>${i18next.t(section.title)}</h3>\n ${rows.length ? html`<span class=\"count\">${rows.length}</span>` : nothing}\n ${rows.length\n ? html`<div class=\"page-section-actions\">\n <button @click=${add}><md-icon>add</md-icon>${i18next.t('button.add')}</button>\n </div>`\n : nothing}\n </header>\n ${rows.length\n ? html`<div class=\"entries\">${rows.map((row, index) => this.renderEntry(section, row, index, change, () => remove(index)))}</div>`\n : html`<div class=\"empty-slot\">\n <span class=\"muted\">${i18next.t(`text.employee-profile-why-${section.key}`)}</span>\n <button @click=${add}><md-icon>add</md-icon>${i18next.t('button.add')}</button>\n </div>`}\n </section>`\n }\n\n private renderEntry(section: ProfileSection, row: ProfileRow, index: number, change: (index: number, patch: ProfileRow) => void, remove: () => void) {\n const headline = headlineOf(section, row)\n const period = periodLabelOf(row, i18next.t('text.employee-profile-doc-ongoing'))\n const field = (one: ProfileField) => {\n const label = i18next.t(one.label)\n if (one.input === 'textarea') {\n return html`<label class=\"wide\"\n >${label}<textarea .value=${row[one.name] ?? ''} @input=${(e: any) => change(index, { [one.name]: e.target.value })}></textarea\n ></label>`\n }\n const ended = one.name === 'endedOn' && section.ongoing\n const input = html`<input\n type=${one.input ?? 'text'}\n .value=${ended && row.ongoing ? '' : (row[one.name] ?? '')}\n ?disabled=${ended && !!row.ongoing}\n @input=${(e: any) => change(index, { [one.name]: e.target.value })}\n />`\n /* A period begins a line of its own, its end beside it. */\n if (!ended) return html`<label class=${one.name === 'startedOn' ? 'start' : ''}>${label}${input}</label>`\n /* The end and 「going on」 share one cell - the period stays on one line. */\n return html`<div class=\"end\">\n <label>${label}${input}</label>\n <label class=\"ongoing\"\n ><input\n type=\"checkbox\"\n .checked=${!!row.ongoing}\n @change=${(e: any) => change(index, { ongoing: e.target.checked ? 'true' : '', ...(e.target.checked ? { endedOn: '' } : {}) })}\n />${i18next.t('label.employee-profile-ongoing')}</label\n >\n </div>`\n }\n\n return html`<div class=\"entry page-card\">\n <div class=\"entry-head\">\n <strong class=${headline ? '' : 'untitled'}>${headline || i18next.t('text.employee-profile-new-entry')}</strong>\n ${period ? html`<span class=\"period muted\">${period}</span>` : nothing}\n <button quiet icon-only title=${i18next.t('button.delete')} aria-label=${i18next.t('button.delete')} @click=${remove}><md-icon>delete</md-icon></button>\n </div>\n <div class=\"fields\">${section.fields.map(field)}</div>\n </div>`\n }\n}\n"]}
|