@things-factory/inquiry 0.0.0-stage → 10.1.252

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 (106) hide show
  1. package/client/bootstrap.ts +27 -0
  2. package/client/components/inquiry-thread.ts +277 -0
  3. package/client/components/inquiry-todo.ts +36 -0
  4. package/client/components/inquiry-writer.ts +212 -0
  5. package/client/index.ts +2 -0
  6. package/client/inquiry-watch.ts +45 -0
  7. package/client/pages/inquiry-list.ts +218 -0
  8. package/client/route.ts +8 -0
  9. package/client/tsconfig.json +13 -0
  10. package/client/utils/inquiry-api.ts +103 -0
  11. package/client/utils/inquiry-badge.ts +46 -0
  12. package/client/utils/inquiry-words.ts +26 -0
  13. package/dist-client/bootstrap.d.ts +2 -0
  14. package/dist-client/bootstrap.js +25 -0
  15. package/dist-client/bootstrap.js.map +1 -0
  16. package/dist-client/components/inquiry-thread.d.ts +28 -0
  17. package/dist-client/components/inquiry-thread.js +303 -0
  18. package/dist-client/components/inquiry-thread.js.map +1 -0
  19. package/dist-client/components/inquiry-todo.d.ts +9 -0
  20. package/dist-client/components/inquiry-todo.js +43 -0
  21. package/dist-client/components/inquiry-todo.js.map +1 -0
  22. package/dist-client/components/inquiry-writer.d.ts +25 -0
  23. package/dist-client/components/inquiry-writer.js +233 -0
  24. package/dist-client/components/inquiry-writer.js.map +1 -0
  25. package/dist-client/index.d.ts +2 -0
  26. package/dist-client/index.js +3 -0
  27. package/dist-client/index.js.map +1 -0
  28. package/dist-client/inquiry-watch.d.ts +2 -0
  29. package/dist-client/inquiry-watch.js +41 -0
  30. package/dist-client/inquiry-watch.js.map +1 -0
  31. package/dist-client/pages/inquiry-list.d.ts +56 -0
  32. package/dist-client/pages/inquiry-list.js +241 -0
  33. package/dist-client/pages/inquiry-list.js.map +1 -0
  34. package/dist-client/route.d.ts +1 -0
  35. package/dist-client/route.js +9 -0
  36. package/dist-client/route.js.map +1 -0
  37. package/dist-client/tsconfig.tsbuildinfo +1 -0
  38. package/dist-client/utils/inquiry-api.d.ts +73 -0
  39. package/dist-client/utils/inquiry-api.js +34 -0
  40. package/dist-client/utils/inquiry-api.js.map +1 -0
  41. package/dist-client/utils/inquiry-badge.d.ts +4 -0
  42. package/dist-client/utils/inquiry-badge.js +47 -0
  43. package/dist-client/utils/inquiry-badge.js.map +1 -0
  44. package/dist-client/utils/inquiry-words.d.ts +13 -0
  45. package/dist-client/utils/inquiry-words.js +22 -0
  46. package/dist-client/utils/inquiry-words.js.map +1 -0
  47. package/dist-server/attachment-reader.d.ts +1 -0
  48. package/dist-server/attachment-reader.js +21 -0
  49. package/dist-server/attachment-reader.js.map +1 -0
  50. package/dist-server/index.d.ts +2 -0
  51. package/dist-server/index.js +22 -0
  52. package/dist-server/index.js.map +1 -0
  53. package/dist-server/inquiry-activity.d.ts +38 -0
  54. package/dist-server/inquiry-activity.js +38 -0
  55. package/dist-server/inquiry-activity.js.map +1 -0
  56. package/dist-server/role-tasks.d.ts +2 -0
  57. package/dist-server/role-tasks.js +14 -0
  58. package/dist-server/role-tasks.js.map +1 -0
  59. package/dist-server/service/index.d.ts +7 -0
  60. package/dist-server/service/index.js +24 -0
  61. package/dist-server/service/index.js.map +1 -0
  62. package/dist-server/service/inquiry/index.d.ts +4 -0
  63. package/dist-server/service/inquiry/index.js +8 -0
  64. package/dist-server/service/inquiry/index.js.map +1 -0
  65. package/dist-server/service/inquiry/inquiry-resolver.d.ts +29 -0
  66. package/dist-server/service/inquiry/inquiry-resolver.js +407 -0
  67. package/dist-server/service/inquiry/inquiry-resolver.js.map +1 -0
  68. package/dist-server/service/inquiry/inquiry-rules.d.ts +88 -0
  69. package/dist-server/service/inquiry/inquiry-rules.js +157 -0
  70. package/dist-server/service/inquiry/inquiry-rules.js.map +1 -0
  71. package/dist-server/service/inquiry/inquiry-service.d.ts +35 -0
  72. package/dist-server/service/inquiry/inquiry-service.js +143 -0
  73. package/dist-server/service/inquiry/inquiry-service.js.map +1 -0
  74. package/dist-server/service/inquiry/inquiry-types.d.ts +18 -0
  75. package/dist-server/service/inquiry/inquiry-types.js +69 -0
  76. package/dist-server/service/inquiry/inquiry-types.js.map +1 -0
  77. package/dist-server/service/inquiry/inquiry.d.ts +48 -0
  78. package/dist-server/service/inquiry/inquiry.js +232 -0
  79. package/dist-server/service/inquiry/inquiry.js.map +1 -0
  80. package/dist-server/tsconfig.tsbuildinfo +1 -0
  81. package/package.json +51 -4
  82. package/server/attachment-reader.ts +18 -0
  83. package/server/index.ts +18 -0
  84. package/server/inquiry-activity.ts +35 -0
  85. package/server/role-tasks.ts +13 -0
  86. package/server/service/index.ts +19 -0
  87. package/server/service/inquiry/index.ts +5 -0
  88. package/server/service/inquiry/inquiry-resolver.ts +321 -0
  89. package/server/service/inquiry/inquiry-rules.ts +173 -0
  90. package/server/service/inquiry/inquiry-service.ts +143 -0
  91. package/server/service/inquiry/inquiry-types.ts +45 -0
  92. package/server/service/inquiry/inquiry.ts +180 -0
  93. package/server/tsconfig.json +11 -0
  94. package/test/inquiry-persistence.test.ts +218 -0
  95. package/test/inquiry-rules.test.ts +121 -0
  96. package/test/open-doors.test.ts +44 -0
  97. package/test/translations.test.ts +53 -0
  98. package/test/writer-popup-standard.test.ts +40 -0
  99. package/things-factory.config.js +8 -0
  100. package/translations/en.json +93 -0
  101. package/translations/es.json +93 -0
  102. package/translations/ja.json +93 -0
  103. package/translations/ko.json +93 -0
  104. package/translations/ms.json +93 -0
  105. package/translations/zh.json +93 -0
  106. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inquiry-writer.js","sourceRoot":"","sources":["../../client/components/inquiry-writer.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 문의 · 제안 보내기 (ADR-0184 decisions 1, 4, 5, 9) - the window the avatar menu opens on any screen: the kind, the title,\n * the words, files, and who reads it. The screen it was opened on goes with it; the application, its version, the\n * writer and the domain are the server's to take.\n */\nimport '@material/web/icon/icon.js'\nimport '@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/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { CommonPopupStyles, FormFieldStyles, PopupBodyStyles, PopupFieldStyles } from '@operato/styles'\n\nimport { inquiriesChanged, inquiryApi } from '../utils/inquiry-api.js'\nimport { KINDS, kindWord, reasonOf, t } from '../utils/inquiry-words.js'\n\nconst MAX_TITLE = 200\n\n/** Opens the window, carrying the screen it is opened on. */\nexport function openInquiryWriter(kind = 'QUESTION') {\n const pageUrl = location.href\n const handle: any = openPopup(\n html`<inquiry-writer .kind=${kind} .pageUrl=${pageUrl} @close=${() => handle.close()}></inquiry-writer>`,\n {\n backdrop: true,\n size: 'large',\n title: t('inquiry.title.write')\n }\n )\n return handle\n}\n\n@customElement('inquiry-writer')\nexport class InquiryWriter extends localize(i18next)(LitElement) {\n /* The house shape of a popup (page-standard sections 7, 8): only the body scrolls, fields are labels above native\n inputs, the one button row is `ox-popup-actions`. */\n static styles = [\n CommonPopupStyles,\n PopupBodyStyles,\n FormFieldStyles,\n PopupFieldStyles,\n css`\n ox-input-select-buttons {\n align-self: flex-start;\n }\n textarea {\n min-height: 160px;\n resize: vertical;\n }\n .note {\n color: var(--ui-muted);\n font-size: var(--ui-t-small, 11.5px);\n word-break: break-all;\n }\n .files {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small, 4px);\n align-items: center;\n color: var(--ui-ink);\n }\n .file {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .file md-icon {\n --md-icon-size: 14px;\n }\n .file button {\n border: 0;\n background: transparent;\n box-shadow: none;\n padding: 0;\n cursor: pointer;\n color: var(--ui-muted);\n }\n .check {\n display: flex;\n align-items: center;\n gap: var(--spacing-small, 4px);\n color: var(--ui-ink);\n }\n /* The field rule stretches its inputs to the row; a checkbox keeps its own size. */\n .field .check input {\n width: auto;\n margin: 0;\n }\n `\n ]\n\n @property() kind = 'QUESTION'\n @property() pageUrl = ''\n @state() title = ''\n @state() body = ''\n @state() privately = false\n @state() files: File[] = []\n @state() sending = false\n /* Set only while files go up - the picker shows its bar then. */\n @state() progress?: number\n\n render() {\n const title = this.title.trim()\n return html`\n <div class=\"body\">\n <div class=\"field\">\n <ox-input-select-buttons\n .value=${this.kind}\n .options=${KINDS.map(code => ({ display: kindWord(code), value: code }))}\n @change=${(e: CustomEvent) => e.detail && (this.kind = e.detail)}\n ></ox-input-select-buttons>\n <span>${t(`inquiry.text.kind-hint-${this.kind.toLowerCase()}`)}</span>\n </div>\n <label class=\"field\">\n <span\n >${t('inquiry.field.title')} ·\n ${t('inquiry.text.title-limit', { count: this.title.length, max: MAX_TITLE })}</span\n >\n <input .value=${this.title} maxlength=${MAX_TITLE} @input=${(e: any) => (this.title = e.target.value)} />\n </label>\n <label class=\"field\">\n <span>${t('inquiry.field.body')}</span>\n <textarea\n .value=${this.body}\n placeholder=${t(`inquiry.text.body-placeholder-${this.kind.toLowerCase()}`)}\n @input=${(e: any) => (this.body = e.target.value)}\n ></textarea>\n </label>\n <div class=\"files\">\n ${this.files.map(\n (file, index) =>\n html`<span class=\"file\"\n ><md-icon>attach_file</md-icon>${file.name}<button\n aria-label=${t('inquiry.button.remove')}\n @click=${() => (this.files = this.files.filter((_, i) => i !== index))}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n <ox-input-file\n quiet\n hide-filelist\n multiple\n icon=\"attach_file\"\n .progress=${this.progress}\n @change=${(e: CustomEvent) => this.pick(e)}\n ></ox-input-file>\n </div>\n <div class=\"field\">\n <label class=\"check\"\n ><input\n type=\"checkbox\"\n .checked=${this.privately}\n @change=${(e: any) => (this.privately = e.target.checked)}\n />${t('inquiry.text.private-label')}</label\n >\n <span>${this.privately ? t('inquiry.text.private-hint') : t('inquiry.text.domain-hint')}</span>\n </div>\n ${this.pageUrl ? html`<div class=\"note\">${t('inquiry.text.page-hint', { page: this.pageUrl })}</div>` : nothing}\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.dispatchEvent(new CustomEvent('close'))}\n >${t('inquiry.button.cancel')}</md-text-button\n >\n <md-filled-button slot=\"confirm\" ?disabled=${!title || this.sending} @click=${() => this.send()}\n >${t('inquiry.button.submit')}</md-filled-button\n >\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 send() {\n this.sending = true\n try {\n await inquiryApi.create(\n {\n kind: this.kind,\n title: this.title.trim(),\n body: this.body,\n visibility: this.privately ? 'PRIVATE' : 'DOMAIN',\n pageUrl: this.pageUrl\n },\n this.files,\n fraction => (this.progress = fraction)\n )\n inquiriesChanged()\n notify({ message: t('inquiry.text.sent') })\n /* The writer stays on the screen they were on - the answer comes as a notice and on the menu's badge. */\n this.dispatchEvent(new CustomEvent('close'))\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.sending = false\n this.progress = undefined\n }\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { generateInquiryBadge, refreshInquiryBadge } from './utils/inquiry-badge.js';
2
+ export { openInquiryWriter } from './components/inquiry-writer.js';
@@ -0,0 +1,3 @@
1
+ export { generateInquiryBadge, refreshInquiryBadge } from './utils/inquiry-badge.js';
2
+ export { openInquiryWriter } from './components/inquiry-writer.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA","sourcesContent":["export { generateInquiryBadge, refreshInquiryBadge } from './utils/inquiry-badge.js'\nexport { openInquiryWriter } from './components/inquiry-writer.js'\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function startInquiryWatch(): Promise<void>;
2
+ export declare function stopInquiryWatch(): void;
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Keeps the menu badge up with inquiries while the application is open (ADR-0184 decision 8). The notice of an inquiry
3
+ * reaches the screen through notification's subscription; the count itself is asked of the server.
4
+ */
5
+ import gql from 'graphql-tag';
6
+ import { subscribe } from '@operato/graphql';
7
+ import { refreshInquiryBadge } from './utils/inquiry-badge.js';
8
+ window.addEventListener('inquiries-changed', () => refreshInquiryBadge());
9
+ let subscription;
10
+ let watching = false;
11
+ export async function startInquiryWatch() {
12
+ if (watching)
13
+ return;
14
+ watching = true;
15
+ refreshInquiryBadge();
16
+ try {
17
+ subscription = await subscribe({
18
+ query: gql `
19
+ subscription {
20
+ notification(subjects: ["info"]) {
21
+ type
22
+ }
23
+ }
24
+ `
25
+ }, {
26
+ next({ data }) {
27
+ if (data?.notification?.type === 'inquiry')
28
+ refreshInquiryBadge();
29
+ }
30
+ });
31
+ }
32
+ catch {
33
+ /* without the live line the badge comes at the next sign-in or the next change on a screen */
34
+ }
35
+ }
36
+ export function stopInquiryWatch() {
37
+ subscription?.unsubscribe();
38
+ subscription = undefined;
39
+ watching = false;
40
+ }
41
+ //# sourceMappingURL=inquiry-watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inquiry-watch.js","sourceRoot":"","sources":["../client/inquiry-watch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAE9D,MAAM,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC,CAAA;AACzE,IAAI,YAAiD,CAAA;AACrD,IAAI,QAAQ,GAAG,KAAK,CAAA;AAEpB,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,QAAQ;QAAE,OAAM;IACpB,QAAQ,GAAG,IAAI,CAAA;IACf,mBAAmB,EAAE,CAAA;IACrB,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,SAAS,CAC5B;YACE,KAAK,EAAE,GAAG,CAAA;;;;;;SAMT;SACF,EACD;YACE,IAAI,CAAC,EAAE,IAAI,EAAO;gBAChB,IAAI,IAAI,EAAE,YAAY,EAAE,IAAI,KAAK,SAAS;oBAAE,mBAAmB,EAAE,CAAA;YACnE,CAAC;SACF,CACF,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,8FAA8F;IAChG,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,YAAY,GAAG,SAAS,CAAA;IACxB,QAAQ,GAAG,KAAK,CAAA;AAClB,CAAC","sourcesContent":["/*\n * Keeps the menu badge up with inquiries while the application is open (ADR-0184 decision 8). The notice of an inquiry\n * reaches the screen through notification's subscription; the count itself is asked of the server.\n */\nimport gql from 'graphql-tag'\n\nimport { subscribe } from '@operato/graphql'\n\nimport { refreshInquiryBadge } from './utils/inquiry-badge.js'\n\nwindow.addEventListener('inquiries-changed', () => refreshInquiryBadge())\nlet subscription: { unsubscribe(): void } | undefined\nlet watching = false\n\nexport async function startInquiryWatch(): Promise<void> {\n if (watching) return\n watching = true\n refreshInquiryBadge()\n try {\n subscription = await subscribe(\n {\n query: gql`\n subscription {\n notification(subjects: [\"info\"]) {\n type\n }\n }\n `\n },\n {\n next({ data }: any) {\n if (data?.notification?.type === 'inquiry') refreshInquiryBadge()\n }\n }\n )\n } catch {\n /* without the live line the badge comes at the next sign-in or the next change on a screen */\n }\n}\n\nexport function stopInquiryWatch(): void {\n subscription?.unsubscribe()\n subscription = undefined\n watching = false\n}\n"]}
@@ -0,0 +1,56 @@
1
+ import '@material/web/icon/icon.js';
2
+ import '@operato/data-grist/ox-grist.js';
3
+ import '@operato/data-grist/ox-filters-form.js';
4
+ import '@operato/input/ox-select.js';
5
+ import '@operato/popup/ox-popup-list.js';
6
+ import '../components/inquiry-thread.js';
7
+ import { FetchOption } from '@operato/data-grist';
8
+ import { PageView } from '@operato/shell';
9
+ declare const InquiryList_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
10
+ /**
11
+ * 문의 · 제안 — the questions, bug reports and proposals of the domain that the person may read, and with `?id=` one of
12
+ * them as its thread (ADR-0184 decision 8). Handlers work from here too: they open on those waiting on them.
13
+ */
14
+ export declare class InquiryList extends InquiryList_base {
15
+ static styles: import("lit").CSSResult[];
16
+ gristConfig: any;
17
+ scope: string;
18
+ handler: boolean;
19
+ openId: string;
20
+ private grist;
21
+ private thread;
22
+ private onChanged;
23
+ get context(): {
24
+ actions: ({
25
+ title: string;
26
+ icon: string;
27
+ action: () => Promise<boolean>;
28
+ emphasis?: undefined;
29
+ } | {
30
+ title: string;
31
+ icon: string;
32
+ emphasis: {
33
+ raised: boolean;
34
+ };
35
+ action: () => any;
36
+ })[];
37
+ search?: {
38
+ handler: (search: string) => void;
39
+ value: string;
40
+ } | undefined;
41
+ filter?: {
42
+ handler: () => void;
43
+ } | undefined;
44
+ title: string;
45
+ };
46
+ render(): import("lit-html").TemplateResult<1>;
47
+ connectedCallback(): void;
48
+ disconnectedCallback(): void;
49
+ pageUpdated(changes: any, lifecycle: any): Promise<void>;
50
+ pageInitialized(): Promise<void>;
51
+ fetchHandler({ page, limit, filters, search }: FetchOption): Promise<{
52
+ total: any;
53
+ records: any;
54
+ }>;
55
+ }
56
+ export {};
@@ -0,0 +1,241 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/icon/icon.js';
3
+ import '@operato/data-grist/ox-grist.js';
4
+ import '@operato/data-grist/ox-filters-form.js';
5
+ import '@operato/input/ox-select.js';
6
+ import '@operato/popup/ox-popup-list.js';
7
+ import '../components/inquiry-thread.js';
8
+ import gql from 'graphql-tag';
9
+ import { css, html, nothing } from 'lit';
10
+ import { customElement, query, state } from 'lit/decorators.js';
11
+ import { DataGrist } from '@operato/data-grist';
12
+ import { client } from '@operato/graphql';
13
+ import { i18next, localize } from '@operato/i18n';
14
+ import { navigate, PageView } from '@operato/shell';
15
+ import { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
16
+ import { isMobileDevice } from '@operato/utils';
17
+ import { openInquiryWriter } from '../components/inquiry-writer.js';
18
+ import { inquiryApi, LIST_FIELDS } from '../utils/inquiry-api.js';
19
+ import { KIND_ICONS, KINDS, kindWord, STATUSES, statusWord, t, visibilityWord, when } from '../utils/inquiry-words.js';
20
+ /**
21
+ * 문의 · 제안 — the questions, bug reports and proposals of the domain that the person may read, and with `?id=` one of
22
+ * them as its thread (ADR-0184 decision 8). Handlers work from here too: they open on those waiting on them.
23
+ */
24
+ let InquiryList = class InquiryList extends localize(i18next)(PageView) {
25
+ constructor() {
26
+ super(...arguments);
27
+ this.scope = 'all';
28
+ this.handler = false;
29
+ /* The inquiry shown as its thread - none shows the list. */
30
+ this.openId = '';
31
+ this.onChanged = () => {
32
+ if (this.openId)
33
+ return;
34
+ this.grist?.fetch();
35
+ };
36
+ }
37
+ static { this.styles = [
38
+ WorkSurfacePageStyles,
39
+ CommonGristStyles,
40
+ CommonHeaderStyles,
41
+ ScrollbarStyles,
42
+ css `
43
+ .filters {
44
+ display: flex;
45
+ flex-wrap: wrap;
46
+ align-items: center;
47
+ gap: var(--spacing-medium, 8px);
48
+ }
49
+ ox-select {
50
+ min-width: 140px;
51
+ }
52
+ .thread {
53
+ overflow: auto;
54
+ padding: var(--spacing-large, 12px) var(--spacing-huge, 16px);
55
+ max-width: 880px;
56
+ width: 100%;
57
+ box-sizing: border-box;
58
+ }
59
+ `
60
+ ]; }
61
+ get context() {
62
+ return {
63
+ title: t('inquiry.title.list'),
64
+ ...(this.openId
65
+ ? {}
66
+ : {
67
+ search: {
68
+ handler: (search) => {
69
+ this.grist.searchText = search;
70
+ },
71
+ value: this.grist?.searchText || ''
72
+ },
73
+ filter: {
74
+ handler: () => {
75
+ this.grist.toggleHeadroom();
76
+ }
77
+ }
78
+ }),
79
+ actions: [
80
+ ...(this.openId ? [{ title: t('inquiry.button.back'), icon: 'arrow_back', action: () => navigate('inquiry-list') }] : []),
81
+ { title: t('inquiry.button.send'), icon: 'add', emphasis: { raised: true }, action: () => openInquiryWriter() }
82
+ ]
83
+ };
84
+ }
85
+ render() {
86
+ if (this.openId)
87
+ return html `<div class="thread"><inquiry-thread .inquiryId=${this.openId}></inquiry-thread></div>`;
88
+ const scopes = [
89
+ { value: 'all', display: t('inquiry.scope.all') },
90
+ { value: 'mine', display: t('inquiry.scope.mine') },
91
+ ...(this.handler ? [{ value: 'handlers-turn', display: t('inquiry.scope.handlers-turn') }] : [])
92
+ ];
93
+ return html `<ox-grist class="page-fill" search-mode="term" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
94
+ <div slot="headroom" class="header">
95
+ <div class="filters">
96
+ <ox-select
97
+ .value=${this.scope}
98
+ aria-label=${t('inquiry.text.scope')}
99
+ @change=${(e) => {
100
+ const next = String(e.detail ?? 'all');
101
+ if (next === this.scope)
102
+ return;
103
+ this.scope = next;
104
+ this.grist.fetch();
105
+ }}
106
+ >
107
+ <span slot="label">${scopes.find(one => one.value === this.scope)?.display}</span>
108
+ <ox-popup-list align-left nowrap>${scopes.map(one => html `<div option value=${one.value}>${one.display}</div>`)}</ox-popup-list>
109
+ </ox-select>
110
+ <ox-filters-form without-search autofocus></ox-filters-form>
111
+ </div>
112
+ </div>
113
+ </ox-grist>`;
114
+ }
115
+ connectedCallback() {
116
+ super.connectedCallback();
117
+ window.addEventListener('inquiries-changed', this.onChanged);
118
+ }
119
+ disconnectedCallback() {
120
+ window.removeEventListener('inquiries-changed', this.onChanged);
121
+ super.disconnectedCallback();
122
+ }
123
+ async pageUpdated(changes, lifecycle) {
124
+ if (!this.active || !(changes.active || changes.params))
125
+ return;
126
+ const id = String(lifecycle?.params?.id ?? '');
127
+ if (id !== this.openId) {
128
+ this.openId = id;
129
+ this.updateContext();
130
+ }
131
+ else if (id)
132
+ this.thread?.load(true);
133
+ else if (this.gristConfig)
134
+ this.grist?.fetch();
135
+ }
136
+ async pageInitialized() {
137
+ try {
138
+ this.handler = (await inquiryApi.summary()).handler;
139
+ /* A handler opens on what waits on them. */
140
+ if (this.handler)
141
+ this.scope = 'handlers-turn';
142
+ }
143
+ catch {
144
+ this.handler = false;
145
+ }
146
+ const open = (record) => record?.id && navigate(`inquiry-list?id=${record.id}`);
147
+ this.gristConfig = {
148
+ rows: { appendable: false, selectable: false, handlers: { click: (_c, _d, _col, record) => open(record) } },
149
+ pagination: { limit: 50, pages: [50, 100] },
150
+ emptyNote: { title: t('inquiry.text.empty'), description: t('inquiry.text.empty-description') },
151
+ list: { fields: ['title', 'status'], details: ['kind', 'createdAt'] },
152
+ columns: [
153
+ {
154
+ type: 'string',
155
+ name: 'kind',
156
+ header: t('inquiry.field.kind'),
157
+ width: 110,
158
+ record: {
159
+ editable: false,
160
+ renderer: (value) => html `<span style="display:inline-flex;align-items:center;gap:2px"><md-icon style="--md-icon-size:16px">${KIND_ICONS[value] ?? 'help'}</md-icon>${kindWord(value)}</span>`
161
+ },
162
+ filter: { type: 'select', operator: 'eq', options: [{ display: '', value: '' }, ...KINDS.map(code => ({ display: kindWord(code), value: code }))] }
163
+ },
164
+ {
165
+ type: 'string',
166
+ name: 'title',
167
+ header: t('inquiry.field.title'),
168
+ width: 320,
169
+ record: {
170
+ editable: false,
171
+ renderer: (value, _c, record) => html `<span style=${record?.isNew ? 'font-weight:600' : ''}
172
+ >${record?.visibility === 'PRIVATE' ? html `<md-icon style="--md-icon-size:14px" title=${visibilityWord('PRIVATE')}>lock</md-icon> ` : nothing}${value}${record?.replyCount
173
+ ? ` (${record.replyCount})`
174
+ : ''}</span
175
+ >`
176
+ }
177
+ },
178
+ {
179
+ type: 'string',
180
+ name: 'status',
181
+ header: t('inquiry.field.status'),
182
+ width: 100,
183
+ record: {
184
+ editable: false,
185
+ renderer: (value, _c, record) => html `<span style=${record?.isNew ? 'color:var(--md-sys-color-primary);font-weight:600' : ''}>${statusWord(value)}${record?.isNew ? ` · ${t('inquiry.text.new')}` : ''}</span>`
186
+ },
187
+ filter: { type: 'select', operator: 'eq', options: [{ display: '', value: '' }, ...STATUSES.map(code => ({ display: statusWord(code), value: code }))] }
188
+ },
189
+ { type: 'string', name: 'creator', header: t('inquiry.field.writer'), width: 110, record: { editable: false, renderer: (value) => value?.name ?? '' } },
190
+ { type: 'string', name: 'assignee', header: t('inquiry.field.assignee'), width: 110, record: { editable: false, renderer: (value) => value?.name ?? '' } },
191
+ { type: 'string', name: 'createdAt', header: t('inquiry.field.created-at'), width: 130, record: { editable: false, renderer: (value) => when(value) } }
192
+ ]
193
+ };
194
+ }
195
+ async fetchHandler({ page = 1, limit = 50, filters = [], search }) {
196
+ const response = await client.query({
197
+ query: gql `
198
+ query ($filters: [Filter!], $pagination: Pagination, $search: String, $scope: String) {
199
+ responses: inquiries(filters: $filters, pagination: $pagination, search: $search, scope: $scope) {
200
+ items { ${LIST_FIELDS} }
201
+ total
202
+ }
203
+ }
204
+ `,
205
+ variables: { filters, pagination: { page, limit }, search: search?.trim() || undefined, scope: this.scope },
206
+ fetchPolicy: 'network-only'
207
+ });
208
+ if (response.errors?.length)
209
+ throw response;
210
+ return { total: response.data.responses.total, records: response.data.responses.items };
211
+ }
212
+ };
213
+ __decorate([
214
+ state(),
215
+ __metadata("design:type", Object)
216
+ ], InquiryList.prototype, "gristConfig", void 0);
217
+ __decorate([
218
+ state(),
219
+ __metadata("design:type", Object)
220
+ ], InquiryList.prototype, "scope", void 0);
221
+ __decorate([
222
+ state(),
223
+ __metadata("design:type", Object)
224
+ ], InquiryList.prototype, "handler", void 0);
225
+ __decorate([
226
+ state(),
227
+ __metadata("design:type", Object)
228
+ ], InquiryList.prototype, "openId", void 0);
229
+ __decorate([
230
+ query('ox-grist'),
231
+ __metadata("design:type", DataGrist)
232
+ ], InquiryList.prototype, "grist", void 0);
233
+ __decorate([
234
+ query('inquiry-thread'),
235
+ __metadata("design:type", Function)
236
+ ], InquiryList.prototype, "thread", void 0);
237
+ InquiryList = __decorate([
238
+ customElement('inquiry-list')
239
+ ], InquiryList);
240
+ export { InquiryList };
241
+ //# sourceMappingURL=inquiry-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inquiry-list.js","sourceRoot":"","sources":["../../client/pages/inquiry-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist/ox-grist.js'\nimport '@operato/data-grist/ox-filters-form.js'\nimport '@operato/input/ox-select.js'\nimport '@operato/popup/ox-popup-list.js'\nimport '../components/inquiry-thread.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } 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 { navigate, PageView } from '@operato/shell'\nimport { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport { openInquiryWriter } from '../components/inquiry-writer.js'\nimport type { InquiryThread } from '../components/inquiry-thread.js'\nimport { inquiryApi, LIST_FIELDS } from '../utils/inquiry-api.js'\nimport { KIND_ICONS, KINDS, kindWord, STATUSES, statusWord, t, visibilityWord, when } from '../utils/inquiry-words.js'\n\n/**\n * 문의 · 제안 — the questions, bug reports and proposals of the domain that the person may read, and with `?id=` one of\n * them as its thread (ADR-0184 decision 8). Handlers work from here too: they open on those waiting on them.\n */\n@customElement('inquiry-list')\nexport class InquiryList extends localize(i18next)(PageView) {\n static styles = [\n WorkSurfacePageStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n .filters {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-medium, 8px);\n }\n ox-select {\n min-width: 140px;\n }\n .thread {\n overflow: auto;\n padding: var(--spacing-large, 12px) var(--spacing-huge, 16px);\n max-width: 880px;\n width: 100%;\n box-sizing: border-box;\n }\n `\n ]\n\n @state() gristConfig: any\n @state() scope = 'all'\n @state() handler = false\n /* The inquiry shown as its thread - none shows the list. */\n @state() openId = ''\n @query('ox-grist') private grist!: DataGrist\n @query('inquiry-thread') private thread!: InquiryThread\n\n private onChanged = () => {\n if (this.openId) return\n this.grist?.fetch()\n }\n\n get context() {\n return {\n title: t('inquiry.title.list'),\n ...(this.openId\n ? {}\n : {\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n }\n }),\n actions: [\n ...(this.openId ? [{ title: t('inquiry.button.back'), icon: 'arrow_back', action: () => navigate('inquiry-list') }] : []),\n { title: t('inquiry.button.send'), icon: 'add', emphasis: { raised: true }, action: () => openInquiryWriter() }\n ]\n }\n }\n\n render() {\n if (this.openId) return html`<div class=\"thread\"><inquiry-thread .inquiryId=${this.openId}></inquiry-thread></div>`\n const scopes = [\n { value: 'all', display: t('inquiry.scope.all') },\n { value: 'mine', display: t('inquiry.scope.mine') },\n ...(this.handler ? [{ value: 'handlers-turn', display: t('inquiry.scope.handlers-turn') }] : [])\n ]\n return html`<ox-grist class=\"page-fill\" search-mode=\"term\" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <ox-select\n .value=${this.scope}\n aria-label=${t('inquiry.text.scope')}\n @change=${(e: CustomEvent) => {\n const next = String(e.detail ?? 'all')\n if (next === this.scope) return\n this.scope = next\n this.grist.fetch()\n }}\n >\n <span slot=\"label\">${scopes.find(one => one.value === this.scope)?.display}</span>\n <ox-popup-list align-left nowrap>${scopes.map(one => html`<div option value=${one.value}>${one.display}</div>`)}</ox-popup-list>\n </ox-select>\n <ox-filters-form without-search autofocus></ox-filters-form>\n </div>\n </div>\n </ox-grist>`\n }\n\n connectedCallback() {\n super.connectedCallback()\n window.addEventListener('inquiries-changed', this.onChanged)\n }\n\n disconnectedCallback() {\n window.removeEventListener('inquiries-changed', this.onChanged)\n super.disconnectedCallback()\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (!this.active || !(changes.active || changes.params)) return\n const id = String(lifecycle?.params?.id ?? '')\n if (id !== this.openId) {\n this.openId = id\n this.updateContext()\n } else if (id) this.thread?.load(true)\n else if (this.gristConfig) this.grist?.fetch()\n }\n\n async pageInitialized() {\n try {\n this.handler = (await inquiryApi.summary()).handler\n /* A handler opens on what waits on them. */\n if (this.handler) this.scope = 'handlers-turn'\n } catch {\n this.handler = false\n }\n const open = (record: any) => record?.id && navigate(`inquiry-list?id=${record.id}`)\n this.gristConfig = {\n rows: { appendable: false, selectable: false, handlers: { click: (_c: any, _d: any, _col: any, record: any) => open(record) } },\n pagination: { limit: 50, pages: [50, 100] },\n emptyNote: { title: t('inquiry.text.empty'), description: t('inquiry.text.empty-description') },\n list: { fields: ['title', 'status'], details: ['kind', 'createdAt'] },\n columns: [\n {\n type: 'string',\n name: 'kind',\n header: t('inquiry.field.kind'),\n width: 110,\n record: {\n editable: false,\n renderer: (value: string) => html`<span style=\"display:inline-flex;align-items:center;gap:2px\"><md-icon style=\"--md-icon-size:16px\">${KIND_ICONS[value] ?? 'help'}</md-icon>${kindWord(value)}</span>`\n },\n filter: { type: 'select', operator: 'eq', options: [{ display: '', value: '' }, ...KINDS.map(code => ({ display: kindWord(code), value: code }))] }\n },\n {\n type: 'string',\n name: 'title',\n header: t('inquiry.field.title'),\n width: 320,\n record: {\n editable: false,\n renderer: (value: string, _c: any, record: any) =>\n html`<span style=${record?.isNew ? 'font-weight:600' : ''}\n >${record?.visibility === 'PRIVATE' ? html`<md-icon style=\"--md-icon-size:14px\" title=${visibilityWord('PRIVATE')}>lock</md-icon> ` : nothing}${value}${record?.replyCount\n ? ` (${record.replyCount})`\n : ''}</span\n >`\n }\n },\n {\n type: 'string',\n name: 'status',\n header: t('inquiry.field.status'),\n width: 100,\n record: {\n editable: false,\n renderer: (value: string, _c: any, record: any) =>\n html`<span style=${record?.isNew ? 'color:var(--md-sys-color-primary);font-weight:600' : ''}>${statusWord(value)}${record?.isNew ? ` · ${t('inquiry.text.new')}` : ''}</span>`\n },\n filter: { type: 'select', operator: 'eq', options: [{ display: '', value: '' }, ...STATUSES.map(code => ({ display: statusWord(code), value: code }))] }\n },\n { type: 'string', name: 'creator', header: t('inquiry.field.writer'), width: 110, record: { editable: false, renderer: (value: any) => value?.name ?? '' } },\n { type: 'string', name: 'assignee', header: t('inquiry.field.assignee'), width: 110, record: { editable: false, renderer: (value: any) => value?.name ?? '' } },\n { type: 'string', name: 'createdAt', header: t('inquiry.field.created-at'), width: 130, record: { editable: false, renderer: (value: string) => when(value) } }\n ]\n }\n }\n\n async fetchHandler({ page = 1, limit = 50, filters = [], search }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $search: String, $scope: String) {\n responses: inquiries(filters: $filters, pagination: $pagination, search: $search, scope: $scope) {\n items { ${LIST_FIELDS} }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, search: search?.trim() || undefined, scope: this.scope },\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"]}
@@ -0,0 +1 @@
1
+ export default function route(page: string): "inquiry-list" | undefined;
@@ -0,0 +1,9 @@
1
+ /* The page this module brings to an application that puts it in its menu (ADR-0184 decision 8). */
2
+ export default function route(page) {
3
+ switch (page) {
4
+ case 'inquiry-list':
5
+ import('./pages/inquiry-list.js');
6
+ return page;
7
+ }
8
+ }
9
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../client/route.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAY;IACxC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,cAAc;YACjB,MAAM,CAAC,yBAAyB,CAAC,CAAA;YACjC,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC","sourcesContent":["/* The page this module brings to an application that puts it in its menu (ADR-0184 decision 8). */\nexport default function route(page: string) {\n switch (page) {\n case 'inquiry-list':\n import('./pages/inquiry-list.js')\n return page\n }\n}\n"]}