@things-factory/compliance 10.1.258 → 10.1.260

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist-client/components/my-trainings.js +6 -2
  2. package/dist-client/components/my-trainings.js.map +1 -1
  3. package/dist-client/components/training-session-form.d.ts +3 -0
  4. package/dist-client/components/training-session-form.js +24 -1
  5. package/dist-client/components/training-session-form.js.map +1 -1
  6. package/dist-client/legal-record/legal-child-grid.d.ts +12 -2
  7. package/dist-client/legal-record/legal-child-grid.js +22 -2
  8. package/dist-client/legal-record/legal-child-grid.js.map +1 -1
  9. package/dist-client/legal-record/legal-grid.d.ts +1 -1
  10. package/dist-client/legal-record/legal-grid.js +4 -2
  11. package/dist-client/legal-record/legal-grid.js.map +1 -1
  12. package/dist-client/pages/compliance-case-list.js +1 -1
  13. package/dist-client/pages/compliance-case-list.js.map +1 -1
  14. package/dist-client/pages/dispute-list.js +5 -3
  15. package/dist-client/pages/dispute-list.js.map +1 -1
  16. package/dist-client/pages/invention-list.js +4 -3
  17. package/dist-client/pages/invention-list.js.map +1 -1
  18. package/dist-client/pages/legal-registration-list.js +6 -4
  19. package/dist-client/pages/legal-registration-list.js.map +1 -1
  20. package/dist-client/pages/privacy-record-list.d.ts +1 -1
  21. package/dist-client/pages/privacy-record-list.js +16 -6
  22. package/dist-client/pages/privacy-record-list.js.map +1 -1
  23. package/dist-client/pages/regulation-list.js +4 -4
  24. package/dist-client/pages/regulation-list.js.map +1 -1
  25. package/dist-client/pages/seal-use-list.d.ts +7 -0
  26. package/dist-client/pages/seal-use-list.js +4 -4
  27. package/dist-client/pages/seal-use-list.js.map +1 -1
  28. package/dist-client/pages/training-list.d.ts +16 -2
  29. package/dist-client/pages/training-list.js +63 -31
  30. package/dist-client/pages/training-list.js.map +1 -1
  31. package/dist-client/tsconfig.tsbuildinfo +1 -1
  32. package/dist-server/service/training/training-checks.d.ts +5 -0
  33. package/dist-server/service/training/training-checks.js +24 -0
  34. package/dist-server/service/training/training-checks.js.map +1 -1
  35. package/dist-server/service/training/training-query.d.ts +2 -0
  36. package/dist-server/service/training/training-query.js +11 -0
  37. package/dist-server/service/training/training-query.js.map +1 -1
  38. package/dist-server/service/training/training-register.js +6 -0
  39. package/dist-server/service/training/training-register.js.map +1 -1
  40. package/dist-server/service/training/training-rules.d.ts +7 -0
  41. package/dist-server/service/training/training-rules.js +8 -0
  42. package/dist-server/service/training/training-rules.js.map +1 -1
  43. package/dist-server/service/training/training-service.d.ts +11 -0
  44. package/dist-server/service/training/training-service.js +104 -3
  45. package/dist-server/service/training/training-service.js.map +1 -1
  46. package/dist-server/service/training/training-type.d.ts +1 -0
  47. package/dist-server/service/training/training-type.js +4 -0
  48. package/dist-server/service/training/training-type.js.map +1 -1
  49. package/dist-server/service/training/training.d.ts +13 -0
  50. package/dist-server/service/training/training.js +51 -1
  51. package/dist-server/service/training/training.js.map +1 -1
  52. package/dist-server/tsconfig.tsbuildinfo +1 -1
  53. package/package.json +19 -18
  54. package/translations/en.json +19 -7
  55. package/translations/es.json +18 -6
  56. package/translations/ja.json +19 -7
  57. package/translations/ko.json +19 -7
  58. package/translations/ms.json +19 -7
  59. package/translations/zh.json +19 -7
@@ -5,6 +5,7 @@ import { css, html, LitElement, nothing } from 'lit';
5
5
  import { customElement } from 'lit/decorators.js';
6
6
  import { QueryController } from '@operato/graphql';
7
7
  import { i18next, localize } from '@operato/i18n';
8
+ import { navigate } from '@operato/shell';
8
9
  import { trainingWord } from '../training-words.js';
9
10
  import { failureOf } from '../words.js';
10
11
  import { openTrainingCertificateForm } from './training-certificate-form.js';
@@ -21,7 +22,7 @@ let ComplianceMyTrainings = class ComplianceMyTrainings extends localize(i18next
21
22
  myTrainings {
22
23
  kind year dueOn state
23
24
  completion { id status completedOn returnReason }
24
- sessions { id name method startsOn endsOn }
25
+ sessions { id name method startsOn endsOn course { id name } }
25
26
  }
26
27
  }
27
28
  `);
@@ -96,7 +97,10 @@ let ComplianceMyTrainings = class ComplianceMyTrainings extends localize(i18next
96
97
  </td>
97
98
  <td>
98
99
  ${row.sessions.length
99
- ? row.sessions.map((one) => html `<p>${one.name} · ${one.endsOn && one.endsOn !== one.startsOn ? `${one.startsOn} ~ ${one.endsOn}` : one.startsOn} · ${trainingWord('method', one.method)}</p>`)
100
+ ? row.sessions.map((one) => html `<p>
101
+ ${one.name} · ${one.endsOn && one.endsOn !== one.startsOn ? `${one.startsOn} ~ ${one.endsOn}` : one.startsOn} · ${trainingWord('method', one.method)}
102
+ ${one.course && row.state !== 'DONE' ? html `<md-text-button @click=${() => navigate('my-learning')}>${i18next.t('button.training-online-learn')}</md-text-button>` : nothing}
103
+ </p>`)
100
104
  : html `<p muted>${i18next.t('text.training-no-session-yet')}</p>`}
101
105
  </td>
102
106
  <td>
@@ -1 +1 @@
1
- {"version":3,"file":"my-trainings.js","sourceRoot":"","sources":["../../client/components/my-trainings.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/text-button.js'\n\nimport 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, localize } from '@operato/i18n'\n\nimport { trainingWord } from '../training-words.js'\nimport { failureOf } from '../words.js'\nimport { openTrainingCertificateForm } from './training-certificate-form.js'\n\n/**\n * 내 의무 교육 (ADR-0187 decisions 10, 17, 18) - this year's trainings the person must take: by when, whether done, the\n * sessions of it, and the certificate of one taken elsewhere. Only a certificate the manager confirmed is done.\n */\n@customElement('compliance-my-trainings')\nexport class ComplianceMyTrainings extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n color: var(--ui-ink);\n font-size: var(--ui-t-body, 13px);\n }\n table {\n width: 100%;\n border-collapse: collapse;\n }\n th,\n td {\n text-align: left;\n vertical-align: top;\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border-bottom: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n }\n th {\n color: var(--ui-muted);\n font-weight: normal;\n }\n [state='DONE'] {\n color: var(--ui-ok, var(--md-sys-color-primary));\n }\n [state='NOT_DONE'] {\n color: var(--ui-crit, var(--md-sys-color-error));\n }\n [muted] {\n color: var(--ui-muted);\n }\n p {\n margin: 0;\n }\n `\n\n /* The trainings the person owes, with the sessions they may take (ADR-0190). */\n private mine = new QueryController(\n this,\n gql`\n query {\n myTrainings {\n kind year dueOn state\n completion { id status completedOn returnReason }\n sessions { id name method startsOn endsOn }\n }\n }\n `\n )\n\n private get rows(): any[] {\n return this.mine.data?.myTrainings ?? []\n }\n\n private get message() {\n return this.mine.error ? failureOf(this.mine.error) : ''\n }\n\n render() {\n if (this.message) return html`<p muted>${this.message}</p>`\n if (!this.mine.data) return nothing\n if (!this.rows.length) return html`<p muted>${i18next.t('text.training-mine-empty')}</p>`\n return html`<table>\n <thead>\n <tr>\n <th>${i18next.t('field.training-kind')}</th>\n <th>${i18next.t('field.training-due-on')}</th>\n <th>${i18next.t('field.training-state')}</th>\n <th>${i18next.t('field.training-session')}</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n ${this.rows.map(\n row => html`<tr>\n <td>${trainingWord('kind', row.kind)}</td>\n <td>${row.dueOn}</td>\n <td>\n <p state=${row.state}>${trainingWord('state', row.state)}</p>\n ${row.completion?.status === 'CONFIRMED' ? html`<p muted>${row.completion.completedOn}</p>` : nothing}\n ${row.state === 'NOT_DONE' && row.completion?.status === 'RETURNED'\n ? html`<p muted>${i18next.t('text.training-returned', { reason: row.completion.returnReason ?? '' })}</p>`\n : nothing}\n </td>\n <td>\n ${row.sessions.length\n ? row.sessions.map(\n (one: any) =>\n html`<p>${one.name} · ${one.endsOn && one.endsOn !== one.startsOn ? `${one.startsOn} ~ ${one.endsOn}` : one.startsOn} · ${trainingWord('method', one.method)}</p>`\n )\n : html`<p muted>${i18next.t('text.training-no-session-yet')}</p>`}\n </td>\n <td>\n ${row.state === 'NOT_DONE'\n ? html`<md-text-button @click=${() => this.upload(row)}>${i18next.t('button.training-certificate-upload')}</md-text-button>`\n : nothing}\n </td>\n </tr>`\n )}\n </tbody>\n </table>`\n }\n\n private async upload(row: any) {\n if (await openTrainingCertificateForm({ kind: row.kind, year: row.year, sessions: row.sessions })) this.mine.refetch()\n }\n}\n"]}
1
+ {"version":3,"file":"my-trainings.js","sourceRoot":"","sources":["../../client/components/my-trainings.ts"],"names":[],"mappings":";AAAA,OAAO,qCAAqC,CAAA;AAE5C,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AAE5E;;;GAGG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAAjE;;QAoCL,gFAAgF;QACxE,SAAI,GAAG,IAAI,eAAe,CAChC,IAAI,EACJ,GAAG,CAAA;;;;;;;;KAQF,CACF,CAAA;IA6DH,CAAC;aA5GQ,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiClB,AAjCY,CAiCZ;IAgBD,IAAY,IAAI;QACd,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,CAAA;IAC1C,CAAC;IAED,IAAY,OAAO;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAC1D,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA,YAAY,IAAI,CAAC,OAAO,MAAM,CAAA;QAC3D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,OAAO,CAAA;QACnC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA,YAAY,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,MAAM,CAAA;QACzF,OAAO,IAAI,CAAA;;;gBAGC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;gBAChC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;gBAClC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC;gBACjC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;;;;;UAKzC,IAAI,CAAC,IAAI,CAAC,GAAG,CACb,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA;kBACH,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC;kBAC9B,GAAG,CAAC,KAAK;;yBAEF,GAAG,CAAC,KAAK,IAAI,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC;gBACtD,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAA,YAAY,GAAG,CAAC,UAAU,CAAC,WAAW,MAAM,CAAC,CAAC,CAAC,OAAO;gBACnG,GAAG,CAAC,KAAK,KAAK,UAAU,IAAI,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,UAAU;YACjE,CAAC,CAAC,IAAI,CAAA,YAAY,OAAO,CAAC,CAAC,CAAC,wBAAwB,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC,MAAM;YAC1G,CAAC,CAAC,OAAO;;;gBAGT,GAAG,CAAC,QAAQ,CAAC,MAAM;YACnB,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CACd,CAAC,GAAQ,EAAE,EAAE,CACX,IAAI,CAAA;0BACA,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,MAAM,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC;0BAClJ,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA,0BAA0B,GAAG,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO;2BACzK,CACR;YACH,CAAC,CAAC,IAAI,CAAA,YAAY,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC,MAAM;;;gBAGjE,GAAG,CAAC,KAAK,KAAK,UAAU;YACxB,CAAC,CAAC,IAAI,CAAA,0BAA0B,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,oCAAoC,CAAC,mBAAmB;YAC5H,CAAC,CAAC,OAAO;;gBAET,CACP;;aAEI,CAAA;IACX,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,GAAQ;QAC3B,IAAI,MAAM,2BAA2B,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAA;IACxH,CAAC;;AA5GU,qBAAqB;IADjC,aAAa,CAAC,yBAAyB,CAAC;GAC5B,qBAAqB,CA6GjC","sourcesContent":["import '@material/web/button/text-button.js'\n\nimport 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, localize } from '@operato/i18n'\nimport { navigate } from '@operato/shell'\n\nimport { trainingWord } from '../training-words.js'\nimport { failureOf } from '../words.js'\nimport { openTrainingCertificateForm } from './training-certificate-form.js'\n\n/**\n * 내 의무 교육 (ADR-0187 decisions 10, 17, 18) - this year's trainings the person must take: by when, whether done, the\n * sessions of it, and the certificate of one taken elsewhere. Only a certificate the manager confirmed is done.\n */\n@customElement('compliance-my-trainings')\nexport class ComplianceMyTrainings extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n color: var(--ui-ink);\n font-size: var(--ui-t-body, 13px);\n }\n table {\n width: 100%;\n border-collapse: collapse;\n }\n th,\n td {\n text-align: left;\n vertical-align: top;\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border-bottom: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n }\n th {\n color: var(--ui-muted);\n font-weight: normal;\n }\n [state='DONE'] {\n color: var(--ui-ok, var(--md-sys-color-primary));\n }\n [state='NOT_DONE'] {\n color: var(--ui-crit, var(--md-sys-color-error));\n }\n [muted] {\n color: var(--ui-muted);\n }\n p {\n margin: 0;\n }\n `\n\n /* The trainings the person owes, with the sessions they may take (ADR-0190). */\n private mine = new QueryController(\n this,\n gql`\n query {\n myTrainings {\n kind year dueOn state\n completion { id status completedOn returnReason }\n sessions { id name method startsOn endsOn course { id name } }\n }\n }\n `\n )\n\n private get rows(): any[] {\n return this.mine.data?.myTrainings ?? []\n }\n\n private get message() {\n return this.mine.error ? failureOf(this.mine.error) : ''\n }\n\n render() {\n if (this.message) return html`<p muted>${this.message}</p>`\n if (!this.mine.data) return nothing\n if (!this.rows.length) return html`<p muted>${i18next.t('text.training-mine-empty')}</p>`\n return html`<table>\n <thead>\n <tr>\n <th>${i18next.t('field.training-kind')}</th>\n <th>${i18next.t('field.training-due-on')}</th>\n <th>${i18next.t('field.training-state')}</th>\n <th>${i18next.t('field.training-session')}</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n ${this.rows.map(\n row => html`<tr>\n <td>${trainingWord('kind', row.kind)}</td>\n <td>${row.dueOn}</td>\n <td>\n <p state=${row.state}>${trainingWord('state', row.state)}</p>\n ${row.completion?.status === 'CONFIRMED' ? html`<p muted>${row.completion.completedOn}</p>` : nothing}\n ${row.state === 'NOT_DONE' && row.completion?.status === 'RETURNED'\n ? html`<p muted>${i18next.t('text.training-returned', { reason: row.completion.returnReason ?? '' })}</p>`\n : nothing}\n </td>\n <td>\n ${row.sessions.length\n ? row.sessions.map(\n (one: any) =>\n html`<p>\n ${one.name} · ${one.endsOn && one.endsOn !== one.startsOn ? `${one.startsOn} ~ ${one.endsOn}` : one.startsOn} · ${trainingWord('method', one.method)}\n ${one.course && row.state !== 'DONE' ? html`<md-text-button @click=${() => navigate('my-learning')}>${i18next.t('button.training-online-learn')}</md-text-button>` : nothing}\n </p>`\n )\n : html`<p muted>${i18next.t('text.training-no-session-yet')}</p>`}\n </td>\n <td>\n ${row.state === 'NOT_DONE'\n ? html`<md-text-button @click=${() => this.upload(row)}>${i18next.t('button.training-certificate-upload')}</md-text-button>`\n : nothing}\n </td>\n </tr>`\n )}\n </tbody>\n </table>`\n }\n\n private async upload(row: any) {\n if (await openTrainingCertificateForm({ kind: row.kind, year: row.year, sessions: row.sessions })) this.mine.refetch()\n }\n}\n"]}
@@ -31,8 +31,11 @@ export declare class TrainingSessionForm extends TrainingSessionForm_base {
31
31
  private progress;
32
32
  private working;
33
33
  private message;
34
+ private courseId;
35
+ private courses;
34
36
  connectedCallback(): void;
35
37
  render(): import("lit-html").TemplateResult<1>;
38
+ private renderCourse;
36
39
  private pick;
37
40
  private open;
38
41
  }
@@ -10,7 +10,7 @@ import '@things-factory/announcement/dist-client/components/audience-picker.js';
10
10
  import gql from 'graphql-tag';
11
11
  import { css, html, LitElement } from 'lit';
12
12
  import { customElement, property, state } from 'lit/decorators.js';
13
- import { client, uploadContext } from '@operato/graphql';
13
+ import { client, QueryController, uploadContext } from '@operato/graphql';
14
14
  import { i18next, localize } from '@operato/i18n';
15
15
  import { notify, openPopup } from '@operato/layout';
16
16
  import { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles';
@@ -46,6 +46,11 @@ let TrainingSessionForm = class TrainingSessionForm extends localize(i18next)(Li
46
46
  this.progress = 0;
47
47
  this.working = false;
48
48
  this.message = '';
49
+ this.courseId = '';
50
+ /* The published courses an online session may be taken on (ADR-0194 decision 15) - read once ONLINE is picked. */
51
+ this.courses = new QueryController(this, gql `query { courses(pagination: { page: 1, limit: 500 }) { items { id name publishedVersion { id number } } } }`, {
52
+ variables: () => (this.method === 'ONLINE' ? {} : undefined)
53
+ });
49
54
  }
50
55
  static { this.styles = [
51
56
  CommonPopupStyles,
@@ -110,6 +115,8 @@ let TrainingSessionForm = class TrainingSessionForm extends localize(i18next)(Li
110
115
  <ox-input-select-buttons .value=${this.method} .options=${trainingOptions('method', TRAINING_METHODS)} @change=${(e) => e.detail && (this.method = e.detail)}></ox-input-select-buttons>
111
116
  </div>
112
117
 
118
+ ${this.method === 'ONLINE' ? this.renderCourse() : ''}
119
+
113
120
  <label class="field">
114
121
  <span>${i18next.t('field.training-starts-on')}</span>
115
122
  <input type="date" .value=${this.startsOn} @input=${(e) => (this.startsOn = e.target.value)} />
@@ -155,6 +162,17 @@ let TrainingSessionForm = class TrainingSessionForm extends localize(i18next)(Li
155
162
  </ox-popup-actions>
156
163
  `;
157
164
  }
165
+ renderCourse() {
166
+ const courses = (this.courses.data?.courses?.items ?? []).filter((one) => one.publishedVersion);
167
+ return html `<label class="field">
168
+ <span>${i18next.t('field.training-course')}</span>
169
+ <ox-select .value=${this.courseId} @change=${(e) => (this.courseId = String(e.detail ?? ''))}>
170
+ <span slot="label">${courses.find((one) => one.id === this.courseId)?.name ?? '—'}</span>
171
+ <ox-popup-list align-left nowrap with-search>${courses.map((one) => html `<div option value=${one.id}>${one.name}</div>`)}</ox-popup-list>
172
+ </ox-select>
173
+ <span>${courses.length ? i18next.t('text.training-online-course-hint') : i18next.t('text.training-online-no-course')}</span>
174
+ </label>`;
175
+ }
158
176
  pick(e) {
159
177
  const picked = [...(e.detail ?? [])];
160
178
  /* The picker's own reset says `change` again, with nothing - that one is let go. */
@@ -184,6 +202,7 @@ let TrainingSessionForm = class TrainingSessionForm extends localize(i18next)(Li
184
202
  instructor: this.instructor,
185
203
  organisation: this.organisation,
186
204
  audiences: this.audiences.map(({ scope, targetId, targetName }) => ({ scope, targetId, targetName })),
205
+ courseId: this.method === 'ONLINE' ? this.courseId || null : null,
187
206
  notes: this.notes
188
207
  },
189
208
  attach: this.files
@@ -263,6 +282,10 @@ __decorate([
263
282
  state(),
264
283
  __metadata("design:type", Object)
265
284
  ], TrainingSessionForm.prototype, "message", void 0);
285
+ __decorate([
286
+ state(),
287
+ __metadata("design:type", Object)
288
+ ], TrainingSessionForm.prototype, "courseId", void 0);
266
289
  TrainingSessionForm = __decorate([
267
290
  customElement('training-session-form')
268
291
  ], TrainingSessionForm);
@@ -1 +1 @@
1
- {"version":3,"file":"training-session-form.js","sourceRoot":"","sources":["../../client/components/training-session-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/input/ox-input-file.js'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/input/ox-select.js'\nimport '@operato/popup/ox-popup-actions.js'\nimport '@operato/popup/ox-popup-list.js'\nimport '@things-factory/announcement/dist-client/components/audience-picker.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client, uploadContext } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles'\n\nimport { TRAINING_METHODS, trainingOptions } from '../training-words.js'\nimport { failureOf } from '../words.js'\n\ntype Audience = { scope: string; targetId: string; targetName?: string }\n\n/** Opens the form with the kinds on; resolves with the opened session, or null when the person closed it. */\nexport function openTrainingSessionForm(kinds: string[], year: number): Promise<any | null> {\n return new Promise(resolve => {\n let done: any = null\n const handle: any = openPopup(\n html`<training-session-form .kinds=${kinds} .year=${year} @close=${() => handle.close()} @opened=${(e: CustomEvent) => ((done = e.detail), handle.close())}></training-session-form>`,\n { backdrop: true, size: 'medium', title: i18next.t('title.training-session-open') }\n )\n handle.onclosed = () => resolve(done)\n })\n}\n\n/**\n * 회차 열기 (ADR-0187 decision 16) - one training given: its kind and year, how, when, by whom, its material and who it\n * is for. Opening it tells them.\n */\n@customElement('training-session-form')\nexport class TrainingSessionForm extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n FormFieldStyles,\n PopupFieldStyles,\n css`\n [invalid] {\n color: var(--ui-crit, var(--md-sys-color-error));\n font-size: var(--ui-t-small, 11.5px);\n }\n [invalid]:empty {\n display: none;\n }\n [guide] p {\n margin: 0;\n color: var(--ui-muted);\n line-height: var(--popup-line-height);\n }\n ox-input-select-buttons {\n align-self: flex-start;\n }\n ox-select {\n width: 100%;\n }\n ul {\n margin: 0;\n padding-left: var(--spacing-large, 12px);\n }\n `\n ]\n\n @property({ type: Array }) kinds: string[] = []\n @property({ type: Number }) year = new Date().getFullYear()\n\n @state() private kind = ''\n @state() private name = ''\n @state() private method = 'COLLECTIVE'\n @state() private startsOn = ''\n @state() private endsOn = ''\n @state() private instructor = ''\n @state() private organisation = ''\n @state() private audiences: Audience[] = []\n @state() private notes = ''\n @state() private files: File[] = []\n @state() private progress = 0\n @state() private working = false\n @state() private message = ''\n\n connectedCallback() {\n super.connectedCallback()\n this.kind = this.kinds[0] ?? ''\n }\n\n render() {\n const kinds = trainingOptions('kind', this.kinds)\n return html`\n <div class=\"body\">\n <div guide><p>${i18next.t('text.training-session-guide')}</p></div>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-kind')}</span>\n <ox-select .value=${this.kind} @change=${(e: CustomEvent) => (this.kind = String(e.detail ?? ''))}>\n <span slot=\"label\">${kinds.find(one => one.value === this.kind)?.display ?? '—'}</span>\n <ox-popup-list align-left nowrap with-search>${kinds.map(one => html`<div option value=${one.value}>${one.display}</div>`)}</ox-popup-list>\n </ox-select>\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-year')}</span>\n <input type=\"number\" min=\"2000\" max=\"2999\" .value=${String(this.year)} @input=${(e: any) => (this.year = Number(e.target.value))} />\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-session-name')}</span>\n <input .value=${this.name} @input=${(e: any) => (this.name = e.target.value)} />\n </label>\n\n <div class=\"field\">\n <span>${i18next.t('field.training-method')}</span>\n <ox-input-select-buttons .value=${this.method} .options=${trainingOptions('method', TRAINING_METHODS)} @change=${(e: CustomEvent) => e.detail && (this.method = e.detail)}></ox-input-select-buttons>\n </div>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-starts-on')}</span>\n <input type=\"date\" .value=${this.startsOn} @input=${(e: any) => (this.startsOn = e.target.value)} />\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-ends-on')}</span>\n <input type=\"date\" .value=${this.endsOn} @input=${(e: any) => (this.endsOn = e.target.value)} />\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-instructor')}</span>\n <input .value=${this.instructor} @input=${(e: any) => (this.instructor = e.target.value)} />\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-organisation')}</span>\n <input .value=${this.organisation} @input=${(e: any) => (this.organisation = e.target.value)} />\n </label>\n\n <div class=\"field\">\n <span>${i18next.t('field.training-audiences')}</span>\n <announcement-audience-picker .value=${this.audiences} @change=${(e: CustomEvent) => Array.isArray(e.detail) && (this.audiences = e.detail)}></announcement-audience-picker>\n <span>${i18next.t('text.training-session-audiences-hint')}</span>\n </div>\n\n <div class=\"field\">\n <span>${i18next.t('field.training-material')}</span>\n ${this.files.length ? html`<ul>${this.files.map(one => html`<li>${one.name}</li>`)}</ul>` : ''}\n <ox-input-file quiet hide-filelist multiple icon=\"attach_file\" .progress=${this.progress} @change=${(e: CustomEvent) => this.pick(e)}></ox-input-file>\n </div>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-notes')}</span>\n <input .value=${this.notes} @input=${(e: any) => (this.notes = e.target.value)} />\n <span invalid>${this.message}</span>\n </label>\n </div>\n\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${i18next.t('button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.working} @click=${() => this.open()}>${i18next.t('button.training-session-open')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private pick(e: CustomEvent) {\n const picked = [...((e.detail as File[]) ?? [])]\n /* The picker's own reset says `change` again, with nothing - that one is let go. */\n if (!picked.length) return\n ;(e.target as any).reset?.()\n this.files = [...this.files, ...picked]\n }\n\n private async open() {\n this.message = ''\n this.working = true\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($session: NewTrainingSession!, $attach: [Upload!]) {\n openTrainingSession(session: $session, attach: $attach) { id }\n }\n `,\n variables: {\n session: {\n kind: this.kind,\n year: this.year,\n name: this.name,\n method: this.method,\n startsOn: this.startsOn,\n endsOn: this.endsOn || null,\n instructor: this.instructor,\n organisation: this.organisation,\n audiences: this.audiences.map(({ scope, targetId, targetName }) => ({ scope, targetId, targetName })),\n notes: this.notes\n },\n attach: this.files\n },\n ...(this.files.length ? { context: uploadContext((fraction: number) => (this.progress = fraction)) } : {})\n })\n if ((response as any).errors?.length) throw response\n notify({ message: i18next.t('text.training-session-opened') })\n this.dispatchEvent(new CustomEvent('opened', { detail: response.data.openTrainingSession }))\n } catch (error) {\n this.message = failureOf(error)\n } finally {\n this.working = false\n }\n }\n}\n"]}
1
+ {"version":3,"file":"training-session-form.js","sourceRoot":"","sources":["../../client/components/training-session-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/input/ox-input-file.js'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/input/ox-select.js'\nimport '@operato/popup/ox-popup-actions.js'\nimport '@operato/popup/ox-popup-list.js'\nimport '@things-factory/announcement/dist-client/components/audience-picker.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client, QueryController, uploadContext } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles'\n\nimport { TRAINING_METHODS, trainingOptions } from '../training-words.js'\nimport { failureOf } from '../words.js'\n\ntype Audience = { scope: string; targetId: string; targetName?: string }\n\n/** Opens the form with the kinds on; resolves with the opened session, or null when the person closed it. */\nexport function openTrainingSessionForm(kinds: string[], year: number): Promise<any | null> {\n return new Promise(resolve => {\n let done: any = null\n const handle: any = openPopup(\n html`<training-session-form .kinds=${kinds} .year=${year} @close=${() => handle.close()} @opened=${(e: CustomEvent) => ((done = e.detail), handle.close())}></training-session-form>`,\n { backdrop: true, size: 'medium', title: i18next.t('title.training-session-open') }\n )\n handle.onclosed = () => resolve(done)\n })\n}\n\n/**\n * 회차 열기 (ADR-0187 decision 16) - one training given: its kind and year, how, when, by whom, its material and who it\n * is for. Opening it tells them.\n */\n@customElement('training-session-form')\nexport class TrainingSessionForm extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n FormFieldStyles,\n PopupFieldStyles,\n css`\n [invalid] {\n color: var(--ui-crit, var(--md-sys-color-error));\n font-size: var(--ui-t-small, 11.5px);\n }\n [invalid]:empty {\n display: none;\n }\n [guide] p {\n margin: 0;\n color: var(--ui-muted);\n line-height: var(--popup-line-height);\n }\n ox-input-select-buttons {\n align-self: flex-start;\n }\n ox-select {\n width: 100%;\n }\n ul {\n margin: 0;\n padding-left: var(--spacing-large, 12px);\n }\n `\n ]\n\n @property({ type: Array }) kinds: string[] = []\n @property({ type: Number }) year = new Date().getFullYear()\n\n @state() private kind = ''\n @state() private name = ''\n @state() private method = 'COLLECTIVE'\n @state() private startsOn = ''\n @state() private endsOn = ''\n @state() private instructor = ''\n @state() private organisation = ''\n @state() private audiences: Audience[] = []\n @state() private notes = ''\n @state() private files: File[] = []\n @state() private progress = 0\n @state() private working = false\n @state() private message = ''\n @state() private courseId = ''\n\n /* The published courses an online session may be taken on (ADR-0194 decision 15) - read once ONLINE is picked. */\n private courses = new QueryController(this, gql`query { courses(pagination: { page: 1, limit: 500 }) { items { id name publishedVersion { id number } } } }`, {\n variables: () => (this.method === 'ONLINE' ? {} : undefined)\n })\n\n connectedCallback() {\n super.connectedCallback()\n this.kind = this.kinds[0] ?? ''\n }\n\n render() {\n const kinds = trainingOptions('kind', this.kinds)\n return html`\n <div class=\"body\">\n <div guide><p>${i18next.t('text.training-session-guide')}</p></div>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-kind')}</span>\n <ox-select .value=${this.kind} @change=${(e: CustomEvent) => (this.kind = String(e.detail ?? ''))}>\n <span slot=\"label\">${kinds.find(one => one.value === this.kind)?.display ?? '—'}</span>\n <ox-popup-list align-left nowrap with-search>${kinds.map(one => html`<div option value=${one.value}>${one.display}</div>`)}</ox-popup-list>\n </ox-select>\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-year')}</span>\n <input type=\"number\" min=\"2000\" max=\"2999\" .value=${String(this.year)} @input=${(e: any) => (this.year = Number(e.target.value))} />\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-session-name')}</span>\n <input .value=${this.name} @input=${(e: any) => (this.name = e.target.value)} />\n </label>\n\n <div class=\"field\">\n <span>${i18next.t('field.training-method')}</span>\n <ox-input-select-buttons .value=${this.method} .options=${trainingOptions('method', TRAINING_METHODS)} @change=${(e: CustomEvent) => e.detail && (this.method = e.detail)}></ox-input-select-buttons>\n </div>\n\n ${this.method === 'ONLINE' ? this.renderCourse() : ''}\n\n <label class=\"field\">\n <span>${i18next.t('field.training-starts-on')}</span>\n <input type=\"date\" .value=${this.startsOn} @input=${(e: any) => (this.startsOn = e.target.value)} />\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-ends-on')}</span>\n <input type=\"date\" .value=${this.endsOn} @input=${(e: any) => (this.endsOn = e.target.value)} />\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-instructor')}</span>\n <input .value=${this.instructor} @input=${(e: any) => (this.instructor = e.target.value)} />\n </label>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-organisation')}</span>\n <input .value=${this.organisation} @input=${(e: any) => (this.organisation = e.target.value)} />\n </label>\n\n <div class=\"field\">\n <span>${i18next.t('field.training-audiences')}</span>\n <announcement-audience-picker .value=${this.audiences} @change=${(e: CustomEvent) => Array.isArray(e.detail) && (this.audiences = e.detail)}></announcement-audience-picker>\n <span>${i18next.t('text.training-session-audiences-hint')}</span>\n </div>\n\n <div class=\"field\">\n <span>${i18next.t('field.training-material')}</span>\n ${this.files.length ? html`<ul>${this.files.map(one => html`<li>${one.name}</li>`)}</ul>` : ''}\n <ox-input-file quiet hide-filelist multiple icon=\"attach_file\" .progress=${this.progress} @change=${(e: CustomEvent) => this.pick(e)}></ox-input-file>\n </div>\n\n <label class=\"field\">\n <span>${i18next.t('field.training-notes')}</span>\n <input .value=${this.notes} @input=${(e: any) => (this.notes = e.target.value)} />\n <span invalid>${this.message}</span>\n </label>\n </div>\n\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${i18next.t('button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.working} @click=${() => this.open()}>${i18next.t('button.training-session-open')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private renderCourse() {\n const courses = ((this.courses.data as any)?.courses?.items ?? []).filter((one: any) => one.publishedVersion)\n return html`<label class=\"field\">\n <span>${i18next.t('field.training-course')}</span>\n <ox-select .value=${this.courseId} @change=${(e: CustomEvent) => (this.courseId = String(e.detail ?? ''))}>\n <span slot=\"label\">${courses.find((one: any) => one.id === this.courseId)?.name ?? '—'}</span>\n <ox-popup-list align-left nowrap with-search>${courses.map((one: any) => html`<div option value=${one.id}>${one.name}</div>`)}</ox-popup-list>\n </ox-select>\n <span>${courses.length ? i18next.t('text.training-online-course-hint') : i18next.t('text.training-online-no-course')}</span>\n </label>`\n }\n\n private pick(e: CustomEvent) {\n const picked = [...((e.detail as File[]) ?? [])]\n /* The picker's own reset says `change` again, with nothing - that one is let go. */\n if (!picked.length) return\n ;(e.target as any).reset?.()\n this.files = [...this.files, ...picked]\n }\n\n private async open() {\n this.message = ''\n this.working = true\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($session: NewTrainingSession!, $attach: [Upload!]) {\n openTrainingSession(session: $session, attach: $attach) { id }\n }\n `,\n variables: {\n session: {\n kind: this.kind,\n year: this.year,\n name: this.name,\n method: this.method,\n startsOn: this.startsOn,\n endsOn: this.endsOn || null,\n instructor: this.instructor,\n organisation: this.organisation,\n audiences: this.audiences.map(({ scope, targetId, targetName }) => ({ scope, targetId, targetName })),\n courseId: this.method === 'ONLINE' ? this.courseId || null : null,\n notes: this.notes\n },\n attach: this.files\n },\n ...(this.files.length ? { context: uploadContext((fraction: number) => (this.progress = fraction)) } : {})\n })\n if ((response as any).errors?.length) throw response\n notify({ message: i18next.t('text.training-session-opened') })\n this.dispatchEvent(new CustomEvent('opened', { detail: response.data.openTrainingSession }))\n } catch (error) {\n this.message = failureOf(error)\n } finally {\n this.working = false\n }\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import '@material/web/button/filled-button.js';
2
2
  import '@material/web/button/text-button.js';
3
+ import '@material/web/icon/icon.js';
3
4
  import '@operato/data-grist/ox-grist.js';
4
5
  import '@operato/popup/ox-popup-actions.js';
5
6
  import { LitElement } from 'lit';
@@ -7,8 +8,13 @@ import { DataGrist } from '@operato/data-grist';
7
8
  export interface ChildGridSpec {
8
9
  /** The grid's columns, past the gutters. */
9
10
  columns: any[];
10
- /** Whether rows may be added. */
11
- appendable: boolean;
11
+ /**
12
+ * Whether rows may be added - by 「항목 추가」 beside the grid or by pasting past the last row. There is no empty row
13
+ * waiting at the bottom; a grid that only corrects rows (the changes to file) shows no add.
14
+ */
15
+ creates: boolean;
16
+ /** The values a new row starts with; the parent itself travels in `save`, not on the row. */
17
+ newRecord?: () => Record<string, any>;
12
18
  /** The rows. */
13
19
  fetch: () => Promise<any[]>;
14
20
  /** Saves the grid's dirty rows; true when saved. */
@@ -18,6 +24,10 @@ declare const LegalChildGrid_base: (new (...args: any[]) => LitElement) & typeof
18
24
  /**
19
25
  * The rows that hang on one legal record - a centre's researchers and its changes to file, an invention's rewards, a
20
26
  * dispute's hearings: a small grid in a popup, saved with the one main action. Nothing is deleted from it.
27
+ *
28
+ * Save scope: the popup's confirm (「저장」 in ox-popup-actions) writes this grid's new and changed rows and nothing
29
+ * else - the list page behind it keeps its own unsaved edits and its own save. A row added here and not saved is
30
+ * dropped when the popup closes.
21
31
  */
22
32
  export declare class LegalChildGrid extends LegalChildGrid_base {
23
33
  static styles: import("lit").CSSResult[];
@@ -1,9 +1,10 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import '@material/web/button/filled-button.js';
3
3
  import '@material/web/button/text-button.js';
4
+ import '@material/web/icon/icon.js';
4
5
  import '@operato/data-grist/ox-grist.js';
5
6
  import '@operato/popup/ox-popup-actions.js';
6
- import { css, html, LitElement } from 'lit';
7
+ import { css, html, LitElement, nothing } from 'lit';
7
8
  import { customElement, property, query } from 'lit/decorators.js';
8
9
  import { DataGrist } from '@operato/data-grist';
9
10
  import { i18next, localize } from '@operato/i18n';
@@ -12,6 +13,10 @@ import { CommonGristStyles, CommonPopupStyles } from '@operato/styles';
12
13
  /**
13
14
  * The rows that hang on one legal record - a centre's researchers and its changes to file, an invention's rewards, a
14
15
  * dispute's hearings: a small grid in a popup, saved with the one main action. Nothing is deleted from it.
16
+ *
17
+ * Save scope: the popup's confirm (「저장」 in ox-popup-actions) writes this grid's new and changed rows and nothing
18
+ * else - the list page behind it keeps its own unsaved edits and its own save. A row added here and not saved is
19
+ * dropped when the popup closes.
15
20
  */
16
21
  let LegalChildGrid = class LegalChildGrid extends localize(i18next)(LitElement) {
17
22
  static { this.styles = [
@@ -23,6 +28,11 @@ let LegalChildGrid = class LegalChildGrid extends localize(i18next)(LitElement)
23
28
  flex-direction: column;
24
29
  min-height: 360px;
25
30
  }
31
+ .grid-tools {
32
+ display: flex;
33
+ justify-content: flex-end;
34
+ padding-bottom: var(--spacing-small, 4px);
35
+ }
26
36
  ox-grist {
27
37
  flex: 1;
28
38
  }
@@ -37,11 +47,21 @@ let LegalChildGrid = class LegalChildGrid extends localize(i18next)(LitElement)
37
47
  }
38
48
  render() {
39
49
  const config = {
40
- rows: { appendable: this.spec.appendable, selectable: { multiple: false } },
50
+ rows: {
51
+ appendable: false,
52
+ pasteAppendable: this.spec.creates,
53
+ ...(this.spec.newRecord ? { newRecord: this.spec.newRecord } : {}),
54
+ selectable: { multiple: false }
55
+ },
41
56
  pagination: { infinite: true },
42
57
  columns: [{ type: 'gutter', gutterName: 'dirty' }, { type: 'gutter', gutterName: 'sequence' }, ...this.spec.columns]
43
58
  };
44
59
  return html `
60
+ ${this.spec.creates
61
+ ? html `<div class="grid-tools">
62
+ <md-text-button @click=${() => this.grist.addNewRecord()}><md-icon slot="icon">add</md-icon>${i18next.t('button.legal-child-add')}</md-text-button>
63
+ </div>`
64
+ : nothing}
45
65
  <ox-grist .mode=${'GRID'} .config=${config} .fetchHandler=${async () => {
46
66
  const records = await this.spec.fetch();
47
67
  return { total: records.length, records };
@@ -1 +1 @@
1
- {"version":3,"file":"legal-child-grid.js","sourceRoot":"","sources":["../../client/legal-record/legal-child-grid.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/data-grist/ox-grist.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { DataGrist } from '@operato/data-grist'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\nimport { CommonGristStyles, CommonPopupStyles } from '@operato/styles'\n\nexport interface ChildGridSpec {\n /** The grid's columns, past the gutters. */\n columns: any[]\n /** Whether rows may be added. */\n appendable: boolean\n /** The rows. */\n fetch: () => Promise<any[]>\n /** Saves the grid's dirty rows; true when saved. */\n save: (grist: DataGrist) => Promise<boolean>\n}\n\n/**\n * The rows that hang on one legal record - a centre's researchers and its changes to file, an invention's rewards, a\n * dispute's hearings: a small grid in a popup, saved with the one main action. Nothing is deleted from it.\n */\n@customElement('legal-child-grid')\nexport class LegalChildGrid extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n CommonGristStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 360px;\n }\n ox-grist {\n flex: 1;\n }\n `\n ]\n\n @property({ attribute: false }) spec!: ChildGridSpec\n @query('ox-grist') private grist!: DataGrist\n\n /** Opens the grid; `changed` runs when the popup closes after a save. */\n static open(title: string, spec: ChildGridSpec, changed?: () => void) {\n let saved = false\n const popup: any = openPopup(html`<legal-child-grid .spec=${spec} @saved=${() => (saved = true)} @close=${() => popup.close()}></legal-child-grid>`, { backdrop: true, size: 'large', title })\n popup.onclosed = () => saved && changed?.()\n return popup\n }\n\n render() {\n const config = {\n rows: { appendable: this.spec.appendable, selectable: { multiple: false } },\n pagination: { infinite: true },\n columns: [{ type: 'gutter', gutterName: 'dirty' }, { type: 'gutter', gutterName: 'sequence' }, ...this.spec.columns]\n }\n return html`\n <ox-grist .mode=${'GRID'} .config=${config} .fetchHandler=${async () => {\n const records = await this.spec.fetch()\n return { total: records.length, records }\n }}></ox-grist>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${i18next.t('button.close')}</md-text-button>\n <md-filled-button slot=\"confirm\" @click=${() => this.save()}>${i18next.t('button.save')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private async save() {\n if (!(await this.spec.save(this.grist))) return\n this.dispatchEvent(new CustomEvent('saved'))\n this.grist.fetch()\n }\n}\n"]}
1
+ {"version":3,"file":"legal-child-grid.js","sourceRoot":"","sources":["../../client/legal-record/legal-child-grid.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/data-grist/ox-grist.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { DataGrist } from '@operato/data-grist'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\nimport { CommonGristStyles, CommonPopupStyles } from '@operato/styles'\n\nexport interface ChildGridSpec {\n /** The grid's columns, past the gutters. */\n columns: any[]\n /**\n * Whether rows may be added - by 「항목 추가」 beside the grid or by pasting past the last row. There is no empty row\n * waiting at the bottom; a grid that only corrects rows (the changes to file) shows no add.\n */\n creates: boolean\n /** The values a new row starts with; the parent itself travels in `save`, not on the row. */\n newRecord?: () => Record<string, any>\n /** The rows. */\n fetch: () => Promise<any[]>\n /** Saves the grid's dirty rows; true when saved. */\n save: (grist: DataGrist) => Promise<boolean>\n}\n\n/**\n * The rows that hang on one legal record - a centre's researchers and its changes to file, an invention's rewards, a\n * dispute's hearings: a small grid in a popup, saved with the one main action. Nothing is deleted from it.\n *\n * Save scope: the popup's confirm (「저장」 in ox-popup-actions) writes this grid's new and changed rows and nothing\n * else - the list page behind it keeps its own unsaved edits and its own save. A row added here and not saved is\n * dropped when the popup closes.\n */\n@customElement('legal-child-grid')\nexport class LegalChildGrid extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n CommonGristStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 360px;\n }\n .grid-tools {\n display: flex;\n justify-content: flex-end;\n padding-bottom: var(--spacing-small, 4px);\n }\n ox-grist {\n flex: 1;\n }\n `\n ]\n\n @property({ attribute: false }) spec!: ChildGridSpec\n @query('ox-grist') private grist!: DataGrist\n\n /** Opens the grid; `changed` runs when the popup closes after a save. */\n static open(title: string, spec: ChildGridSpec, changed?: () => void) {\n let saved = false\n const popup: any = openPopup(html`<legal-child-grid .spec=${spec} @saved=${() => (saved = true)} @close=${() => popup.close()}></legal-child-grid>`, { backdrop: true, size: 'large', title })\n popup.onclosed = () => saved && changed?.()\n return popup\n }\n\n render() {\n const config = {\n rows: {\n appendable: false,\n pasteAppendable: this.spec.creates,\n ...(this.spec.newRecord ? { newRecord: this.spec.newRecord } : {}),\n selectable: { multiple: false }\n },\n pagination: { infinite: true },\n columns: [{ type: 'gutter', gutterName: 'dirty' }, { type: 'gutter', gutterName: 'sequence' }, ...this.spec.columns]\n }\n return html`\n ${this.spec.creates\n ? html`<div class=\"grid-tools\">\n <md-text-button @click=${() => this.grist.addNewRecord()}><md-icon slot=\"icon\">add</md-icon>${i18next.t('button.legal-child-add')}</md-text-button>\n </div>`\n : nothing}\n <ox-grist .mode=${'GRID'} .config=${config} .fetchHandler=${async () => {\n const records = await this.spec.fetch()\n return { total: records.length, records }\n }}></ox-grist>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.dispatchEvent(new CustomEvent('close'))}>${i18next.t('button.close')}</md-text-button>\n <md-filled-button slot=\"confirm\" @click=${() => this.save()}>${i18next.t('button.save')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private async save() {\n if (!(await this.spec.save(this.grist))) return\n this.dispatchEvent(new CustomEvent('saved'))\n this.grist.fetch()\n }\n}\n"]}
@@ -3,7 +3,7 @@ import { DataGrist } from '@operato/data-grist';
3
3
  export declare function patchesOf(grist: DataGrist, fields: string[], shape?: (patch: any) => any): any[];
4
4
  /** An object column's id as the patch carries it - `inCharge` → `inChargeId`. */
5
5
  export declare function idsOf(patch: any, objects: string[]): any;
6
- /** Saves through `mutation(<extra>, patches)`; true when saved. */
6
+ /** Saves through `mutation(<extra>, patches)`; true when saved. With nothing changed it says so and saves nothing. */
7
7
  export declare function saveRows(mutation: string, type: string, patches: any[], extra?: Record<string, string>): Promise<boolean>;
8
8
  /** An employee picked in a grid cell - the framework's resource-object editor over `employees`. */
9
9
  export declare const employeeColumn: (name: string, header: string, width?: number) => {
@@ -24,10 +24,12 @@ export function idsOf(patch, objects) {
24
24
  (patch[`${name}Id`] = patch[name]?.id ?? null), delete patch[name];
25
25
  return patch;
26
26
  }
27
- /** Saves through `mutation(<extra>, patches)`; true when saved. */
27
+ /** Saves through `mutation(<extra>, patches)`; true when saved. With nothing changed it says so and saves nothing. */
28
28
  export async function saveRows(mutation, type, patches, extra = {}) {
29
- if (!patches.length)
29
+ if (!patches.length) {
30
+ notify({ level: 'info', message: i18next.t('text.compliance-nothing-to-save') });
30
31
  return false;
32
+ }
31
33
  const args = Object.keys(extra).map(name => `$${name}: String!`);
32
34
  const passes = Object.keys(extra).map(name => `${name}: $${name}`);
33
35
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"legal-grid.js","sourceRoot":"","sources":["../../client/legal-record/legal-grid.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\n\nimport { DataGrist, getEditor } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { notify } from '@operato/layout'\n\nimport { failureOf } from '../words.js'\n\n/*\n * What the grids of the ledger, the inventions and the disputes share (ADR-0187 decisions 23-25): rows are added and\n * corrected, never deleted, so a save sends the new rows whole and the changed fields of the others.\n */\n\n/** The grid's new and changed rows as patches - all fields of a new row, the changed ones otherwise. */\nexport function patchesOf(grist: DataGrist, fields: string[], shape: (patch: any) => any = patch => patch) {\n return grist.dirtyRecords\n .filter((record: any) => record.__dirty__ === '+' || record.__dirty__ === 'M')\n .map((record: any) => {\n const changed = record.__dirty__ === '+' ? fields.filter(field => record[field] !== undefined) : Object.keys(record.__dirtyfields__ ?? {}).filter(field => fields.includes(field))\n return shape({ ...(record.id ? { id: record.id } : {}), cuFlag: record.__dirty__, ...Object.fromEntries(changed.map(field => [field, record[field] === '' ? null : record[field]])) })\n })\n}\n\n/** An object column's id as the patch carries it - `inCharge` → `inChargeId`. */\nexport function idsOf(patch: any, objects: string[]) {\n for (const name of objects) if (name in patch) (patch[`${name}Id`] = patch[name]?.id ?? null), delete patch[name]\n return patch\n}\n\n/** Saves through `mutation(<extra>, patches)`; true when saved. */\nexport async function saveRows(mutation: string, type: string, patches: any[], extra: Record<string, string> = {}): Promise<boolean> {\n if (!patches.length) return false\n const args = Object.keys(extra).map(name => `$${name}: String!`)\n const passes = Object.keys(extra).map(name => `${name}: $${name}`)\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation (${[...args, `$patches: [${type}!]!`].join(', ')}) {\n ${mutation}(${[...passes, 'patches: $patches'].join(', ')}) { id }\n }\n `,\n variables: { ...extra, patches }\n })\n if ((response as any).errors?.length) throw response\n notify({ message: i18next.t('text.legal-record-saved') })\n return true\n } catch (error) {\n notify({ level: 'error', message: failureOf(error) })\n return false\n }\n}\n\n/** An employee picked in a grid cell - the framework's resource-object editor over `employees`. */\nexport const employeeColumn = (name: string, header: string, width = 100) => ({\n type: 'object',\n name,\n header,\n width,\n record: {\n editable: true,\n editor: getEditor('resource-object'),\n options: { queryName: 'employees', select: [{ name: 'id', hidden: true }, { name: 'name', width: 160 }, { name: 'controlNo', header: i18next.t('field.control-no'), width: 100 }] }\n }\n})\n\n/** A day cell. */\nexport const dayColumn = (name: string, header: string, editable = true, width = 100) => ({ type: 'date', name, header, width, sortable: true, record: { editable, align: 'center' } })\n\n/** A text cell. */\nexport const textColumn = (name: string, header: string, width = 140, editable = true) => ({ type: 'string', name, header, width, record: { editable } })\n"]}
1
+ {"version":3,"file":"legal-grid.js","sourceRoot":"","sources":["../../client/legal-record/legal-grid.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\n\nimport { DataGrist, getEditor } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { notify } from '@operato/layout'\n\nimport { failureOf } from '../words.js'\n\n/*\n * What the grids of the ledger, the inventions and the disputes share (ADR-0187 decisions 23-25): rows are added and\n * corrected, never deleted, so a save sends the new rows whole and the changed fields of the others.\n */\n\n/** The grid's new and changed rows as patches - all fields of a new row, the changed ones otherwise. */\nexport function patchesOf(grist: DataGrist, fields: string[], shape: (patch: any) => any = patch => patch) {\n return grist.dirtyRecords\n .filter((record: any) => record.__dirty__ === '+' || record.__dirty__ === 'M')\n .map((record: any) => {\n const changed = record.__dirty__ === '+' ? fields.filter(field => record[field] !== undefined) : Object.keys(record.__dirtyfields__ ?? {}).filter(field => fields.includes(field))\n return shape({ ...(record.id ? { id: record.id } : {}), cuFlag: record.__dirty__, ...Object.fromEntries(changed.map(field => [field, record[field] === '' ? null : record[field]])) })\n })\n}\n\n/** An object column's id as the patch carries it - `inCharge` → `inChargeId`. */\nexport function idsOf(patch: any, objects: string[]) {\n for (const name of objects) if (name in patch) (patch[`${name}Id`] = patch[name]?.id ?? null), delete patch[name]\n return patch\n}\n\n/** Saves through `mutation(<extra>, patches)`; true when saved. With nothing changed it says so and saves nothing. */\nexport async function saveRows(mutation: string, type: string, patches: any[], extra: Record<string, string> = {}): Promise<boolean> {\n if (!patches.length) {\n notify({ level: 'info', message: i18next.t('text.compliance-nothing-to-save') })\n return false\n }\n const args = Object.keys(extra).map(name => `$${name}: String!`)\n const passes = Object.keys(extra).map(name => `${name}: $${name}`)\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation (${[...args, `$patches: [${type}!]!`].join(', ')}) {\n ${mutation}(${[...passes, 'patches: $patches'].join(', ')}) { id }\n }\n `,\n variables: { ...extra, patches }\n })\n if ((response as any).errors?.length) throw response\n notify({ message: i18next.t('text.legal-record-saved') })\n return true\n } catch (error) {\n notify({ level: 'error', message: failureOf(error) })\n return false\n }\n}\n\n/** An employee picked in a grid cell - the framework's resource-object editor over `employees`. */\nexport const employeeColumn = (name: string, header: string, width = 100) => ({\n type: 'object',\n name,\n header,\n width,\n record: {\n editable: true,\n editor: getEditor('resource-object'),\n options: { queryName: 'employees', select: [{ name: 'id', hidden: true }, { name: 'name', width: 160 }, { name: 'controlNo', header: i18next.t('field.control-no'), width: 100 }] }\n }\n})\n\n/** A day cell. */\nexport const dayColumn = (name: string, header: string, editable = true, width = 100) => ({ type: 'date', name, header, width, sortable: true, record: { editable, align: 'center' } })\n\n/** A text cell. */\nexport const textColumn = (name: string, header: string, width = 140, editable = true) => ({ type: 'string', name, header, width, record: { editable } })\n"]}
@@ -33,7 +33,7 @@ let ComplianceCaseList = class ComplianceCaseList extends localize(i18next)(Page
33
33
  };
34
34
  }
35
35
  render() {
36
- return html `<ox-grist class="page-fill" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
36
+ return html `<ox-grist class="page-fill" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)} ?url-params-sensitive=${this.active}>
37
37
  <div slot="headroom" class="header">
38
38
  <div class="filters"><ox-filters-form without-search autofocus></ox-filters-form></div>
39
39
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"compliance-case-list.js","sourceRoot":"","sources":["../../client/pages/compliance-case-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist/ox-grist.js'\nimport '@operato/data-grist/ox-filters-form.js'\n\nimport gql from 'graphql-tag'\nimport { html } from 'lit'\nimport { customElement, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, FetchOption } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport { CASE_KINDS, openComplianceCaseForm } from '../components/compliance-case-form.js'\nimport { openComplianceCaseSheet } from '../components/compliance-case-sheet.js'\nimport { optionsOf, wordOf } from '../words.js'\n\nexport const CASE_STATUSES = ['RECEIVED', 'INVESTIGATING', 'DECIDED', 'TOLD', 'CLOSED']\nconst blankFirst = (options: { value: string; display: string }[]) => [{ value: '', display: '' }, ...options]\n\n/**\n * 신고 사건 (ADR-0187 decision 21) - the cases the handler reads, newest first: never one they are reported against,\n * never one left to its reporter. A case opens in its sheet, where its handling and investigation are written.\n */\n@customElement('compliance-case-list')\nexport class ComplianceCaseList extends localize(i18next)(PageView) {\n static styles = [WorkSurfacePageStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles]\n\n @state() gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('title.compliance-case-list'),\n filter: { handler: () => this.grist.toggleHeadroom() },\n actions: [\n { title: i18next.t('button.compliance-case-open'), icon: 'open_in_new', action: () => this.open() },\n { title: i18next.t('button.compliance-case-record'), icon: 'add', action: () => this.record() }\n ]\n }\n }\n\n render() {\n return html`<ox-grist class=\"page-fill\" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\"><ox-filters-form without-search autofocus></ox-filters-form></div>\n </div>\n </ox-grist>`\n }\n\n async pageInitialized() {\n const header = (name: string) => i18next.t(`field.compliance-case-${name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()}`)\n const shown = (name: string, width: number, renderer?: (value: any) => any, extra: any = {}) => ({ type: 'string', name, header: header(name), width, sortable: true, ...extra, record: { renderer, ...extra.record } })\n const names = (value: any[]) => (value ?? []).map(one => one.name).join(', ')\n this.gristConfig = {\n rows: { appendable: false, selectable: { multiple: false } },\n pagination: { limit: 100, pages: [50, 100] },\n emptyNote: { title: i18next.t('text.compliance-case-empty') },\n list: { fields: ['receivedOn', 'kind', 'status'], details: ['investigationDueOn'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'row-selector', multiple: false },\n shown('receivedOn', 100, undefined, { record: { align: 'center' } }),\n shown('kind', 120, value => wordOf('compliance-case-kind', value), { type: 'select', filter: { type: 'select', operator: 'eq', options: blankFirst(optionsOf('compliance-case-kind', CASE_KINDS)) } }),\n shown('status', 90, value => wordOf('compliance-case-status', value), { type: 'select', filter: { type: 'select', operator: 'eq', options: blankFirst(optionsOf('compliance-case-status', CASE_STATUSES)) } }),\n shown('reporter', 90, value => value?.name ?? '', { sortable: false }),\n shown('accused', 140, names, { sortable: false }),\n shown('investigationDueOn', 110, undefined, { record: { align: 'center' } }),\n shown('investigationStartedOn', 110, undefined, { record: { align: 'center' } }),\n shown('investigators', 140, names, { sortable: false }),\n shown('resultToldOn', 100, undefined, { record: { align: 'center' } }),\n shown('closedOn', 100, undefined, { record: { align: 'center' } })\n ],\n sorters: [{ name: 'receivedOn', desc: true }]\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: complianceCases(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id kind status receivedOn investigationDueOn investigationStartedOn resultToldOn closedOn\n reporter { id name } accused { id name } investigators { id name }\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings },\n fetchPolicy: 'network-only'\n })\n if (response.errors?.length) throw response\n return { total: response.data.responses.total, records: response.data.responses.items }\n }\n\n private async open() {\n const [chosen] = this.grist.selected\n if (!chosen?.id) return notify({ level: 'warn', message: i18next.t('text.compliance-case-pick-one') })\n await openComplianceCaseSheet(chosen.id)\n this.grist.fetch()\n }\n\n private async record() {\n if (await openComplianceCaseForm(true)) this.grist.fetch()\n }\n}\n"]}
1
+ {"version":3,"file":"compliance-case-list.js","sourceRoot":"","sources":["../../client/pages/compliance-case-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist/ox-grist.js'\nimport '@operato/data-grist/ox-filters-form.js'\n\nimport gql from 'graphql-tag'\nimport { html } from 'lit'\nimport { customElement, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, FetchOption } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport { CASE_KINDS, openComplianceCaseForm } from '../components/compliance-case-form.js'\nimport { openComplianceCaseSheet } from '../components/compliance-case-sheet.js'\nimport { optionsOf, wordOf } from '../words.js'\n\nexport const CASE_STATUSES = ['RECEIVED', 'INVESTIGATING', 'DECIDED', 'TOLD', 'CLOSED']\nconst blankFirst = (options: { value: string; display: string }[]) => [{ value: '', display: '' }, ...options]\n\n/**\n * 신고 사건 (ADR-0187 decision 21) - the cases the handler reads, newest first: never one they are reported against,\n * never one left to its reporter. A case opens in its sheet, where its handling and investigation are written.\n */\n@customElement('compliance-case-list')\nexport class ComplianceCaseList extends localize(i18next)(PageView) {\n static styles = [WorkSurfacePageStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles]\n\n @state() gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('title.compliance-case-list'),\n filter: { handler: () => this.grist.toggleHeadroom() },\n actions: [\n { title: i18next.t('button.compliance-case-open'), icon: 'open_in_new', action: () => this.open() },\n { title: i18next.t('button.compliance-case-record'), icon: 'add', action: () => this.record() }\n ]\n }\n }\n\n render() {\n return html`<ox-grist class=\"page-fill\" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)} ?url-params-sensitive=${this.active}>\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\"><ox-filters-form without-search autofocus></ox-filters-form></div>\n </div>\n </ox-grist>`\n }\n\n async pageInitialized() {\n const header = (name: string) => i18next.t(`field.compliance-case-${name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()}`)\n const shown = (name: string, width: number, renderer?: (value: any) => any, extra: any = {}) => ({ type: 'string', name, header: header(name), width, sortable: true, ...extra, record: { renderer, ...extra.record } })\n const names = (value: any[]) => (value ?? []).map(one => one.name).join(', ')\n this.gristConfig = {\n rows: { appendable: false, selectable: { multiple: false } },\n pagination: { limit: 100, pages: [50, 100] },\n emptyNote: { title: i18next.t('text.compliance-case-empty') },\n list: { fields: ['receivedOn', 'kind', 'status'], details: ['investigationDueOn'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'row-selector', multiple: false },\n shown('receivedOn', 100, undefined, { record: { align: 'center' } }),\n shown('kind', 120, value => wordOf('compliance-case-kind', value), { type: 'select', filter: { type: 'select', operator: 'eq', options: blankFirst(optionsOf('compliance-case-kind', CASE_KINDS)) } }),\n shown('status', 90, value => wordOf('compliance-case-status', value), { type: 'select', filter: { type: 'select', operator: 'eq', options: blankFirst(optionsOf('compliance-case-status', CASE_STATUSES)) } }),\n shown('reporter', 90, value => value?.name ?? '', { sortable: false }),\n shown('accused', 140, names, { sortable: false }),\n shown('investigationDueOn', 110, undefined, { record: { align: 'center' } }),\n shown('investigationStartedOn', 110, undefined, { record: { align: 'center' } }),\n shown('investigators', 140, names, { sortable: false }),\n shown('resultToldOn', 100, undefined, { record: { align: 'center' } }),\n shown('closedOn', 100, undefined, { record: { align: 'center' } })\n ],\n sorters: [{ name: 'receivedOn', desc: true }]\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: complianceCases(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id kind status receivedOn investigationDueOn investigationStartedOn resultToldOn closedOn\n reporter { id name } accused { id name } investigators { id name }\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings },\n fetchPolicy: 'network-only'\n })\n if (response.errors?.length) throw response\n return { total: response.data.responses.total, records: response.data.responses.items }\n }\n\n private async open() {\n const [chosen] = this.grist.selected\n if (!chosen?.id) return notify({ level: 'warn', message: i18next.t('text.compliance-case-pick-one') })\n await openComplianceCaseSheet(chosen.id)\n this.grist.fetch()\n }\n\n private async record() {\n if (await openComplianceCaseForm(true)) this.grist.fetch()\n }\n}\n"]}
@@ -33,6 +33,7 @@ let DisputeListPage = class DisputeListPage extends localize(i18next)(PageView)
33
33
  search: { handler: (search) => (this.grist.searchText = search), value: this.grist?.searchText || '' },
34
34
  filter: { handler: () => this.grist.toggleHeadroom() },
35
35
  actions: [
36
+ { title: i18next.t('button.legal-record-add-row'), icon: 'add', action: () => this.grist.addNewRecord() },
36
37
  { title: i18next.t('button.dispute-hearings'), icon: 'event', action: () => this.hearings() },
37
38
  { title: i18next.t('button.legal-record-files'), icon: 'attach_file', action: () => this.files() },
38
39
  { title: i18next.t('button.save'), action: () => this.save(), ...CommonButtonStyles.save }
@@ -41,7 +42,7 @@ let DisputeListPage = class DisputeListPage extends localize(i18next)(PageView)
41
42
  };
42
43
  }
43
44
  render() {
44
- return html `<ox-grist class="page-fill" search-mode="term" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
45
+ return html `<ox-grist class="page-fill" search-mode="term" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)} ?url-params-sensitive=${this.active}>
45
46
  <div slot="headroom" class="header">
46
47
  <div class="filters"><ox-filters-form without-search autofocus></ox-filters-form></div>
47
48
  </div>
@@ -59,7 +60,8 @@ let DisputeListPage = class DisputeListPage extends localize(i18next)(PageView)
59
60
  filter: { type: 'select', operator: 'eq', options: blankFirst(optionsOf(set, codes)) }
60
61
  });
61
62
  this.gristConfig = {
62
- rows: { appendable: true, selectable: { multiple: false } },
63
+ /* A dispute is started by 「행 추가」 or a paste - no empty row waits at the bottom. It opens as the server opens it. */
64
+ rows: { appendable: false, pasteAppendable: true, newRecord: () => ({ status: 'OPEN' }), selectable: { multiple: false } },
63
65
  pagination: { limit: 100, pages: [50, 100] },
64
66
  emptyNote: { title: i18next.t('text.dispute-empty'), description: i18next.t('text.dispute-empty-description') },
65
67
  list: { fields: ['title', 'kind', 'status'], details: ['counterparty', 'startedOn'] },
@@ -126,7 +128,7 @@ let DisputeListPage = class DisputeListPage extends localize(i18next)(PageView)
126
128
  return;
127
129
  const header = (name) => i18next.t(`field.dispute-hearing-${name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()}`);
128
130
  LegalChildGrid.open(`${i18next.t('button.dispute-hearings')} · ${dispute.title}`, {
129
- appendable: true,
131
+ creates: true,
130
132
  columns: [dayColumn('heldOn', header('heldOn')), textColumn('heldAt', header('heldAt'), 70), textColumn('name', header('name'), 160), textColumn('place', header('place'), 180), textColumn('notes', header('notes'), 200)],
131
133
  fetch: async () => {
132
134
  const response = await client.query({ query: gql `query ($id: String) { disputeHearings(disputeId: $id) { items { id heldOn heldAt name place notes } } }`, variables: { id: dispute.id }, fetchPolicy: 'network-only' });