@webx-ui/module-inbox 0.5.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FormNotifications.d.ts +3 -1
- package/dist/api.d.ts +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1454 -1294
- package/dist/index.js.map +1 -1
- package/dist/recipients.d.ts +8 -0
- package/dist/style.css +1 -1
- package/dist/types.d.ts +39 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/LocalizedRichText.vue","../src/api.ts","../src/messages.ts","../src/i18n.ts","../src/types.ts","../src/FieldDialog.vue","../src/FieldList.vue","../src/options.ts","../src/FormAntispam.vue","../src/FormEmbed.vue","../src/FormGeneral.vue","../src/FormNotifications.vue","../src/FormEditorPage.vue","../src/FormCreateDialog.vue","../src/SubmissionCreateDialog.vue","../src/SubmissionList.vue","../src/InboxPage.vue","../src/StatusDialog.vue","../src/StatusesPage.vue","../src/SubmissionPage.vue","../src/module.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useLocales, WxLocales, WxRichText, type LocalizedValue } from '@webx-ui/core'\n\n/**\n * Rich text in every language the site publishes in.\n *\n * `WxRichText` holds one string, the way `WxInput` does without `localized`; what a localized\n * field adds is the picker and the map underneath it. This is that, for the one place in this\n * module that needs it — the thank-you, which is printed raw on the site and is therefore\n * written where formatting is possible.\n *\n * With no content languages at all — a panel assembled by hand, a test — the value stays a\n * plain string, which is exactly what `useLocalized` does in the same situation and what the\n * server accepts for a form written before the site had a second language.\n */\nconst model = defineModel<LocalizedValue | string>({ default: '' })\n\nconst props = withDefaults(defineProps<{ placeholder?: string; minHeight?: string }>(), {\n placeholder: undefined,\n minHeight: '160px',\n})\n\nconst locales = useLocales()\n\nconst active = computed(() => {\n const chosen = locales.active.value\n const known = locales.list.value.some((locale) => locale.code === chosen)\n\n return known ? chosen : (locales.list.value[0]?.code ?? '')\n})\n\nconst text = computed({\n get: () => {\n const value = model.value\n\n if (typeof value === 'string') {\n // A string under a localized field belongs to the first language: that is where the\n // words were written, and hiding them would look like losing them.\n return active.value === '' || active.value === locales.list.value[0]?.code ? value : ''\n }\n\n return value[active.value] ?? ''\n },\n set: (next: string) => {\n if (active.value === '') {\n model.value = next\n\n return\n }\n\n const base = typeof model.value === 'string' ? { [active.value]: model.value } : model.value\n\n model.value = { ...base, [active.value]: next }\n },\n})\n</script>\n\n<template>\n <wx-locales v-if=\"locales.list.value.length > 0\">\n <wx-rich-text v-model=\"text\" :placeholder=\"props.placeholder\" :min-height=\"props.minHeight\" />\n </wx-locales>\n\n <wx-rich-text\n v-else\n v-model=\"text\"\n :placeholder=\"props.placeholder\"\n :min-height=\"props.minHeight\"\n />\n</template>\n","import type { AdminContext } from '@webx-ui/module-admin'\nimport type {\n FieldInput,\n FormInput,\n InboxField,\n InboxForm,\n InboxRecipient,\n InboxStatus,\n InboxSubmission,\n StatusInput,\n SubmissionInput,\n SubmissionMassInput,\n SubmissionQuery,\n SubmissionsPage,\n} from './types'\n\nexport interface InboxApi {\n /** Every form, in the order of the column, with what is waiting in each. */\n forms(): Promise<InboxForm[]>\n /** One form with its fields — what the editor opens. */\n form(id: number): Promise<InboxForm>\n createForm(input: FormInput): Promise<InboxForm>\n saveForm(id: number, input: FormInput): Promise<InboxForm>\n /** Refused with a 422 when the form has submissions: it is switched off, not deleted. */\n removeForm(id: number): Promise<void>\n /** A copy, switched off, with the questions and none of the answers. */\n duplicateForm(id: number): Promise<InboxForm>\n sortForms(ids: number[]): Promise<void>\n\n fields(formId: number): Promise<InboxField[]>\n createField(formId: number, input: FieldInput): Promise<InboxField>\n saveField(id: number, input: FieldInput): Promise<InboxField>\n /** Softly: the answers already given through it keep reading. */\n removeField(id: number): Promise<void>\n sortFields(formId: number, ids: number[]): Promise<void>\n\n statuses(): Promise<InboxStatus[]>\n createStatus(input: StatusInput): Promise<InboxStatus>\n saveStatus(id: number, input: StatusInput): Promise<InboxStatus>\n /** Refused with a 422 while submissions are still in it. */\n removeStatus(id: number): Promise<void>\n sortStatuses(ids: number[]): Promise<void>\n\n /** The administrators a form can be told to write to: the ones who may read the section. */\n recipients(): Promise<InboxRecipient[]>\n\n /** One form's submissions, with the columns of the list and the counts of its tabs. */\n submissions(formId: number, query?: SubmissionQuery): Promise<SubmissionsPage>\n /**\n * One of them, open. Opening it marks it read.\n *\n * The filters travel with it so that the neighbours it reports are the ones either side of\n * it in the list somebody was actually looking at.\n */\n submission(id: number, query?: SubmissionQuery): Promise<InboxSubmission>\n /** Typed in by hand — a call that came by telephone. `fields` is by machine name. */\n createSubmission(formId: number, fields: Record<string, unknown>): Promise<InboxSubmission>\n saveSubmission(id: number, input: SubmissionInput): Promise<InboxSubmission>\n removeSubmission(id: number): Promise<void>\n /** A pile moved, marked or thrown away at once. */\n massSubmissions(input: SubmissionMassInput): Promise<{ count: number }>\n /**\n * Where the spreadsheet is. An address rather than a request: a download is the browser's\n * own job, and fetching a file into memory to hand it back to the browser is work for\n * nothing.\n */\n exportUrl(formId: number, query?: SubmissionQuery): string\n}\n\n/** Everything under `/inbox`, below the panel's API path. */\nexport function createInboxApi(admin: AdminContext): InboxApi {\n const base = `${admin.apiPath}/inbox`\n const data = <T>(body: { data: T }): T => body.data\n const nothing = (): void => undefined\n\n return {\n forms: () => admin.http.get<{ data: InboxForm[] }>(`${base}/forms`).then(data),\n form: (id) => admin.http.get<{ data: InboxForm }>(`${base}/forms/${id}`).then(data),\n createForm: (input) => admin.http.post<{ data: InboxForm }>(`${base}/forms`, input).then(data),\n saveForm: (id, input) =>\n admin.http.put<{ data: InboxForm }>(`${base}/forms/${id}`, input).then(data),\n removeForm: (id) => admin.http.delete(`${base}/forms/${id}`).then(nothing),\n duplicateForm: (id) =>\n admin.http.post<{ data: InboxForm }>(`${base}/forms/${id}/duplicate`, {}).then(data),\n sortForms: (ids) => admin.http.post(`${base}/forms/sorting`, { ids }).then(nothing),\n\n fields: (formId) =>\n admin.http.get<{ data: InboxField[] }>(`${base}/forms/${formId}/fields`).then(data),\n createField: (formId, input) =>\n admin.http.post<{ data: InboxField }>(`${base}/forms/${formId}/fields`, input).then(data),\n saveField: (id, input) =>\n admin.http.put<{ data: InboxField }>(`${base}/fields/${id}`, input).then(data),\n removeField: (id) => admin.http.delete(`${base}/fields/${id}`).then(nothing),\n sortFields: (formId, ids) =>\n admin.http.post(`${base}/forms/${formId}/fields/sorting`, { ids }).then(nothing),\n\n statuses: () => admin.http.get<{ data: InboxStatus[] }>(`${base}/statuses`).then(data),\n createStatus: (input) =>\n admin.http.post<{ data: InboxStatus }>(`${base}/statuses`, input).then(data),\n saveStatus: (id, input) =>\n admin.http.put<{ data: InboxStatus }>(`${base}/statuses/${id}`, input).then(data),\n removeStatus: (id) => admin.http.delete(`${base}/statuses/${id}`).then(nothing),\n sortStatuses: (ids) => admin.http.post(`${base}/statuses/sorting`, { ids }).then(nothing),\n\n recipients: () => admin.http.get<{ data: InboxRecipient[] }>(`${base}/recipients`).then(data),\n\n submissions: (formId, query = {}) =>\n admin.http\n .get<{\n data: SubmissionsPage['data']\n meta: Omit<SubmissionsPage, 'data' | 'columns' | 'counts' | 'placements'>\n columns: SubmissionsPage['columns']\n counts: SubmissionsPage['counts']\n placements?: SubmissionsPage['placements']\n }>(`${base}/forms/${formId}/submissions`, { query: listQuery(query) })\n .then((body) => ({\n ...body.meta,\n data: body.data,\n columns: body.columns,\n counts: body.counts,\n // Optional on the wire: a server from before placements answers without them.\n placements: body.placements ?? [],\n })),\n\n submission: (id, query = {}) =>\n admin.http\n .get<{ data: InboxSubmission }>(`${base}/submissions/${id}`, { query: listQuery(query) })\n .then(data),\n\n createSubmission: (formId, fields) =>\n admin.http\n .post<{ data: InboxSubmission }>(`${base}/forms/${formId}/submissions`, { fields })\n .then(data),\n\n saveSubmission: (id, input) =>\n admin.http.put<{ data: InboxSubmission }>(`${base}/submissions/${id}`, input).then(data),\n\n removeSubmission: (id) => admin.http.delete(`${base}/submissions/${id}`).then(nothing),\n\n massSubmissions: (input) =>\n admin.http.post<{ data: { count: number } }>(`${base}/submissions/mass`, input).then(data),\n\n exportUrl: (formId, query = {}) => {\n const search = new URLSearchParams()\n\n for (const [key, value] of Object.entries(listQuery(query))) {\n if (value !== undefined && value !== null && value !== '') {\n search.set(key, String(value))\n }\n }\n\n const suffix = search.toString()\n\n return `${base}/forms/${formId}/submissions/export${suffix === '' ? '' : `?${suffix}`}`\n },\n }\n}\n\n/**\n * The filters as query parameters, with the empty ones left out.\n *\n * `page` and `per_page` go too, because the same shape is what the export is asked for — the\n * server ignores them there, and a second almost-identical builder is a second thing to get\n * out of step.\n */\nfunction listQuery(query: SubmissionQuery): Record<string, string | number | undefined> {\n return {\n view: query.view === undefined || query.view === '' ? undefined : query.view,\n search: query.search === undefined || query.search === '' ? undefined : query.search,\n assignee: query.assignee ?? undefined,\n placement: query.placement ?? undefined,\n sort: query.sort ?? undefined,\n page: query.page,\n per_page: query.per_page,\n }\n}\n","import type { Messages } from '@webx-ui/module-admin'\n\n/**\n * What this package says, in English — the same keys `webx-ui/module-inbox` ships as\n * `lang/en/*.php`, so a key never reaches the screen while the dictionary is still on its way.\n *\n * The server's dictionary wins over these. There is no second dictionary inside this package:\n * a module translated into ten languages with an English dialog in the middle of it is worse\n * than one that is not translated at all, and the only way to notice that gap is to compare\n * the two lists — which `messages.test.ts` does.\n *\n * Placeholders are Laravel's, `:like-this`: the same line is read from a PHP file and from\n * here, and only one of the two spellings can be right.\n */\nexport const inboxMessages: Record<string, Messages> = {\n module: {\n title: 'Inbox',\n },\n\n panel: {\n forms: 'Forms',\n 'new-form': 'New form',\n 'no-forms': 'No forms yet.',\n 'no-forms-help': 'A form is a few questions and a list of who hears the answers.',\n unread: 'Unread',\n submissions: 'Submissions in all',\n off: 'Off',\n settings: 'Settings',\n duplicate: 'Duplicate',\n delete: 'Delete',\n 'delete-form-title': 'Delete “:form”?',\n 'delete-form-text': 'The form and its questions go. This cannot be undone.',\n cancel: 'Cancel',\n save: 'Save',\n saved: 'Saved.',\n deleted: 'Deleted.',\n duplicated: 'A copy was made.',\n failed: 'Some values were not accepted. Check the highlighted fields.',\n 'reorder-failed': 'The new order could not be saved.',\n 'new-form-title': 'New form',\n title: 'Title',\n slug: 'Address',\n 'slug-help': 'What the form is called on the site and where it posts.',\n 'is-enabled': 'Active',\n 'is-enabled-help': 'A form that is off is neither drawn nor accepted.',\n 'tab-general': 'General',\n 'tab-fields': 'Fields',\n 'tab-notifications': 'Notifications',\n 'tab-antispam': 'Antispam',\n 'tab-embed': 'Embedding',\n 'after-sending': 'After sending',\n 'thank-you-heading': 'Heading',\n 'thank-you-text': 'Text',\n 'submit-text': 'Text on the button',\n redirect: 'Go to this address instead',\n 'redirect-help': 'Left empty, the thank-you takes the form’s place on the page.',\n recipients: 'Who is written to',\n 'recipients-help': 'Nobody here means nobody is told. The submission is kept either way.',\n 'no-recipients': 'Nobody yet.',\n 'add-admin': 'Add an administrator',\n 'add-email': 'Add an address',\n remove: 'Remove',\n 'remove-recipient-title': 'Remove this recipient?',\n 'remove-recipient-text': 'They stop being told when something arrives.',\n 'email-field': 'The field holding the sender’s address',\n 'email-field-help': 'A reply to the notification then goes to whoever wrote in.',\n 'no-email-field': 'None',\n honeypot: 'Hidden field',\n 'honeypot-help': 'A field nobody sees and a robot fills in.',\n 'min-seconds': 'Fastest a person could send it, in seconds',\n 'min-seconds-help': 'Zero switches the check off.',\n throttle: 'Sends a minute from one address',\n 'throttle-help': 'Zero switches the limit off.',\n captcha: 'Captcha',\n 'captcha-help': 'The keys belong to the site and are set in its settings, not here.',\n 'captcha-off': 'Off',\n 'captcha-recaptcha': 'reCAPTCHA',\n 'captcha-turnstile': 'Turnstile',\n 'embed-blade': 'On a page of the site',\n 'embed-blade-help':\n 'Put the tag where the form belongs. The markup is published and rewritten by the site.',\n 'embed-block': 'In the block builder',\n 'embed-block-help':\n 'A block type prints the same tag, so an editor drops the form in without touching a template.',\n 'embed-names': 'Names of the fields',\n 'embed-names-help':\n 'A hidden field is filled in by the page: the address it was sent from, a product, a campaign.',\n copy: 'Copy',\n copied: 'Copied.',\n statuses: 'Statuses',\n 'new-status': 'New status',\n 'status-key': 'Key',\n 'status-color': 'Colour',\n 'status-default': 'Given to a new submission',\n 'status-spam': 'Spam',\n 'status-closed': 'Nothing further expected',\n 'in-use': 'In use',\n 'delete-status-title': 'Delete “:status”?',\n 'delete-status-text': 'Only a status nothing is in can go.',\n 'no-statuses': 'No statuses yet.',\n 'color-default': 'Grey',\n 'color-primary': 'Blue',\n 'color-success': 'Green',\n 'color-warning': 'Amber',\n 'color-info': 'Cyan',\n 'color-danger': 'Red',\n\n // The submissions: the list on the right of the section, and one of them opened.\n id: 'ID',\n received: 'Received',\n status: 'Status',\n assignee: 'Assignee',\n unassigned: 'Nobody',\n 'submissions-empty': 'Nothing has come in through this form yet.',\n 'search-submissions': 'Search the answers',\n 'view-all': 'All',\n 'view-unread': 'Unread',\n export: 'Export',\n 'new-submission': 'New submission',\n 'new-submission-title': 'A submission by hand',\n 'new-submission-help':\n 'For one that came by telephone or on paper. It is written the same way and lands in the same list.',\n created: 'Added.',\n submission: 'Submission :id',\n previous: 'Previous',\n next: 'Next',\n 'mark-read': 'Mark as read',\n 'mark-unread': 'Mark as unread',\n 'delete-submission-title': 'Delete this submission?',\n 'delete-submission-text': 'It goes with its attachments. This cannot be undone.',\n selected: ':count selected',\n 'move-to': 'Move to',\n 'delete-selected-title': 'Delete :count submissions?',\n answers: 'Answers',\n attachments: 'Attachments',\n details: 'Details',\n 'meta-page': 'Page',\n 'meta-placement': 'Placement',\n 'any-placement': 'Any placement',\n 'placement-none': 'Not specified',\n 'meta-referrer': 'Came from',\n 'meta-ip': 'Address',\n 'meta-agent': 'Browser',\n 'meta-locale': 'Language',\n 'meta-source': 'How it arrived',\n 'source-web': 'From the site',\n 'source-panel': 'Typed in',\n notified: 'The notification went out',\n 'not-notified': 'No notification was sent',\n 'notify-failed': 'The notification could not be sent',\n reply: 'Reply by mail',\n log: 'What has happened',\n 'event-created': 'Arrived',\n 'event-status': 'Status: :to',\n 'event-assignee': 'Given to :to',\n 'event-unassigned': 'Left to nobody',\n 'event-note': 'A note was added',\n 'event-notified': 'The notification went out',\n system: 'System',\n 'no-answers': 'Nothing was filled in.',\n download: 'Download',\n 'no-files-by-hand':\n 'A file cannot be attached by hand: the files a submission carries are what was posted with it.',\n 'submissions-none': 'Nothing here under this filter.',\n },\n\n fields: {\n field: 'Field',\n 'new-field': 'New field',\n 'edit-field': 'Field',\n 'no-fields': 'No questions yet.',\n 'no-fields-help': 'A form with no fields draws nothing on the page.',\n 'save-first': 'Save the form first, then write its questions.',\n delete: 'Delete',\n 'delete-title': 'Delete “:field”?',\n 'delete-text': 'It stops being asked. Answers already given keep it.',\n cancel: 'Cancel',\n save: 'Save',\n name: 'Name',\n 'name-help': 'What the field is called in the HTML. Left empty, it answers to f17.',\n type: 'Type',\n title: 'Label',\n placeholder: 'Placeholder',\n help: 'Hint under the field',\n 'is-enabled': 'Shown',\n 'is-required': 'Required',\n 'is-fullsize': 'Full width',\n 'in-table': 'A column in the list',\n choices: 'Choices',\n 'choice-value': 'Value',\n 'choice-label': 'Label',\n 'add-choice': 'Add a choice',\n 'no-choices': 'No choices yet. A field with none accepts nothing.',\n maxlength: 'Longest answer, in characters',\n rows: 'Height, in lines',\n pattern: 'Pattern the answer has to match',\n 'pattern-help': 'The browser’s own, written without delimiters: [0-9+ ()-]{6,}',\n earliest: 'Earliest date',\n latest: 'Latest date',\n 'min-choices': 'Fewest ticks',\n 'max-choices': 'Most ticks',\n 'consent-text': 'The sentence beside the tick',\n 'consent-text-help': 'A link is allowed here: it is printed as written.',\n 'max-size': 'Largest file, in kilobytes',\n extensions: 'Extensions allowed',\n 'extensions-help': 'Comma separated. Empty means the list the site allows.',\n multiple: 'Several files at once',\n 'type-text': 'Text',\n 'type-email': 'E-mail',\n 'type-tel': 'Telephone',\n 'type-textarea': 'Long text',\n 'type-select': 'Drop-down',\n 'type-radio': 'One of several',\n 'type-checkbox': 'Several of several',\n 'type-consent': 'Consent',\n 'type-date': 'Date',\n 'type-file': 'File',\n 'type-hidden': 'Hidden',\n },\n}\n","import { useAdmin } from '@webx-ui/module-admin'\nimport { inboxMessages } from './messages'\n\nconst seeded = new WeakSet<object>()\n\n/** Puts this package's English under the panel's dictionary, once per panel. */\nexport function useInboxMessages(): void {\n try {\n const { i18n } = useAdmin()\n\n if (!seeded.has(i18n)) {\n i18n.defaults('webx-inbox', inboxMessages)\n seeded.add(i18n)\n }\n } catch {\n // Outside a panel there is no dictionary to seed, and `useTranslate` falls back on its own.\n }\n}\n","import type { LocalizedValue } from '@webx-ui/core'\n\n/** The kinds of question a form can ask (§4). Mirrors `WebxUi\\Inbox\\Fields\\FieldType`. */\nexport const FIELD_TYPES = [\n 'text',\n 'email',\n 'tel',\n 'textarea',\n 'select',\n 'radio',\n 'checkbox',\n 'consent',\n 'date',\n 'file',\n 'hidden',\n] as const\n\nexport type FieldType = (typeof FIELD_TYPES)[number]\n\n/** Tones of `WxBadge`, which is what a status is coloured with — never a hex value. */\nexport const STATUS_COLORS = ['default', 'primary', 'success', 'warning', 'info', 'danger'] as const\n\nexport type StatusColor = (typeof STATUS_COLORS)[number]\n\n/** One written-down answer of a `select`, `radio` or `checkbox`. */\nexport interface FieldChoice {\n value: string\n label: LocalizedValue | string\n}\n\n/**\n * What a field may be configured with. Which keys mean anything depends on the type (§4), and\n * the server keeps only the ones that do.\n */\nexport interface FieldOptions {\n maxlength?: number\n rows?: number\n pattern?: string\n min?: number | string\n max?: number | string\n choices?: FieldChoice[]\n text?: LocalizedValue | string\n max_size?: number\n extensions?: string[]\n multiple?: boolean\n [key: string]: unknown\n}\n\nexport interface InboxField {\n id: number\n form_id: number\n /** What somebody typed, or null. */\n name: string | null\n /** What the HTML will actually say — `f17` for a field nobody named. */\n key: string\n type: FieldType\n title: LocalizedValue\n placeholder: LocalizedValue\n help: LocalizedValue\n options: FieldOptions\n is_enabled: boolean\n is_required: boolean\n is_fullsize: boolean\n in_table: boolean\n position: number\n /* A table row, so the index signature `WxTable` asks of what it draws. */\n [key: string]: unknown\n}\n\n/** A field as the dialog saves it. */\nexport interface FieldInput {\n name: string | null\n type: FieldType\n title: LocalizedValue\n placeholder?: LocalizedValue\n help?: LocalizedValue\n options?: FieldOptions\n is_enabled: boolean\n is_required: boolean\n is_fullsize: boolean\n in_table: boolean\n}\n\n/** Who a notification goes to: somebody with an account, or an address typed in. */\nexport type Recipient = { admin_id: number } | { email: string }\n\n/** The settings of a form (§5). Every key is literal, dots included. */\nexport interface FormOptions {\n 'thank-you.heading'?: LocalizedValue\n 'thank-you.text'?: LocalizedValue\n 'design.submit-text'?: LocalizedValue\n redirect?: string\n recipients?: Recipient[]\n email_field?: string\n 'antispam.honeypot'?: boolean\n 'antispam.min_seconds'?: number\n 'antispam.throttle'?: number\n 'antispam.captcha'?: 'off' | 'recaptcha' | 'turnstile'\n [key: string]: unknown\n}\n\nexport interface InboxForm {\n id: number\n slug: string\n title: LocalizedValue\n is_enabled: boolean\n options: FormOptions\n position: number\n /** Only where the query counted them — null on a form loaded on its own. */\n submissions_count: number | null\n /** Unread and not spam. */\n unread_count: number | null\n /** Only on a form asked for by id, or one just written. */\n fields?: InboxField[]\n created_at: string | null\n updated_at: string | null\n}\n\n/** A form as its editor saves it. */\nexport interface FormInput {\n slug: string\n title: LocalizedValue\n is_enabled: boolean\n options: FormOptions\n}\n\nexport interface InboxStatus {\n id: number\n key: string\n title: LocalizedValue\n color: StatusColor\n is_default: boolean\n is_spam: boolean\n is_closed: boolean\n position: number\n submissions_count: number | null\n}\n\nexport interface StatusInput {\n key: string\n title: LocalizedValue\n color: StatusColor\n is_default: boolean\n is_spam: boolean\n is_closed: boolean\n}\n\n/** Somebody with an account who may read the section, for the recipients list. */\nexport interface InboxRecipient {\n id: number\n name: string\n email: string\n}\n\n/** An administrator as a name beside something else — an assignee, the author of a log line. */\nexport interface InboxAdmin {\n id: number\n name: string\n email: string\n}\n\n/** One column of the list: a field of the form that was marked `in_table`. */\nexport interface SubmissionColumn {\n key: string\n label: string\n type: FieldType\n}\n\n/** What each tab above the list would hold, under the filters that are on. */\nexport interface SubmissionCounts {\n all: number\n unread: number\n /** By the status's key, spam included — its own tab has to say how much is in it. */\n statuses: Record<string, number>\n}\n\n/** A page as Laravel's `->paginate()` serialises it, which is what `WxTable` reads. */\nexport interface InboxPage<T> {\n data: T[]\n current_page: number\n last_page: number\n per_page: number\n total: number\n from: number | null\n to: number | null\n}\n\n/** One line of the list. The answers are keyed by the field's machine name. */\nexport interface SubmissionRow {\n id: number\n values: Record<string, string | null>\n status: InboxStatus | null\n assignee: InboxAdmin | null\n is_read: boolean\n source: string\n /** Where on the site the form stood (`footer`, `article`), or null when the page did not say. */\n placement: string | null\n files_count: number\n created_at: string | null\n /* A table row, so the index signature `WxTable` asks of what it draws. */\n [key: string]: unknown\n}\n\n/**\n * The list, and the two things that travel with it: what its columns are, and what each tab\n * above it would hold.\n */\nexport interface SubmissionsPage extends InboxPage<SubmissionRow> {\n columns: SubmissionColumn[]\n counts: SubmissionCounts\n /**\n * Every place on the site the form has been sent from, `null` for the page that did not say —\n * over the whole form rather than the filter, so the placement filter can always be undone.\n * More than one is what makes that filter worth showing.\n */\n placements: (string | null)[]\n}\n\n/** One answer, with the question as it was asked at the time (§2.2). */\nexport interface SubmissionValue {\n id: number\n field_id: number | null\n name: string\n label: string | null\n type: string\n value: string | null\n payload: unknown\n}\n\nexport interface SubmissionAttachment {\n id: number\n field_id: number | null\n name: string\n size: number\n mime: string | null\n /** Through the panel, behind the same permission as the submission (§8). */\n url: string\n}\n\n/** One line of what has happened to a submission. Never edited, never deleted. */\nexport interface SubmissionEvent {\n id: number\n type: 'created' | 'status' | 'assignee' | 'note' | 'notified' | string\n from: string | null\n to: string | null\n /** Null is the system — the submission arriving, the notification going out. */\n author: { id: number; name: string | null } | null\n created_at: string | null\n}\n\n/** What the intake saw around the submission: the page, the language, the campaign. */\nexport interface SubmissionMeta {\n ip?: string\n user_agent?: string\n page?: string\n referrer?: string\n utm?: Record<string, string>\n locale?: string\n [key: string]: unknown\n}\n\nexport interface InboxSubmission {\n id: number\n form: { id: number; slug: string | null; title: LocalizedValue | null }\n status: InboxStatus | null\n assignee: InboxAdmin | null\n values: SubmissionValue[]\n files: SubmissionAttachment[]\n meta: SubmissionMeta\n events: SubmissionEvent[]\n is_read: boolean\n source: string\n /** Where on the site the form stood (`footer`, `article`), or null when the page did not say. */\n placement: string | null\n notified_at: string | null\n notify_error: string | null\n /** The neighbours in the list this was opened from, so the arrows walk the same pile. */\n previous_id: number | null\n next_id: number | null\n created_at: string | null\n updated_at: string | null\n}\n\n/** Everything the list asks the server for. The tab is `view`, the rest are filters. */\nexport interface SubmissionQuery {\n view?: string\n search?: string\n /** An administrator's id, or `none` — the pile nobody has picked up. */\n assignee?: string | null\n /** A placement, or `none` — the submissions whose page did not say. */\n placement?: string | null\n sort?: string | null\n page?: number\n per_page?: number\n}\n\n/** A submission changed by hand: the status, the assignee, a typo in an answer. */\nexport interface SubmissionInput {\n status_id?: number\n assignee_id?: number | null\n /** Machine name → the corrected text. The snapshot beside it is never rewritten. */\n values?: Record<string, string | null>\n}\n\n/** A pile dealt with at once. */\nexport interface SubmissionMassInput {\n ids: number[]\n action: 'status' | 'read' | 'unread' | 'delete'\n status_id?: number\n}\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n toast,\n useModal,\n WxAction,\n WxButton,\n WxIcon,\n WxCheckbox,\n WxDialog,\n WxFormItem,\n WxInput,\n WxInputNumber,\n WxSelect,\n WxSpace,\n WxDatePicker,\n WxTagsInput,\n WxText,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport LocalizedRichText from './LocalizedRichText.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport { FIELD_TYPES, type FieldChoice, type FieldOptions, type FieldType } from './types'\nimport type { InboxField, InboxForm } from './types'\n\n/**\n * One question, written.\n *\n * The settings shown are the ones the chosen type has and no others (§4): a `select` has\n * choices, a `textarea` has a height, a `file` has a size and a list of extensions. Changing\n * the type changes what is asked for, and the server keeps only what belongs — a leftover\n * `choices` array on a text field would be a column of empty strings in an export a year from\n * now.\n */\nconst props = defineProps<{ field: InboxField | null; form: InboxForm }>()\n\nconst { resolve, dismiss, open } = useModal<InboxField>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nconst name = ref('')\nconst type = ref<FieldType>('text')\nconst title = ref<LocalizedValue>({})\nconst placeholder = ref<LocalizedValue>({})\nconst help = ref<LocalizedValue>({})\nconst options = ref<FieldOptions>({})\nconst isEnabled = ref(true)\nconst isRequired = ref(false)\nconst isFullsize = ref(true)\nconst inTable = ref(false)\n\nwatch(\n () => props.field,\n (field) => {\n name.value = field?.name ?? ''\n type.value = field?.type ?? 'text'\n title.value = { ...(field?.title ?? {}) }\n placeholder.value = { ...(field?.placeholder ?? {}) }\n help.value = { ...(field?.help ?? {}) }\n options.value = { ...(field?.options ?? {}) }\n isEnabled.value = field?.is_enabled ?? true\n isRequired.value = field?.is_required ?? false\n isFullsize.value = field?.is_fullsize ?? true\n inTable.value = field?.in_table ?? false\n errors.value = {}\n },\n { immediate: true },\n)\n\nconst types = computed(() =>\n FIELD_TYPES.map((one) => ({ value: one, label: t(`fields.type-${one}`) })),\n)\n\nconst hasChoices = computed(() => ['select', 'radio', 'checkbox'].includes(type.value))\n\nconst choices = computed<FieldChoice[]>(() =>\n Array.isArray(options.value.choices) ? options.value.choices : [],\n)\n\n/** Extensions are typed as a list of words, which is what they are — not a sentence. */\nconst extensions = computed({\n get: () => (Array.isArray(options.value.extensions) ? options.value.extensions : []),\n set: (value: string[]) =>\n set(\n 'extensions',\n value.map((one) => one.replace(/^\\./, '')),\n ),\n})\n\nfunction set(key: string, value: unknown): void {\n options.value = { ...options.value, [key]: value }\n}\n\nfunction addChoice(): void {\n set('choices', [...choices.value, { value: '', label: {} }])\n}\n\nfunction removeChoice(index: number): void {\n set(\n 'choices',\n choices.value.filter((_, at) => at !== index),\n )\n}\n\nfunction setChoice(index: number, patch: Partial<FieldChoice>): void {\n set(\n 'choices',\n choices.value.map((choice, at) => (at === index ? { ...choice, ...patch } : choice)),\n )\n}\n\nfunction errorOf(field: string): string | undefined {\n return errors.value[field]?.[0]\n}\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n const input = {\n name: name.value.trim() === '' ? null : name.value.trim(),\n type: type.value,\n title: title.value,\n placeholder: placeholder.value,\n help: help.value,\n options: options.value,\n is_enabled: isEnabled.value,\n is_required: isRequired.value,\n is_fullsize: isFullsize.value,\n in_table: inTable.value,\n }\n\n try {\n resolve(\n props.field === null\n ? await api.createField(props.form.id, input)\n : await api.saveField(props.field.id, input),\n )\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog\n v-model:open=\"open\"\n :title=\"field ? t('fields.edit-field') : t('fields.new-field')\"\n :width=\"720\"\n >\n <div class=\"wx-inbox-field-form\">\n <div class=\"wx-inbox-field-form__row\">\n <wx-form-item :label=\"t('fields.type')\">\n <wx-select v-model=\"type\" :options=\"types\" />\n </wx-form-item>\n\n <wx-form-item\n :label=\"t('fields.name')\"\n :help=\"t('fields.name-help')\"\n :error=\"errorOf('name')\"\n >\n <wx-input v-model=\"name\" placeholder=\"email\" />\n </wx-form-item>\n </div>\n\n <wx-form-item :label=\"t('fields.title')\" :error=\"errorOf('title')\" required>\n <wx-input v-model=\"title\" localized />\n </wx-form-item>\n\n <!-- A hidden field has neither: nobody reads a placeholder they cannot see. -->\n <template v-if=\"type !== 'hidden'\">\n <wx-form-item v-if=\"type !== 'consent'\" :label=\"t('fields.placeholder')\">\n <wx-input v-model=\"placeholder\" localized />\n </wx-form-item>\n\n <wx-form-item :label=\"t('fields.help')\">\n <wx-input v-model=\"help\" localized />\n </wx-form-item>\n </template>\n\n <!-- The sentence beside the tick, which is printed raw on the site: it is a sentence\n with a link in it, not a caption. -->\n <wx-form-item\n v-if=\"type === 'consent'\"\n :label=\"t('fields.consent-text')\"\n :help=\"t('fields.consent-text-help')\"\n >\n <localized-rich-text\n :model-value=\"(options.text as LocalizedValue) ?? {}\"\n min-height=\"100px\"\n @update:model-value=\"(value) => set('text', value)\"\n />\n </wx-form-item>\n\n <div v-if=\"hasChoices\" class=\"wx-inbox-choices\">\n <wx-text size=\"sm\" weight=\"medium\">{{ t('fields.choices') }}</wx-text>\n\n <wx-text v-if=\"choices.length === 0\" size=\"sm\" tone=\"placeholder\">\n {{ t('fields.no-choices') }}\n </wx-text>\n\n <div v-for=\"(choice, index) in choices\" :key=\"index\" class=\"wx-inbox-choices__row\">\n <wx-input\n :model-value=\"choice.value\"\n :placeholder=\"t('fields.choice-value')\"\n @update:model-value=\"(value) => setChoice(index, { value: String(value) })\"\n />\n <wx-input\n :model-value=\"choice.label\"\n localized\n :placeholder=\"t('fields.choice-label')\"\n @update:model-value=\"(label) => setChoice(index, { label: label as LocalizedValue })\"\n />\n <wx-action icon=\"trash\" :title=\"t('fields.delete')\" @click=\"removeChoice(index)\" />\n </div>\n\n <wx-button variant=\"outline\" size=\"sm\" @click=\"addChoice\">\n <template #icon><wx-icon name=\"plus\" /></template>\n {{ t('fields.add-choice') }}\n </wx-button>\n </div>\n\n <div class=\"wx-inbox-field-form__row\">\n <wx-form-item v-if=\"type === 'textarea'\" :label=\"t('fields.rows')\">\n <wx-input-number\n :model-value=\"(options.rows as number) ?? 5\"\n :min=\"2\"\n :max=\"30\"\n @update:model-value=\"(value) => set('rows', value)\"\n />\n </wx-form-item>\n\n <wx-form-item\n v-if=\"['text', 'email', 'textarea'].includes(type)\"\n :label=\"t('fields.maxlength')\"\n >\n <wx-input-number\n :model-value=\"(options.maxlength as number) ?? null\"\n :min=\"1\"\n :max=\"20000\"\n @update:model-value=\"(value) => set('maxlength', value)\"\n />\n </wx-form-item>\n\n <wx-form-item\n v-if=\"type === 'tel'\"\n :label=\"t('fields.pattern')\"\n :help=\"t('fields.pattern-help')\"\n >\n <wx-input\n :model-value=\"(options.pattern as string) ?? ''\"\n @update:model-value=\"(value) => set('pattern', value)\"\n />\n </wx-form-item>\n\n <template v-if=\"type === 'date'\">\n <wx-form-item :label=\"t('fields.earliest')\">\n <wx-date-picker\n clearable\n :model-value=\"(options.min as string) ?? null\"\n @update:model-value=\"(value) => set('min', value)\"\n />\n </wx-form-item>\n <wx-form-item :label=\"t('fields.latest')\">\n <wx-date-picker\n clearable\n :model-value=\"(options.max as string) ?? null\"\n @update:model-value=\"(value) => set('max', value)\"\n />\n </wx-form-item>\n </template>\n\n <template v-if=\"type === 'checkbox'\">\n <wx-form-item :label=\"t('fields.min-choices')\">\n <wx-input-number\n :model-value=\"(options.min as number) ?? null\"\n :min=\"0\"\n @update:model-value=\"(value) => set('min', value)\"\n />\n </wx-form-item>\n <wx-form-item :label=\"t('fields.max-choices')\">\n <wx-input-number\n :model-value=\"(options.max as number) ?? null\"\n :min=\"0\"\n @update:model-value=\"(value) => set('max', value)\"\n />\n </wx-form-item>\n </template>\n\n <wx-form-item v-if=\"type === 'file'\" :label=\"t('fields.max-size')\">\n <wx-input-number\n :model-value=\"(options.max_size as number) ?? null\"\n :min=\"1\"\n @update:model-value=\"(value) => set('max_size', value)\"\n />\n </wx-form-item>\n </div>\n\n <template v-if=\"type === 'file'\">\n <wx-form-item :label=\"t('fields.extensions')\" :help=\"t('fields.extensions-help')\">\n <wx-tags-input v-model=\"extensions\" />\n </wx-form-item>\n\n <wx-checkbox\n :model-value=\"Boolean(options.multiple)\"\n :label=\"t('fields.multiple')\"\n @update:model-value=\"(value) => set('multiple', value)\"\n />\n </template>\n\n <div class=\"wx-inbox-field-form__checks\">\n <wx-checkbox v-model=\"isEnabled\" :label=\"t('fields.is-enabled')\" />\n <wx-checkbox v-model=\"isRequired\" :label=\"t('fields.is-required')\" />\n <wx-checkbox\n v-if=\"type !== 'hidden'\"\n v-model=\"isFullsize\"\n :label=\"t('fields.is-fullsize')\"\n />\n <wx-checkbox v-model=\"inTable\" :label=\"t('fields.in-table')\" />\n </div>\n </div>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('fields.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">{{ t('fields.save') }}</wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-inbox-field-form {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n\n.wx-inbox-field-form__row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-12);\n}\n\n.wx-inbox-field-form__row > * {\n flex: 1 1 200px;\n min-width: 0;\n}\n\n/* Empty when the type has nothing to configure, and then it should take no room at all. */\n.wx-inbox-field-form__row:empty {\n display: none;\n}\n\n.wx-inbox-field-form__checks {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-16);\n}\n\n.wx-inbox-choices {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-8);\n align-items: flex-start;\n}\n\n.wx-inbox-choices__row {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n width: 100%;\n}\n\n.wx-inbox-choices__row > :first-child {\n flex: 0 1 180px;\n min-width: 0;\n}\n\n.wx-inbox-choices__row > :nth-child(2) {\n flex: 1 1 auto;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxRowMenu,\n type RowAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n localizedValue,\n toast,\n useLocales,\n WxBadge,\n WxButton,\n WxIcon,\n WxCard,\n WxEmpty,\n WxSortableList,\n WxText,\n} from '@webx-ui/core'\nimport FieldDialog from './FieldDialog.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxField, InboxForm } from './types'\n\n/**\n * The questions the form asks, in the order it asks them.\n *\n * A list with a grip rather than a table, because the order is the thing being edited here\n * and a table cannot be dragged. Each question is saved on its own, in its own dialog: a\n * field is a row with an identity that answers point at (§2.1), not a value of the form.\n */\nconst props = defineProps<{ form: InboxForm; canManage: boolean }>()\n\nconst fields = defineModel<InboxField[]>({ required: true })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst edit = createModal<InboxField, { field: InboxField | null; form: InboxForm }>(FieldDialog)\n\nfunction name(field: InboxField): string {\n return localizedValue(field.title, locales.active.value, field.key)\n}\n\n/** What the row says about itself, under its name: the type, then what is true of it. */\nfunction marks(field: InboxField): string[] {\n return [\n t(`fields.type-${field.type}`),\n ...(field.is_required ? [t('fields.is-required')] : []),\n ...(field.in_table ? [t('fields.in-table')] : []),\n ...(field.is_fullsize ? [] : [t('fields.is-fullsize')]),\n ]\n}\n\nconst empty = computed(() => fields.value.length === 0)\n\nasync function open(field: InboxField | null): Promise<void> {\n const saved = await edit({ field, form: props.form })\n\n if (!saved) return\n\n fields.value =\n field === null\n ? [...fields.value, saved]\n : fields.value.map((one) => (one.id === saved.id ? saved : one))\n}\n\nasync function remove(field: InboxField): Promise<void> {\n const agreed = await confirm({\n title: t('fields.delete-title', { field: name(field) }),\n message: t('fields.delete-text'),\n confirmText: t('fields.delete'),\n cancelText: t('fields.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeField(field.id)\n fields.value = fields.value.filter((one) => one.id !== field.id)\n toast.success(t('panel.deleted'))\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nfunction actionsFor(field: InboxField): RowAction[] {\n if (!props.canManage) return []\n\n return [\n { key: 'edit', icon: 'edit', label: t('fields.edit-field'), run: () => void open(field) },\n {\n key: 'delete',\n icon: 'trash',\n label: t('fields.delete'),\n danger: true,\n run: () => void remove(field),\n },\n ]\n}\n\n/** The whole order, every time — the list is already in it on screen. */\nasync function reorder(): Promise<void> {\n try {\n await api.sortFields(\n props.form.id,\n fields.value.map((field) => field.id),\n )\n } catch (error) {\n toast.danger(message(error, t('panel.reorder-failed')))\n }\n}\n</script>\n\n<template>\n <wx-card :title=\"t('panel.tab-fields')\">\n <template v-if=\"canManage\" #extra>\n <wx-button type=\"primary\" size=\"sm\" @click=\"open(null)\">\n <template #icon><wx-icon name=\"plus\" /></template>\n {{ t('fields.new-field') }}\n </wx-button>\n </template>\n\n <wx-empty\n v-if=\"empty\"\n :title=\"t('fields.no-fields')\"\n :description=\"t('fields.no-fields-help')\"\n />\n\n <wx-sortable-list\n v-else\n v-model=\"fields\"\n plain\n item-key=\"id\"\n :item-label=\"name\"\n :disabled=\"!canManage\"\n :aria-label=\"t('panel.tab-fields')\"\n @move=\"reorder\"\n >\n <template #default=\"{ item }\">\n <div class=\"wx-inbox-field\">\n <div class=\"wx-inbox-field__name\">\n <wx-text weight=\"medium\" truncate>{{ name(item) }}</wx-text>\n <wx-badge v-if=\"!item.is_enabled\" type=\"default\">{{ t('panel.off') }}</wx-badge>\n </div>\n <wx-text size=\"sm\" tone=\"muted\" truncate>\n <code>fields[{{ item.key }}]</code> · {{ marks(item).join(' · ') }}\n </wx-text>\n </div>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-row-menu :actions=\"actionsFor(item)\" :label=\"name(item)\" />\n </template>\n </wx-sortable-list>\n </wx-card>\n</template>\n\n<style scoped>\n.wx-inbox-field {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-2);\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.wx-inbox-field__name {\n display: flex;\n align-items: center;\n gap: var(--wx-space-6);\n min-width: 0;\n}\n</style>\n","import { computed, type Ref, type WritableComputedRef } from 'vue'\nimport type { FormOptions } from './types'\n\n/**\n * One setting of a form, as something a control can be bound to.\n *\n * The keys are literal and several of them have dots in them — `thank-you.heading` is one key\n * (§5) — so nothing here splits on a dot, and a whole new object is written on every change\n * rather than a property being set in place: the editor holds the options as one value, and a\n * mutation underneath it is a change nothing is told about.\n *\n * An empty value is not written as an empty value: it is taken out. The server does the same\n * when it saves, and a form whose settings are twelve blank strings reads as configured when\n * it is not.\n */\nexport function option<T>(\n options: Ref<FormOptions>,\n key: string,\n fallback: T,\n): WritableComputedRef<T> {\n return computed({\n get: () => (options.value[key] ?? fallback) as T,\n set: (value: T) => {\n const next = { ...options.value }\n\n if (value === '' || value === null || value === undefined) {\n delete next[key]\n } else {\n next[key] = value\n }\n\n options.value = next\n },\n })\n}\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { WxCard, WxFormItem, WxInputNumber, WxSelect, WxSwitch } from '@webx-ui/core'\nimport { option } from './options'\nimport type { FormOptions } from './types'\n\n/**\n * The four layers in front of the door (§7), as the three anybody would want to change.\n *\n * The origin check is not here: it is not a dial, it is a fact about where the site is served\n * from, and it lives in the configuration with the rest of the deployment. The captcha keys\n * are not here either — they are the site's, one pair for every form, and a secret repeated\n * in each form's settings is a secret scattered over rows (§5).\n */\nconst options = defineModel<FormOptions>({ required: true })\n\nconst t = useTranslate('webx-inbox')\n\nconst honeypot = option<boolean>(options, 'antispam.honeypot', true)\nconst seconds = option<number>(options, 'antispam.min_seconds', 3)\nconst throttle = option<number>(options, 'antispam.throttle', 5)\nconst captcha = option<string>(options, 'antispam.captcha', 'off')\n\nconst captchas = computed(() => [\n { value: 'off', label: t('panel.captcha-off') },\n { value: 'recaptcha', label: t('panel.captcha-recaptcha') },\n { value: 'turnstile', label: t('panel.captcha-turnstile') },\n])\n</script>\n\n<template>\n <wx-card>\n <wx-form-item :label=\"t('panel.honeypot')\" :help=\"t('panel.honeypot-help')\">\n <wx-switch v-model=\"honeypot\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.min-seconds')\" :help=\"t('panel.min-seconds-help')\">\n <wx-input-number v-model=\"seconds\" :min=\"0\" :max=\"120\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.throttle')\" :help=\"t('panel.throttle-help')\">\n <wx-input-number v-model=\"throttle\" :min=\"0\" :max=\"120\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.captcha')\" :help=\"t('panel.captcha-help')\">\n <wx-select v-model=\"captcha\" :options=\"captchas\" />\n </wx-form-item>\n </wx-card>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { toast, WxAction, WxCard, WxTable, WxText, type TableColumn } from '@webx-ui/core'\nimport { useInboxMessages } from './i18n'\nimport type { InboxField, InboxForm } from './types'\n\n/**\n * How the form gets onto a page.\n *\n * Two answers and both are one line, because the module's whole public half is one tag (§10):\n * a template prints it, and a block type prints the same thing so that an editor never opens\n * a template at all.\n *\n * Under them, the names. A hidden field is filled in by the page it stands on — the address\n * somebody wrote from, the product they were looking at, the campaign that brought them — and\n * the only way to fill one in is to know what it is called (§2.6).\n */\nconst props = defineProps<{ form: InboxForm; slug: string; fields: InboxField[] }>()\n\nuseInboxMessages()\nconst t = useTranslate('webx-inbox')\n\nconst blade = computed(() => `<x-webx-inbox::form slug=\"${props.slug}\" />`)\n\nconst block = computed(\n () =>\n `{{-- resources/views/blocks/contact.blade.php --}}\\n<x-webx-inbox::form slug=\"${props.slug}\" />`,\n)\n\nconst columns = computed<TableColumn<InboxField>[]>(() => [\n { key: 'key', label: t('fields.name') },\n { key: 'title', label: t('fields.title') },\n { key: 'type', label: t('fields.type'), hideBelow: 520 },\n])\n\n/** Only the ones a page can actually fill in or a visitor can actually answer. */\nconst listed = computed(() => props.fields.filter((field) => field.is_enabled))\n\nasync function copy(text: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text)\n toast.success(t('panel.copied'))\n } catch {\n // A browser that refuses the clipboard — an insecure origin, a denied permission — still\n // shows the line, and selecting it by hand is what anybody does next anyway.\n }\n}\n</script>\n\n<template>\n <div class=\"wx-inbox-embed\">\n <wx-card :title=\"t('panel.embed-blade')\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.embed-blade-help') }}</wx-text>\n\n <div class=\"wx-inbox-embed__snippet\">\n <code>{{ blade }}</code>\n <wx-action icon=\"copy\" :title=\"t('panel.copy')\" @click=\"copy(blade)\" />\n </div>\n </wx-card>\n\n <wx-card :title=\"t('panel.embed-block')\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.embed-block-help') }}</wx-text>\n\n <div class=\"wx-inbox-embed__snippet\">\n <code>{{ block }}</code>\n <wx-action icon=\"copy\" :title=\"t('panel.copy')\" @click=\"copy(block)\" />\n </div>\n </wx-card>\n\n <wx-card :title=\"t('panel.embed-names')\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.embed-names-help') }}</wx-text>\n\n <wx-table\n :data=\"listed\"\n :columns=\"columns\"\n row-key=\"id\"\n flush\n :empty-text=\"t('fields.no-fields')\"\n >\n <template #cell-key=\"{ row }\">\n <wx-text mono size=\"sm\">fields[{{ row.key }}]</wx-text>\n </template>\n\n <template #cell-title=\"{ row }\">\n {{ Object.values(row.title)[0] ?? row.key }}\n </template>\n\n <template #cell-type=\"{ row }\">\n {{ t(`fields.type-${row.type}`) }}\n </template>\n </wx-table>\n </wx-card>\n </div>\n</template>\n\n<style scoped>\n.wx-inbox-embed {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-16);\n}\n\n.wx-inbox-embed__snippet {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n margin-top: var(--wx-space-12);\n padding: var(--wx-space-10) var(--wx-space-12);\n border: 1px solid var(--wx-border-default);\n border-radius: var(--wx-radius-md);\n background: var(--wx-bg-subtle);\n}\n\n.wx-inbox-embed__snippet code {\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n white-space: pre;\n font-family: var(--wx-font-family-mono);\n font-size: var(--wx-font-size-sm);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { WxCard, WxFormItem, WxInput, WxSwitch, type LocalizedValue } from '@webx-ui/core'\nimport LocalizedRichText from './LocalizedRichText.vue'\nimport { option } from './options'\nimport type { FormOptions } from './types'\n\n/**\n * What the form is, and what it says once it has been sent.\n *\n * The two halves are on two cards because they are read at two different times: the first is\n * set up once, the second is the sentence a visitor sees and is rewritten whenever the\n * marketing does.\n */\ndefineProps<{ errors: Record<string, string[]> }>()\n\nconst settings = defineModel<{ slug: string; title: LocalizedValue; is_enabled: boolean }>(\n 'settings',\n { required: true },\n)\n\nconst options = defineModel<FormOptions>('options', { required: true })\n\nconst t = useTranslate('webx-inbox')\n\nconst heading = option<LocalizedValue>(options, 'thank-you.heading', {})\nconst text = option<LocalizedValue>(options, 'thank-you.text', {})\nconst submit = option<LocalizedValue>(options, 'design.submit-text', {})\nconst redirect = option<string>(options, 'redirect', '')\n</script>\n\n<template>\n <div class=\"wx-inbox-general\">\n <wx-card>\n <wx-form-item :label=\"t('panel.title')\" :error=\"errors.title?.[0]\" required>\n <wx-input v-model=\"settings.title\" localized />\n </wx-form-item>\n\n <wx-form-item\n :label=\"t('panel.slug')\"\n :help=\"t('panel.slug-help')\"\n :error=\"errors.slug?.[0]\"\n required\n >\n <wx-input v-model=\"settings.slug\" placeholder=\"contact\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.is-enabled')\" :help=\"t('panel.is-enabled-help')\">\n <wx-switch v-model=\"settings.is_enabled\" />\n </wx-form-item>\n </wx-card>\n\n <wx-card :title=\"t('panel.after-sending')\">\n <wx-form-item :label=\"t('panel.submit-text')\">\n <wx-input v-model=\"submit\" localized />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.thank-you-heading')\">\n <wx-input v-model=\"heading\" localized />\n </wx-form-item>\n\n <!-- Printed raw on the site, which is why it is written where formatting is possible. -->\n <wx-form-item :label=\"t('panel.thank-you-text')\">\n <localized-rich-text v-model=\"text\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.redirect')\" :help=\"t('panel.redirect-help')\">\n <wx-input v-model=\"redirect\" placeholder=\"/thank-you\" />\n </wx-form-item>\n </wx-card>\n </div>\n</template>\n\n<style scoped>\n.wx-inbox-general {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-16);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport { useAdmin, useTranslate } from '@webx-ui/module-admin'\nimport {\n confirm,\n WxAction,\n WxAlert,\n WxButton,\n WxIcon,\n WxCard,\n WxFormItem,\n WxInput,\n WxSelect,\n WxSpace,\n WxText,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { option } from './options'\nimport type { FormOptions, InboxField, InboxRecipient, Recipient } from './types'\n\n/**\n * Who hears that something arrived (§9).\n *\n * Two kinds of recipient and they are not interchangeable. An administrator is written to at\n * the address on their account and in the language they keep the panel in, so changing either\n * changes it everywhere; a typed address is written to in the language the submission came in.\n * The list offered is not every administrator but the ones who may open a submission — a\n * notification is a link, and sending one to somebody who gets a 403 looks like the panel is\n * broken rather than like the form is.\n */\nconst props = defineProps<{ fields: InboxField[]; errors: Record<string, string[]> }>()\n\nconst options = defineModel<FormOptions>({ required: true })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst t = useTranslate('webx-inbox')\n\nconst admins = ref<InboxRecipient[]>([])\n\nconst recipients = option<Recipient[]>(options, 'recipients', [])\nconst emailField = option<string>(options, 'email_field', '')\n\nonMounted(async () => {\n try {\n admins.value = await api.recipients()\n } catch {\n // Only the shortcut is gone: an address can still be typed, and that is the half of this\n // that has to work.\n }\n})\n\nconst adminOptions = computed(() =>\n admins.value.map((admin) => ({ value: admin.id, label: `${admin.name} · ${admin.email}` })),\n)\n\n/** The fields that could hold the sender's address, plus the option of naming none. */\nconst emailOptions = computed(() => [\n { value: '', label: t('panel.no-email-field') },\n ...props.fields\n .filter((field) => field.type === 'email')\n .map((field) => ({ value: field.key, label: field.key })),\n])\n\nfunction isAdmin(recipient: Recipient): recipient is { admin_id: number } {\n return 'admin_id' in recipient\n}\n\nfunction add(recipient: Recipient): void {\n recipients.value = [...recipients.value, recipient]\n}\n\n/**\n * A recipient goes behind a question, unless there is nothing there to lose.\n *\n * The row that was just added and never filled in is a blank line, and asking about a blank\n * line teaches the reader to click through the question without reading it — which is the\n * one thing a confirmation must not do.\n */\nasync function remove(index: number): Promise<void> {\n const recipient = recipients.value[index]\n const written =\n recipient !== undefined && (isAdmin(recipient) || (recipient.email ?? '').trim() !== '')\n\n if (written) {\n const agreed = await confirm({\n title: t('panel.remove-recipient-title'),\n message: t('panel.remove-recipient-text'),\n confirmText: t('panel.remove'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n }\n\n recipients.value = recipients.value.filter((_, at) => at !== index)\n}\n\nfunction setAdmin(index: number, id: number): void {\n recipients.value = recipients.value.map((one, at) => (at === index ? { admin_id: id } : one))\n}\n\nfunction setEmail(index: number, email: string): void {\n recipients.value = recipients.value.map((one, at) => (at === index ? { email } : one))\n}\n</script>\n\n<template>\n <wx-card :title=\"t('panel.recipients')\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.recipients-help') }}</wx-text>\n\n <wx-alert\n v-if=\"errors['options.recipients']\"\n type=\"danger\"\n variant=\"soft\"\n :description=\"errors['options.recipients']?.[0]\"\n />\n\n <div class=\"wx-inbox-recipients\">\n <wx-text v-if=\"recipients.length === 0\" size=\"sm\" tone=\"placeholder\">\n {{ t('panel.no-recipients') }}\n </wx-text>\n\n <div v-for=\"(recipient, index) in recipients\" :key=\"index\" class=\"wx-inbox-recipients__row\">\n <wx-select\n v-if=\"isAdmin(recipient)\"\n :model-value=\"recipient.admin_id\"\n :options=\"adminOptions\"\n @update:model-value=\"(id) => setAdmin(index, Number(id))\"\n />\n <wx-input\n v-else\n :model-value=\"recipient.email\"\n type=\"email\"\n placeholder=\"sales@example.com\"\n @update:model-value=\"(email) => setEmail(index, String(email))\"\n />\n\n <!-- Red, like every other way of taking something away in the panel: the colour is\n what tells the two buttons of a row apart before either is read. -->\n <wx-action icon=\"trash\" tone=\"danger\" :title=\"t('panel.remove')\" @click=\"remove(index)\" />\n </div>\n </div>\n\n <wx-space size=\"sm\">\n <wx-button\n variant=\"outline\"\n icon=\"user\"\n :disabled=\"adminOptions.length === 0\"\n @click=\"add({ admin_id: Number(adminOptions[0]?.value) })\"\n >\n {{ t('panel.add-admin') }}\n </wx-button>\n <wx-button variant=\"outline\" @click=\"add({ email: '' })\">\n <template #icon><wx-icon name=\"mail\" /></template>\n {{ t('panel.add-email') }}\n </wx-button>\n </wx-space>\n\n <wx-form-item :label=\"t('panel.email-field')\" :help=\"t('panel.email-field-help')\">\n <wx-select v-model=\"emailField\" :options=\"emailOptions\" />\n </wx-form-item>\n </wx-card>\n</template>\n\n<style scoped>\n/*\n * As wide as a field, because that is what each row is: an address is typed into it and read\n * back off it. The rows are not form items — one of them is a select, the next an input, and\n * both carry a bin — so the cap that a form item applies has to be said here.\n */\n.wx-inbox-recipients {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-8);\n margin-block: var(--wx-space-12);\n max-width: var(--wx-field-max-width, 640px);\n}\n\n.wx-inbox-recipients__row {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n}\n\n.wx-inbox-recipients__row > :first-child {\n flex: 1 1 auto;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, reactive, ref, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useAdmin, useErrorText, useTranslate, WxScreenHead } from '@webx-ui/module-admin'\nimport {\n localizedValue,\n toast,\n useLocales,\n WxActionBar,\n WxBadge,\n WxButton,\n WxCard,\n WxSkeleton,\n WxTab,\n WxTabs,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport FieldList from './FieldList.vue'\nimport FormAntispam from './FormAntispam.vue'\nimport FormEmbed from './FormEmbed.vue'\nimport FormGeneral from './FormGeneral.vue'\nimport FormNotifications from './FormNotifications.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { FormOptions, InboxField, InboxForm } from './types'\n\n/**\n * One form: what it is called, what it asks, who hears about it, and how it is put on a page.\n *\n * Five tabs and one save. The fields are the exception — a question is written in its own\n * dialog and saved on its own, because it is a row with an identity (§2.1) and because a\n * dragged order that waited for a save button would be an order nobody trusts.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/inbox' })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst form = ref<InboxForm | null>(null)\nconst fields = ref<InboxField[]>([])\nconst loading = ref(true)\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nconst settings = reactive<{ slug: string; title: LocalizedValue; is_enabled: boolean }>({\n slug: '',\n title: {},\n is_enabled: true,\n})\n\nconst options = ref<FormOptions>({})\n\nconst canManage = computed(() => context.can('inbox.manage'))\n\nconst id = computed(() => Number(route.params.id))\n\nconst name = computed(() =>\n form.value === null ? '' : localizedValue(settings.title, locales.active.value, settings.slug),\n)\n\n/** Where a submission would come back to: the section, with this form already chosen. */\nconst backTo = computed(() => `${props.base}?form=${id.value}`)\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n const loaded = await api.form(id.value)\n\n form.value = loaded\n fields.value = loaded.fields ?? []\n settings.slug = loaded.slug\n settings.title = { ...loaded.title }\n settings.is_enabled = loaded.is_enabled\n options.value = { ...loaded.options }\n } catch (error) {\n toast.danger(message(error))\n void router.replace(props.base)\n } finally {\n loading.value = false\n }\n}\n\nwatch(id, () => void load(), { immediate: true })\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n try {\n const saved = await api.saveForm(id.value, {\n slug: settings.slug.trim(),\n title: settings.title,\n is_enabled: settings.is_enabled,\n options: options.value,\n })\n\n form.value = saved\n toast.success(t('panel.saved'))\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <!--\n Not a screen that fills its column, whatever the first draft said. `data-wx-fill` makes the\n screen exactly as tall as the window, and nothing inside these tabs scrolls on its own — so\n a form longer than the window grew straight through the box, and the save bar, which is the\n next thing in the column, was drawn across the middle of it with fields still going on\n underneath. What this screen wants is the ordinary thing: the page scrolls, the bar sticks\n to the bottom of it, and `WxMain` gives the screen a floor to push that bar down to.\n -->\n <div class=\"wx-inbox-editor\">\n <!-- On a card, like everything else on this screen: a bare skeleton flush against the\n page is a shape the form that follows it never takes, so the screen jumps twice —\n once when the card appears around it, once when the fields land inside. -->\n <wx-card v-if=\"loading\">\n <wx-skeleton title :rows=\"8\" />\n </wx-card>\n\n <template v-else-if=\"form\">\n <wx-screen-head\n class=\"wx-inbox-editor__head\"\n :title=\"name\"\n :subtitle=\"form.slug\"\n :back=\"backTo\"\n :back-label=\"t('panel.forms')\"\n >\n <template #title-after>\n <wx-badge v-if=\"!settings.is_enabled\" type=\"default\">{{ t('panel.off') }}</wx-badge>\n </template>\n </wx-screen-head>\n\n <!--\n Every tab is mounted at once and the hidden ones keep their state: somebody who wrote\n a thank-you, went to look at the fields and came back should find it still written.\n -->\n <wx-tabs class=\"wx-inbox-editor__tabs\" keep-alive>\n <wx-tab value=\"general\" :label=\"t('panel.tab-general')\">\n <form-general v-model:settings=\"settings\" v-model:options=\"options\" :errors=\"errors\" />\n </wx-tab>\n\n <wx-tab value=\"fields\" :label=\"t('panel.tab-fields')\">\n <field-list v-model=\"fields\" :form=\"form\" :can-manage=\"canManage\" />\n </wx-tab>\n\n <wx-tab value=\"notifications\" :label=\"t('panel.tab-notifications')\">\n <form-notifications v-model=\"options\" :fields=\"fields\" :errors=\"errors\" />\n </wx-tab>\n\n <wx-tab value=\"antispam\" :label=\"t('panel.tab-antispam')\">\n <form-antispam v-model=\"options\" />\n </wx-tab>\n\n <wx-tab value=\"embed\" :label=\"t('panel.tab-embed')\">\n <form-embed :form=\"form\" :slug=\"settings.slug\" :fields=\"fields\" />\n </wx-tab>\n </wx-tabs>\n\n <wx-action-bar v-if=\"canManage\">\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">{{ t('panel.save') }}</wx-button>\n </wx-action-bar>\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-inbox-editor {\n display: flex;\n flex-direction: column;\n /* The panel's own step, which is smaller on a phone than on a desktop. */\n gap: var(--wx-gap, var(--wx-space-16));\n}\n\n/* The tabs take what is left of the column, so the save bar under them is at its bottom\n rather than under the last field. Nothing inside them scrolls on its own — the page does. */\n/* The address it posts to, in the type an address is written in. */\n.wx-inbox-editor__head :deep(.wx-screen-head__subtitle) {\n font-family: var(--wx-font-family-mono);\n}\n\n.wx-inbox-editor__tabs {\n flex: 1 1 auto;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n toast,\n useModal,\n WxButton,\n WxDialog,\n WxFormItem,\n WxInput,\n WxSpace,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxForm } from './types'\n\n/**\n * A form, started.\n *\n * Two fields, because a form has nothing else until it has questions: what it is called and\n * where it answers. Everything else — who is written to, what happens after sending, the\n * antispam — belongs to the editor, and asking for it before the form exists would be a\n * dialog longer than the screen it leads to.\n *\n * The address is typed rather than made out of the title. A page's address is a sentence\n * transliterated; a form's is a short word somebody chooses once and then writes into a\n * template by hand, and guessing `svyazhites-s-nami` for them helps nobody.\n */\nconst { resolve, dismiss, open } = useModal<InboxForm>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst title = ref<LocalizedValue>({})\nconst slug = ref('')\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nfunction errorOf(field: string): string | undefined {\n return errors.value[field]?.[0]\n}\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n try {\n resolve(\n await api.createForm({\n title: title.value,\n slug: slug.value.trim(),\n is_enabled: true,\n options: {},\n }),\n )\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog v-model:open=\"open\" :title=\"t('panel.new-form-title')\" :width=\"520\">\n <div class=\"wx-inbox-create\">\n <wx-form-item :label=\"t('panel.title')\" :error=\"errorOf('title')\" required>\n <wx-input v-model=\"title\" localized autofocus />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.slug')\" :help=\"t('panel.slug-help')\" :error=\"errorOf('slug')\">\n <wx-input v-model=\"slug\" placeholder=\"contact\" />\n </wx-form-item>\n </div>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">\n {{ t('panel.save') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-inbox-create {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n localizedValue,\n toast,\n useLocales,\n useModal,\n WxAlert,\n WxButton,\n WxCheckbox,\n WxCheckboxGroup,\n WxDatePicker,\n WxDialog,\n WxFormItem,\n WxInput,\n WxRadioGroup,\n WxSelect,\n WxSkeleton,\n WxSpace,\n WxTextarea,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxField, InboxForm, InboxSubmission } from './types'\n\n/**\n * A submission typed in by hand — a call that came by telephone, a form filled in on paper.\n *\n * The same questions the site asks, drawn from the same fields, and sent to the same intake:\n * the rules are the form's own, so a required field is required here too and a refusal reads\n * the same way. The one thing the panel cannot do is attach a visitor's file, because there is\n * no visitor — the files a submission carries are what was posted with it.\n */\nconst props = defineProps<{ form: InboxForm }>()\n\nconst { resolve, dismiss, open } = useModal<InboxSubmission>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst fields = ref<InboxField[]>([])\nconst loading = ref(true)\nconst saving = ref(false)\nconst values = ref<Record<string, unknown>>({})\nconst errors = ref<Record<string, string[]>>({})\n\n/** Everything the form actually asks, files excepted. */\nconst asked = computed(() => fields.value.filter((field) => field.type !== 'file'))\n\nconst hasFiles = computed(() => fields.value.some((field) => field.type === 'file'))\n\nfunction errorOf(field: InboxField): string | undefined {\n return errors.value[`fields.${field.key}`]?.[0]\n}\n\nfunction label(field: InboxField): string {\n return localizedValue(field.title, locales.active.value, field.key)\n}\n\nfunction text(value: unknown, fallback = ''): string {\n return localizedValue(\n value as Parameters<typeof localizedValue>[0],\n locales.active.value,\n fallback,\n )\n}\n\n/** The written-down answers of a `select`, `radio` or `checkbox`, in the panel's language. */\nfunction choices(field: InboxField): { value: string; label: string }[] {\n return (field.options.choices ?? []).map((choice) => ({\n value: choice.value,\n label: text(choice.label, choice.value),\n }))\n}\n\nasync function load(): Promise<void> {\n try {\n const form = await api.form(props.form.id)\n\n fields.value = (form.fields ?? []).filter((field) => field.is_enabled)\n\n for (const field of fields.value) {\n values.value[field.key] =\n field.type === 'checkbox' ? [] : field.type === 'consent' ? false : ''\n }\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nvoid load()\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n try {\n resolve(await api.createSubmission(props.form.id, values.value))\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog v-model:open=\"open\" :title=\"t('panel.new-submission-title')\" :width=\"560\">\n <div class=\"wx-inbox-by-hand\">\n <wx-alert type=\"info\" :closable=\"false\">{{ t('panel.new-submission-help') }}</wx-alert>\n\n <wx-skeleton v-if=\"loading\" :rows=\"4\" />\n\n <template v-else>\n <wx-form-item\n v-for=\"field in asked\"\n :key=\"field.id\"\n :label=\"label(field)\"\n :help=\"text(field.help)\"\n :error=\"errorOf(field)\"\n :required=\"field.is_required\"\n >\n <wx-textarea\n v-if=\"field.type === 'textarea'\"\n v-model=\"values[field.key] as string\"\n :rows=\"field.options.rows ?? 4\"\n :placeholder=\"text(field.placeholder)\"\n />\n <wx-select\n v-else-if=\"field.type === 'select'\"\n v-model=\"values[field.key] as string\"\n :options=\"choices(field)\"\n clearable\n :placeholder=\"text(field.placeholder)\"\n />\n <wx-radio-group\n v-else-if=\"field.type === 'radio'\"\n v-model=\"values[field.key] as string\"\n :options=\"choices(field)\"\n />\n <wx-checkbox-group\n v-else-if=\"field.type === 'checkbox'\"\n v-model=\"values[field.key] as string[]\"\n :options=\"choices(field)\"\n />\n <!-- The sentence beside the tick is the form's own and may carry a link, so it is\n the field's label rather than text written here. -->\n <wx-checkbox\n v-else-if=\"field.type === 'consent'\"\n v-model=\"values[field.key] as boolean\"\n :label=\"text(field.options.text, label(field))\"\n />\n <wx-date-picker\n v-else-if=\"field.type === 'date'\"\n v-model=\"values[field.key] as string\"\n :placeholder=\"text(field.placeholder)\"\n />\n <wx-input\n v-else\n v-model=\"values[field.key] as string\"\n :type=\"field.type === 'email' ? 'email' : field.type === 'tel' ? 'tel' : 'text'\"\n :placeholder=\"text(field.placeholder)\"\n :maxlength=\"field.options.maxlength\"\n />\n </wx-form-item>\n\n <!-- Said rather than silently left out: a form whose point is the attachment would\n otherwise look like it had lost a field. -->\n <wx-alert v-if=\"hasFiles\" type=\"warning\" :closable=\"false\">\n {{ t('panel.no-files-by-hand') }}\n </wx-alert>\n </template>\n </div>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" :disabled=\"loading\" @click=\"save\">\n {{ t('panel.save') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-inbox-by-hand {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, useTemplateRef, watch } from 'vue'\nimport { useRoute, useRouter, type LocationQueryRaw } from 'vue-router'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxDate,\n rowMenuWidth,\n WxFilterChips,\n WxRowMenu,\n WxScreenHead,\n type AppliedFilter,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n localizedValue,\n toast,\n useLocales,\n WxAvatar,\n WxBadge,\n WxButton,\n WxIcon,\n WxSelect,\n WxTable,\n WxTabs,\n WxText,\n WxEntityCard,\n WxFormItem,\n WxTooltip,\n useElementWidth,\n type TabItem,\n type TableColumn,\n type TableState,\n} from '@webx-ui/core'\nimport SubmissionCreateDialog from './SubmissionCreateDialog.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type {\n InboxForm,\n InboxStatus,\n InboxSubmission,\n SubmissionRow,\n SubmissionsPage,\n} from './types'\n\n/**\n * What has come in through the chosen form — the right-hand side of the section (§11).\n *\n * Its columns are the form's own `in_table` fields and arrive with the rows, so this never has\n * to fetch the form to know what it is drawing. Which of them survive a narrow pane is decided\n * here and not by the form: the first answer identifies the row and stays at any width, and\n * each one after it goes a step earlier than the last. Pairing two of them into one cell — the\n * e-mail under the name — would mean guessing which fields mean what, and the panel does not\n * know that about somebody else's form.\n *\n * The state of the list lives in the address: coming back from a submission has to land on the\n * same form, the same tab and the same page, or the screen costs exactly that over the dialog\n * it was chosen instead of (§11).\n */\nconst props = withDefaults(\n defineProps<{\n form: InboxForm\n /** Where the section is mounted. */\n base?: string\n }>(),\n { base: '/inbox' },\n)\n\nconst emit = defineEmits<{\n /** Something changed that the column of forms counts. */\n changed: []\n}>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseInboxMessages()\n\n/** Where a row stops being a row. */\nconst CARDS = 640\n\nconst root = useTemplateRef<HTMLElement>('root')\nconst width = useElementWidth(root)\nconst asCards = computed(() => width.value > 0 && width.value < CARDS)\n\n/**\n * One decision about it, not two.\n *\n * The pane measures itself and the table measures itself, and between the two stands the\n * pane's own step — so the same number meant two different widths, and in the band between\n * them the table drew cards out of the full set of columns: five lines of \"Label: value\" for\n * one enquiry, which is exactly what the card exists instead of. The table is told rather\n * than left to work it out: never, or always, and by the same measurement the columns use.\n */\nconst cardsBelow = computed(() => (asCards.value ? Number.POSITIVE_INFINITY : 0))\n\nconst t = useTranslate('webx-inbox')\nconst panel = useTranslate('webx-admin')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst page = ref<SubmissionsPage | null>(null)\nconst statuses = ref<InboxStatus[]>([])\nconst loading = ref(false)\nconst selected = ref<SubmissionRow[]>([])\nconst moving = ref(false)\n\nconst canUpdate = computed(() => context.can('inbox.update'))\n\nconst add = createModal<InboxSubmission, { form: InboxForm }>(SubmissionCreateDialog)\n\n/** The tab, kept in the address so the way back lands on it. */\nconst view = computed({\n get: () =>\n typeof route.query.view === 'string' && route.query.view !== '' ? route.query.view : 'all',\n set: (value: string) => {\n // A new tab is a new list: the page it was on belongs to the tab it was on.\n void router.replace({\n query: { ...route.query, view: value === 'all' ? undefined : value, page: undefined },\n })\n },\n})\n\n/** Everything the list is looking at, as it travels to the server and into the address. */\nconst query = computed(() => ({\n view: view.value,\n search: typeof route.query.search === 'string' ? route.query.search : '',\n assignee: typeof route.query.assignee === 'string' ? route.query.assignee : null,\n placement: typeof route.query.placement === 'string' ? route.query.placement : null,\n sort: typeof route.query.sort === 'string' ? route.query.sort : null,\n page: Number(route.query.page ?? 1) || 1,\n}))\n\n/*\n * Where on the site the form has been sent from — the footer, an article (layout regions §11).\n *\n * The list carries the places with its rows, over the whole form rather than the filter, so the\n * filter costs no request of its own and its choices never shrink to the one already picked. It\n * is offered only when there is more than one place: one form in one place is nothing to filter.\n * And it stays while a placement is in the address, or a filter that arrived by link could not be\n * taken off.\n */\nconst placementOptions = computed(() =>\n (page.value?.placements ?? []).map((placement) =>\n placement === null\n ? { value: 'none', label: t('panel.placement-none') }\n : { value: placement, label: placement },\n ),\n)\n\nconst hasPlacements = computed(\n () => placementOptions.value.length > 1 || query.value.placement !== null,\n)\n\nconst applied = computed<AppliedFilter[]>(() => {\n const placement = query.value.placement\n\n if (placement === null) return []\n\n const label =\n placementOptions.value.find((option) => option.value === placement)?.label ??\n (placement === 'none' ? t('panel.placement-none') : placement)\n\n return [\n {\n key: 'placement',\n label: `${t('panel.meta-placement')}: ${label}`,\n clear: () => narrow(undefined),\n },\n ]\n})\n\nfunction narrow(placement: unknown): void {\n void router.replace({\n query: {\n ...route.query,\n placement: typeof placement === 'string' && placement !== '' ? placement : undefined,\n page: undefined,\n },\n })\n}\n\nconst views = computed<TabItem[]>(() => {\n const counts = page.value?.counts\n\n const items: TabItem[] = [\n { value: 'all', label: t('panel.view-all'), badge: counts?.all || undefined },\n { value: 'unread', label: t('panel.view-unread'), badge: counts?.unread || undefined },\n ]\n\n for (const status of statuses.value) {\n items.push({\n value: status.key,\n label: name(status),\n badge: counts?.statuses[status.key] || undefined,\n })\n }\n\n return items\n})\n\n/**\n * The n-th answer of a submission, for the card that has no columns to put them in.\n *\n * By position rather than by name, because a form's fields are the form's own: the first answer\n * is what the row is recognised by wherever it came from, and the second is the next most likely\n * way to reach whoever wrote it.\n */\nfunction answer(row: SubmissionRow, index: number): string {\n const column = page.value?.columns?.[index]\n\n return column ? (row.values[column.key] ?? '') : ''\n}\n\nconst columns = computed<TableColumn<SubmissionRow>[]>(() => {\n const answers = page.value?.columns ?? []\n\n /*\n * Narrow, a submission is one entity rather than five labelled lines: who wrote it, the next\n * answer under that, and the state of it beside the date. Five lines of \"Label: value\" is four\n * hundred pixels for one enquiry, and an inbox is read in a list.\n */\n if (asCards.value) return [{ key: 'card', label: '' }]\n\n return [\n ...answers.map((column, index) => ({\n key: `values.${column.key}`,\n label: column.label,\n sortable: true,\n // The first answer is what the row is recognised by and stays at any width; every one\n // after it is worth less than the room it takes, so it goes a step sooner. The steps are\n // wide — 640, 960 — because an answer is a sentence and not a number: two of them plus\n // the status and the date is already what a 755px pane holds without scrolling sideways,\n // which is what the pane beside the forms actually is on a 1280 screen (§11).\n hideBelow: index === 0 ? undefined : 320 + index * 320,\n })),\n // A floor rather than a width: the cell holds a badge, sometimes an avatar and sometimes\n // a paperclip, and a fixed width that any of them overflows makes the whole table scroll\n // sideways by two pixels.\n { key: 'status', label: t('panel.status'), minWidth: 100 },\n {\n key: 'created_at',\n label: t('panel.received'),\n sortable: true,\n width: 120,\n // \"today at 16:22\" is three words the table will break over two lines given half a\n // chance, and a date read down a column has to be one line to be read at all.\n cellClass: 'wx-submissions__when',\n hideBelow: 520,\n // Kept on the card, unlike most dates: \"when did this come in\" is one of the two\n // questions a submission is looked at for, and the other one is who sent it.\n },\n { key: 'actions', label: '', width: rowMenuWidth, align: 'right', hideOnCards: true },\n ]\n})\n\n/**\n * Two different nothings, said differently.\n *\n * \"Nothing has ever come in through this form\" is a fact about the form; \"nothing matches\" is\n * a fact about the tab somebody is standing on. Saying the first one on a filtered tab tells a\n * reader their form is dead when it is not.\n */\nconst emptyText = computed(() =>\n query.value.view === 'all' &&\n query.value.search === '' &&\n query.value.assignee === null &&\n query.value.placement === null\n ? t('panel.submissions-empty')\n : t('panel.submissions-none'),\n)\n\nconst statusOptions = computed(() =>\n statuses.value.map((status) => ({ value: status.id, label: name(status) })),\n)\n\nfunction name(status: InboxStatus): string {\n return localizedValue(status.title, locales.active.value, status.key)\n}\n\nfunction formName(): string {\n return localizedValue(props.form.title, locales.active.value, props.form.slug)\n}\n\nasync function load(state?: TableState): Promise<void> {\n loading.value = true\n\n try {\n page.value = await api.submissions(props.form.id, {\n view: query.value.view,\n search: state?.search ?? query.value.search,\n assignee: query.value.assignee,\n placement: query.value.placement,\n sort: state?.sort ? `${state.sort.order === 'desc' ? '-' : ''}${state.sort.key}` : null,\n page: state?.page ?? query.value.page,\n per_page: state?.perPage,\n })\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\n/**\n * The table reports everything it knows in one event, and that is the one place the address is\n * written from — so a page, a sort and a search all survive opening a submission and coming\n * back, and none of them has its own half of the bookkeeping.\n */\nfunction onState(state: TableState): void {\n const wanted: LocationQueryRaw = {\n ...route.query,\n search: state.search === '' ? undefined : state.search,\n sort:\n state.sort === null\n ? undefined\n : `${state.sort.order === 'desc' ? '-' : ''}${state.sort.key}`,\n page: state.page === 1 ? undefined : String(state.page),\n }\n\n void router.replace({ query: wanted })\n void load(state)\n}\n\n/* The form changes under the pane — the left column is a list, not a navigation — so the list\n has to notice rather than go on showing the previous form's submissions. One source per value,\n not a getter returning an array: that array is new on every change of the address, so a page\n turn would clear the selection and ask a second time, racing the request `onState` sent. */\nwatch([() => props.form.id, view, () => query.value.assignee, () => query.value.placement], () => {\n selected.value = []\n void load()\n})\n\nvoid load()\nvoid statusList()\n\nasync function statusList(): Promise<void> {\n try {\n statuses.value = await api.statuses()\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\n/** Opening one carries the whole filter along, so its arrows walk the list it came from. */\nfunction open(row: SubmissionRow): void {\n void router.push({ path: `${props.base}/submissions/${row.id}`, query: { ...route.query } })\n}\n\nfunction actionsFor(row: SubmissionRow): RowAction[] {\n if (!canUpdate.value) return []\n\n return [\n {\n key: 'read',\n icon: row.is_read ? 'eye-off' : 'eye',\n label: row.is_read ? t('panel.mark-unread') : t('panel.mark-read'),\n run: () => void mass([row.id], row.is_read ? 'unread' : 'read'),\n },\n {\n key: 'delete',\n icon: 'trash',\n label: t('panel.delete'),\n danger: true,\n run: () => void remove([row.id]),\n },\n ]\n}\n\nasync function moveTo(statusId: unknown): Promise<void> {\n if (typeof statusId !== 'number') return\n\n moving.value = true\n await mass(\n selected.value.map((row) => row.id),\n 'status',\n statusId,\n )\n moving.value = false\n}\n\nasync function remove(ids: number[]): Promise<void> {\n const agreed = await confirm({\n title:\n ids.length === 1\n ? t('panel.delete-submission-title')\n : t('panel.delete-selected-title', { count: ids.length }),\n message: t('panel.delete-submission-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n await mass(ids, 'delete')\n}\n\nasync function mass(\n ids: number[],\n action: 'status' | 'read' | 'unread' | 'delete',\n statusId?: number,\n): Promise<void> {\n if (ids.length === 0) return\n\n try {\n await api.massSubmissions({ ids, action, status_id: statusId })\n selected.value = []\n await load()\n emit('changed')\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function byHand(): Promise<void> {\n const made = await add({ form: props.form })\n\n if (!made) return\n\n toast.success(t('panel.created'))\n await load()\n emit('changed')\n void router.push({ path: `${props.base}/submissions/${made.id}`, query: { ...route.query } })\n}\n\n/**\n * A plain link and not a fetch: the browser downloads files, and pulling a spreadsheet into\n * memory to hand it straight back is work for nothing. It carries the filter that is on, so\n * what comes out is what is on screen.\n */\nconst exportHref = computed(() =>\n api.exportUrl(props.form.id, {\n view: query.value.view,\n search: query.value.search,\n assignee: query.value.assignee,\n placement: query.value.placement,\n sort: query.value.sort,\n }),\n)\n\n/*\n * The tools of the pane are what is done to this list of answers, and that is one thing:\n * take them away as a file.\n *\n * What the form is — its fields, its letters, its address — belongs to the form's own ··· in\n * the list of forms. And writing a submission is the section's own action, so it stands in\n * the head of the section beside its name (§11); the dialog is still this component's, which\n * is why it is exposed rather than moved: what is created has to land in this list, in this\n * filter, and be counted in these tabs.\n */\nconst actions = computed<ScreenAction[]>(() => [\n { key: 'export', label: t('panel.export'), icon: 'download', href: exportHref.value },\n])\n\ndefineExpose({ create: byHand })\n</script>\n\n<template>\n <div ref=\"root\" class=\"wx-submissions\">\n <wx-screen-head\n class=\"wx-submissions__head\"\n :level=\"3\"\n :title=\"formName()\"\n :subtitle=\"form.slug\"\n :actions=\"actions\"\n />\n\n <!--\n `items` and one panel: the table stays mounted while the tab changes, so the search\n somebody typed does not go with it.\n -->\n <wx-tabs\n v-model=\"view\"\n class=\"wx-submissions__views\"\n :items=\"views\"\n :collapse-below=\"560\"\n :aria-label=\"t('panel.status')\"\n >\n <wx-table\n :data=\"page\"\n :columns=\"columns\"\n row-key=\"id\"\n searchable\n clickable\n hover\n flush\n :loading=\"loading\"\n :selectable=\"canUpdate\"\n :select-row-label=\"panel('filters.select-row')\"\n :select-all-label=\"panel('filters.select-all')\"\n :row-class=\"(row: SubmissionRow) => (row.is_read ? undefined : 'is-unread')\"\n :search-placeholder=\"t('panel.search-submissions')\"\n :empty-text=\"emptyText\"\n :cards-below=\"cardsBelow\"\n :filters-count=\"applied.length\"\n @row-click=\"open\"\n @state-change=\"onState\"\n @selection-change=\"(_keys: unknown, rows: SubmissionRow[]) => (selected = rows)\"\n >\n <!-- The pile only offers what can be done to all of it at once; one row's own menu\n keeps the rest. -->\n <template v-if=\"selected.length > 0\" #actions>\n <div class=\"wx-submissions__mass\">\n <wx-text size=\"sm\" weight=\"medium\">\n {{ t('panel.selected', { count: selected.length }) }}\n </wx-text>\n <wx-select\n :model-value=\"null\"\n :options=\"statusOptions\"\n :placeholder=\"t('panel.move-to')\"\n :disabled=\"moving\"\n size=\"sm\"\n style=\"width: 180px\"\n @update:model-value=\"moveTo\"\n />\n <wx-button\n size=\"sm\"\n variant=\"outline\"\n type=\"danger\"\n icon=\"trash\"\n @click=\"remove(selected.map((row) => row.id))\"\n >\n {{ t('panel.delete') }}\n </wx-button>\n </div>\n </template>\n\n <template v-if=\"hasPlacements\" #filters>\n <wx-form-item :label=\"t('panel.meta-placement')\">\n <wx-select\n :model-value=\"query.placement\"\n :options=\"placementOptions\"\n :placeholder=\"t('panel.any-placement')\"\n clearable\n size=\"sm\"\n @update:model-value=\"narrow\"\n />\n </wx-form-item>\n </template>\n\n <template v-if=\"applied.length > 0\" #applied>\n <wx-filter-chips :filters=\"applied\" />\n </template>\n\n <template #cell-status=\"{ row }\">\n <div class=\"wx-submissions__state\">\n <wx-badge v-if=\"row.status\" :type=\"row.status.color\">{{ name(row.status) }}</wx-badge>\n <!-- The assignee is an avatar beside the status rather than a column: at the\n width this pane has, a column of names costs an answer (§11). -->\n <wx-avatar\n v-if=\"row.assignee\"\n :name=\"row.assignee.name\"\n :title=\"row.assignee.name\"\n size=\"xs\"\n tone=\"auto\"\n />\n <wx-tooltip v-if=\"row.files_count > 0\" :content=\"t('panel.attachments')\">\n <wx-icon name=\"file\" size=\"sm\" />\n </wx-tooltip>\n </div>\n </template>\n\n <template #cell-created_at=\"{ row }\">\n <wx-date :value=\"row.created_at\" compact />\n </template>\n\n <template #cell-card=\"{ row }\">\n <wx-entity-card variant=\"plain\" shape=\"circle\" :title=\"answer(row, 0)\">\n <template #subtitle>{{ answer(row, 1) }}</template>\n\n <template #meta>\n <wx-badge v-if=\"row.status\" :type=\"row.status.color\" size=\"sm\">\n {{ name(row.status) }}\n </wx-badge>\n <wx-avatar\n v-if=\"row.assignee\"\n :name=\"row.assignee.name\"\n :title=\"row.assignee.name\"\n size=\"xs\"\n tone=\"auto\"\n />\n <wx-icon v-if=\"row.files_count > 0\" name=\"file\" size=\"sm\" />\n <wx-date :value=\"row.created_at\" />\n </template>\n </wx-entity-card>\n </template>\n\n <template #card-actions=\"{ row }\">\n <wx-row-menu :actions=\"actionsFor(row)\" :label=\"String(row.id)\" />\n </template>\n\n <template #cell-actions=\"{ row }\">\n <wx-row-menu :actions=\"actionsFor(row)\" :label=\"String(row.id)\" />\n </template>\n </wx-table>\n </wx-tabs>\n </div>\n</template>\n\n<style scoped>\n/*\n * One step, and everything in the pane keeps it.\n *\n * The panel's own — 8 on a phone and 16 on a desktop — and not a number of this screen's own.\n * Written as 16 here, the pane kept desktop air on a 375px screen: the head, the tabs and the\n * rows each took a line of nothing between them, and four rows fitted where six do now.\n *\n * It is the pane that holds it, so the name of the form, the tabs, the search box and the rows\n * all begin on the same line down the left. The table used to add a step of its own inside\n * this one — measured on a phone: the head at 17 and the search at 33 — and two insets, one\n * for the words and one for the list they are about, read as two panels stacked rather than as\n * one screen.\n */\n.wx-submissions {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n padding: var(--wx-gap, var(--wx-space-16));\n min-width: 0;\n}\n\n/* The address the form posts to, in the type an address is written in. */\n.wx-submissions__head :deep(.wx-screen-head__subtitle) {\n font-family: var(--wx-font-family-mono);\n}\n\n/*\n * The tabs and the rows they filter are one thing, so they stand closer than two things do.\n * `WxTabs` leaves the panel's step under the strip, which is right where a card follows it;\n * here what follows is the search box of the same table, and a full step between a filter and\n * what it filters reads as a gap between two screens.\n */\n.wx-submissions__views :deep(.wx-tabs__panels) {\n padding-top: var(--wx-space-8);\n}\n\n.wx-submissions__mass {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n flex-wrap: wrap;\n}\n\n/* `:deep()` because the cell is the table's element and the class is ours — a scoped rule\n would be looking for our attribute on somebody else's markup (CLAUDE.md §4). */\n.wx-submissions :deep(.wx-submissions__when) {\n white-space: nowrap;\n}\n\n.wx-submissions__state {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--wx-space-6);\n min-width: 0;\n}\n\n/*\n * What nobody has opened yet, said on the whole row. `:deep()` because the row is the table's\n * element and the class is ours — a scoped rule would be looking for our attribute on somebody\n * else's markup (CLAUDE.md §4).\n */\n.wx-submissions :deep(.is-unread) {\n font-weight: var(--wx-font-weight-medium);\n}\n\n.wx-submissions :deep(.is-unread) td:first-child {\n box-shadow: inset 2px 0 0 0 var(--wx-color-primary);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, useTemplateRef, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxListScreen,\n WxRowMenu,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n localizedValue,\n toast,\n useLocales,\n WxAction,\n WxButton,\n WxCard,\n WxEmpty,\n WxIcon,\n WxIndicator,\n WxListDetail,\n WxSkeleton,\n WxSortableList,\n WxText,\n} from '@webx-ui/core'\nimport FormCreateDialog from './FormCreateDialog.vue'\nimport SubmissionList from './SubmissionList.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxForm } from './types'\n\n/**\n * The section: the forms of the site on the left, what came in through one of them on the\n * right (§11, §2.12).\n *\n * One screen rather than two, and that is the decision this is built around. The columns of\n * the list are the fields of the chosen form, so a list of everything would have no columns\n * to speak of; and the two questions somebody opens this section to ask — \"what is new\" and\n * \"what does this form ask\" — are one click apart instead of one screen apart.\n *\n * Which of the two is the screen and which is the chooser is the second decision. The forms\n * are the chooser: they are the `filters` column of the pane, so on a phone they fold into a\n * panel and the submissions are what the section opens on. The other way round — forms as the\n * list, submissions as the record beside it — is what this was, and it cost the reader a\n * screen: somebody who opens the section is asking what came in, and was shown a list of\n * three form names instead, every time.\n *\n * One form is therefore always open (the first, unless the address names another), and what\n * is here is the column: the forms, in the order somebody dragged them, with what is waiting\n * in each.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/inbox' })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst forms = ref<InboxForm[]>([])\nconst loading = ref(true)\n\n/** The list of submissions, for the one action of its own that the section's head carries. */\nconst pane = useTemplateRef<{ create: () => void }>('pane')\n\n/**\n * Whether the forms still have a column, and whether their panel is up.\n *\n * Both live here rather than inside the pane because the way to the forms is in the head of\n * the section, beside its other actions — a button that appears exactly when the column is\n * gone. The pane says when that is.\n */\nconst columnInline = ref(true)\nconst formsOpen = ref(false)\n\nconst canManage = computed(() => context.can('inbox.manage'))\n\nconst create = createModal<InboxForm, Record<string, never>>(FormCreateDialog)\n\nconst title = computed(\n () =>\n context.state.manifest?.modules.find((module) => module.id === 'inbox')?.title ??\n t('module.title'),\n)\n\n/**\n * Which form is open, kept in the address.\n *\n * So that coming back from a submission lands on the form it belonged to (§11) — and so that\n * a link to \"the callback form\" is a link somebody can send.\n */\nconst current = computed<number | null>(() => {\n const asked = route.query.form\n\n return typeof asked === 'string' && asked !== '' ? Number(asked) : null\n})\n\nconst chosen = computed(() => forms.value.find((form) => form.id === current.value) ?? null)\n\nfunction name(form: InboxForm): string {\n return localizedValue(form.title, locales.active.value, form.slug)\n}\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n forms.value = await api.forms()\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nvoid load()\n\n/**\n * One form is always open, and the address always says which.\n *\n * The section is the submissions, so the first form stands in until somebody picks another —\n * on a phone especially, where the alternative is opening the panel before seeing anything at\n * all. It covers the address that names no form, the address that names one that has since\n * been deleted, and the list arriving after the address did; `replace`, because none of the\n * three is a place worth going back to.\n */\nwatch([forms, chosen], () => {\n if (forms.value.length === 0 || chosen.value !== null) return\n\n void router.replace({ query: { ...route.query, form: String(forms.value[0].id) } })\n})\n\nfunction choose(form: InboxForm, close: () => void): void {\n void router.replace({ query: { ...route.query, form: String(form.id) } })\n /* Picked from the panel: the panel has done its job. It is a column on a wide screen, and\n closing what is not open does nothing there. */\n close()\n}\n\nfunction edit(form: InboxForm): void {\n void router.push(`${props.base}/forms/${form.id}`)\n}\n\nfunction actionsFor(form: InboxForm): RowAction[] {\n if (!canManage.value) return []\n\n return [\n { key: 'settings', icon: 'settings', label: t('panel.settings'), run: () => edit(form) },\n { key: 'duplicate', icon: 'copy', label: t('panel.duplicate'), run: () => duplicate(form) },\n // A form that has taken submissions is switched off, never deleted (§2.4). The line is\n // left out rather than greyed: a menu is a list of what is possible.\n ...(form.submissions_count === 0\n ? [\n {\n key: 'delete',\n icon: 'trash' as const,\n label: t('panel.delete'),\n danger: true,\n run: () => remove(form),\n },\n ]\n : []),\n ]\n}\n\nasync function add(): Promise<void> {\n const made = await create({})\n\n if (made) {\n await load()\n edit(made)\n }\n}\n\nasync function duplicate(form: InboxForm): Promise<void> {\n try {\n const copy = await api.duplicateForm(form.id)\n toast.success(t('panel.duplicated'))\n await load()\n edit(copy)\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function remove(form: InboxForm): Promise<void> {\n const agreed = await confirm({\n title: t('panel.delete-form-title', { form: name(form) }),\n message: t('panel.delete-form-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeForm(form.id)\n toast.success(t('panel.deleted'))\n\n /* The address named the form that is gone; what stands in its place is decided above. */\n if (current.value === form.id) {\n const rest = { ...route.query }\n delete rest.form\n void router.replace({ query: rest })\n }\n\n await load()\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\n/**\n * The whole order, every time.\n *\n * The list is already in its new order on screen — `WxSortableList` reorders the model before\n * it says anything — so this only has to agree with what is there, and a failure has to put\n * the list back rather than leave the screen disagreeing with the database.\n */\nasync function reorder(): Promise<void> {\n try {\n await api.sortForms(forms.value.map((form) => form.id))\n } catch (error) {\n toast.danger(message(error, t('panel.reorder-failed')))\n await load()\n }\n}\n\n/**\n * What the section offers. Declared, because on a phone the head folds it into the ···.\n *\n * The one it exists for is a submission, not a form: this is the inbox, and the section is\n * opened dozens of times for what came in for every once that a form is added. A new form is\n * the `+` over the list of forms — beside the thing it makes one more of — and what used to\n * stand here as the primary button was that, which is why it was the biggest thing on the\n * screen and almost never what anybody wanted.\n */\nconst actions = computed<ScreenAction[]>(() => {\n const list: ScreenAction[] = []\n\n if (canManage.value) {\n list.push({\n key: 'statuses',\n label: t('panel.statuses'),\n icon: 'tag',\n run: () => void router.push(`${props.base}/statuses`),\n })\n }\n\n /* The dialog belongs to the list: what is written has to land in it, in the filter that is\n on, and be counted in its tabs. The head only asks for it. */\n if (context.can('inbox.update') && chosen.value !== null) {\n list.push({\n key: 'new-submission',\n label: t('panel.new-submission'),\n icon: 'plus',\n primary: true,\n run: () => void pane.value?.create(),\n })\n }\n\n return list\n})\n</script>\n\n<template>\n <wx-list-screen :title=\"title\" :actions=\"actions\" :card=\"false\">\n <!--\n Written here rather than declared as an action, because an action folds behind the ···\n on a narrow head and this is only ever drawn on one: it is the way to the forms for a\n reader whose column of them is gone. It stands where the other actions of the section\n stand, beside the one that writes a submission.\n -->\n <template v-if=\"!columnInline\" #actions>\n <wx-button variant=\"outline\" @click=\"formsOpen = true\">\n <template #icon><wx-icon name=\"list\" /></template>\n {{ t('panel.forms') }}\n </wx-button>\n </template>\n\n <wx-card class=\"wx-inbox\" padding=\"none\">\n <wx-list-detail\n v-model:filters-open=\"formsOpen\"\n class=\"wx-inbox__panes\"\n :filters-width=\"270\"\n :detail-min=\"420\"\n :filters-title=\"t('panel.forms')\"\n @filters-inline=\"columnInline = $event\"\n >\n <!--\n The forms are what narrows the list, so they are the column that folds: on a phone\n this is a panel raised from the head of the submissions, and the submissions are\n the screen.\n -->\n <template #filters=\"{ inline, close }\">\n <wx-skeleton v-if=\"loading\" class=\"wx-inbox__loading\" :rows=\"5\" />\n\n <template v-else>\n <!--\n In the panel the `+` would stand alone on a line of its own under the drawer's\n own heading, which reads as a stray mark rather than as a control. There is\n room for the word here, so it takes it.\n -->\n <wx-button\n v-if=\"!inline && canManage\"\n class=\"wx-inbox__new-form\"\n variant=\"outline\"\n block\n @click=\"add\"\n >\n <template #icon><wx-icon name=\"plus\" /></template>\n {{ t('panel.new-form') }}\n </wx-button>\n\n <!--\n A grip and not the whole row: the row is what opens a form, and a list whose\n rows both open and drag is a list where one of the two happens by accident.\n -->\n <wx-sortable-list\n v-model=\"forms\"\n class=\"wx-inbox__forms\"\n :class=\"{ 'is-panel': !inline }\"\n plain\n size=\"sm\"\n item-key=\"id\"\n :item-label=\"name\"\n :disabled=\"!canManage\"\n :title=\"inline ? t('panel.forms') : undefined\"\n @move=\"reorder\"\n >\n <!--\n A new form is made where the forms are and not in the head of the section: it\n is one more of these, and it is asked for once for every few dozen times\n somebody opens the inbox to read what came in. An icon, because the word for\n it is already written beside it.\n -->\n <template v-if=\"inline && canManage\" #extra>\n <wx-action icon=\"plus\" size=\"sm\" :title=\"t('panel.new-form')\" @click=\"add\" />\n </template>\n\n <template #default=\"{ item }\">\n <button\n type=\"button\"\n class=\"wx-inbox-form\"\n :class=\"{ 'is-current': item.id === current, 'is-off': !item.is_enabled }\"\n @click=\"choose(item, close)\"\n >\n <!--\n A switched-off form is said by the name itself — struck through and grey —\n rather than by a badge beside it. The badge was a second thing on a line\n 270px wide that already holds a name, a count and the ···: it did not\n shrink, so it ran under the menu, and it said in a word what the type says\n at a glance.\n -->\n <span class=\"wx-inbox-form__name\">\n <wx-text truncate weight=\"medium\" :tone=\"item.is_enabled ? 'default' : 'muted'\">\n {{ name(item) }}\n </wx-text>\n\n <!--\n On the name's line, not under it. The list stacks what the slot hands it,\n so a count standing beside the form was a third line under the address —\n the row grew by a line to say a single digit. Unread first and in colour;\n the total behind it, quietly, because it is context rather than work.\n -->\n <wx-indicator\n v-if=\"item.unread_count\"\n class=\"wx-inbox-form__count\"\n type=\"primary\"\n :value=\"item.unread_count\"\n :label=\"t('panel.unread')\"\n />\n <wx-indicator\n v-else-if=\"item.submissions_count\"\n class=\"wx-inbox-form__count\"\n type=\"neutral\"\n :value=\"item.submissions_count\"\n :label=\"t('panel.submissions')\"\n />\n </span>\n <wx-text size=\"sm\" tone=\"muted\" truncate>{{ item.slug }}</wx-text>\n </button>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-row-menu :actions=\"actionsFor(item)\" :label=\"name(item)\" />\n </template>\n </wx-sortable-list>\n </template>\n </template>\n\n <!--\n The submissions of the chosen form, and the screen. The pane is the list's, head\n and all: what is above the rows — which form this is, the way to another one where\n there is no column for them — belongs beside the tabs.\n\n Nothing chosen and nothing loading means the site has no forms yet, since a form\n that exists is picked for the reader. The word about it goes here rather than in\n the column, because here is what a phone shows.\n -->\n <template #list>\n <wx-skeleton v-if=\"loading\" class=\"wx-inbox__loading\" :rows=\"6\" />\n\n <submission-list\n v-else-if=\"chosen\"\n ref=\"pane\"\n :key=\"chosen.id\"\n :form=\"chosen\"\n :base=\"props.base\"\n @changed=\"load\"\n />\n\n <wx-empty v-else :title=\"t('panel.no-forms')\" :description=\"t('panel.no-forms-help')\" />\n </template>\n </wx-list-detail>\n </wx-card>\n </wx-list-screen>\n</template>\n\n<style>\n/*\n * What scrolls here is the page.\n *\n * The section used to be as tall as the window, with the rows scrolling inside a box of their\n * own: a second scroller inside the first, its bar running down the middle of the screen, and\n * a wheel that meant one thing over the rows and another an inch to the left. Page after page\n * of the panel scrolls as a page; this one now does too, and the card is as tall as what is\n * in it.\n *\n * The card's corners are still the screen's corners. The two panes inside are square and paint\n * their own background right up to the edge, so without the clip they covered the rounding —\n * four white notches poking out of the card, most visible where the column divider and the\n * bottom rule of the list meet it. `clip` rather than `hidden`: `hidden` would make this a\n * scroll container again, and everything sticky inside would pin itself to a box that never\n * moves (CLAUDE.md §4).\n */\n.wx-inbox > .wx-card__body {\n display: flex;\n flex-direction: column;\n overflow: clip;\n border-radius: inherit;\n}\n\n.wx-inbox__loading {\n padding: var(--wx-space-16);\n}\n\n.wx-inbox__forms {\n padding: var(--wx-space-8) var(--wx-space-12);\n}\n\n/* In the panel the sheet is the column, and it insets what it holds already: a second step\n inside the first stands the same list further from the edge than it stands anywhere else\n (CLAUDE.md §4). */\n.wx-inbox__forms.is-panel {\n padding: 0;\n}\n\n/*\n * A plain list draws its rows edge to edge, which is right until one of them is tinted: the\n * highlight then starts exactly at the first letter and ends exactly at the `···`, so the\n * chosen form reads as a stain rather than as a row, and it sits flush against the rule that\n * divides the two columns. The padding is inside the tint, not around it.\n */\n.wx-inbox__forms.is-plain .wx-sortable-list__row {\n padding-inline: var(--wx-space-8);\n}\n\n/*\n * Air under the rule that carries the column's name, and the rows' own step beside it.\n *\n * The first row started exactly where the line ended, and the first row here is usually the\n * tinted one — so the chosen form read as hanging off the heading rather than as the first of\n * a list. Visible in the dark theme first, where the tint is a shape of its own.\n *\n * The step is the one the rows take inside their tint (above), so the name of the column\n * begins where the names of the forms do and the `+` stands over the row of `···` rather\n * than eight pixels to the right of them. Measured: 338 against 330.\n */\n.wx-inbox__forms.is-plain .wx-sortable-list__head {\n margin-block-end: var(--wx-space-6);\n padding-inline: var(--wx-space-8);\n}\n\n.wx-inbox-form {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-2);\n align-items: flex-start;\n /* The row is the target, so it takes the row: a name of four letters should not leave\n three quarters of the line dead. */\n flex: 1 1 auto;\n min-width: 0;\n padding: 0;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n}\n\n.wx-inbox-form__name {\n display: flex;\n align-items: center;\n gap: var(--wx-space-6);\n min-width: 0;\n max-width: 100%;\n}\n\n/*\n * Switched off: struck through and grey. On the name alone and not on the line it stands in,\n * because what is off is the form — the count beside it is still true, and a decoration set\n * on the row would run through that too and could not be taken off a child. The grey comes\n * from the text's own `tone`, since `WxText` declares its colour on its own element and an\n * inherited one would never reach it (CLAUDE.md §4).\n */\n.wx-inbox-form.is-off .wx-inbox-form__name > .wx-text {\n text-decoration: line-through;\n}\n\n/*\n * The chosen form, marked on the whole row rather than on the name inside it: the row is what\n * was clicked, and a colour on the words alone leaves the grip and the menu looking like they\n * belong to something else. `:has()` because the row is the list's element and the class is\n * ours — the slot cannot reach the element it is drawn into.\n */\n.wx-inbox__forms .wx-sortable-list__row:has(.wx-inbox-form.is-current) {\n background: var(--wx-bg-subtle);\n border-radius: var(--wx-radius-sm);\n}\n\n.wx-inbox-form.is-current {\n color: var(--wx-color-primary);\n}\n\n.wx-inbox-form__count {\n flex: 0 0 auto;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n toast,\n useModal,\n WxButton,\n WxCheckbox,\n WxDialog,\n WxFormItem,\n WxInput,\n WxSelect,\n WxSpace,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport { STATUS_COLORS, type InboxStatus, type StatusColor } from './types'\n\n/**\n * One state, written.\n *\n * The colour is a tone rather than a swatch: the panel has a light theme and a dark one, and\n * a colour picked in one of them is unreadable in the other.\n *\n * Nothing here refuses a second default — the server clears the flag on whoever had it, which\n * is what somebody moving the default from one status to another means, and refusing the save\n * would be the other reading of the same click.\n */\nconst props = defineProps<{ status: InboxStatus | null }>()\n\nconst { resolve, dismiss, open } = useModal<InboxStatus>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst key = ref('')\nconst title = ref<LocalizedValue>({})\nconst color = ref<StatusColor>('default')\nconst isDefault = ref(false)\nconst isSpam = ref(false)\nconst isClosed = ref(false)\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nwatch(\n () => props.status,\n (status) => {\n key.value = status?.key ?? ''\n title.value = { ...(status?.title ?? {}) }\n color.value = status?.color ?? 'default'\n isDefault.value = status?.is_default ?? false\n isSpam.value = status?.is_spam ?? false\n isClosed.value = status?.is_closed ?? false\n errors.value = {}\n },\n { immediate: true },\n)\n\nconst colors = computed(() =>\n STATUS_COLORS.map((one) => ({ value: one, label: t(`panel.color-${one}`) })),\n)\n\nfunction errorOf(field: string): string | undefined {\n return errors.value[field]?.[0]\n}\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n const input = {\n key: key.value.trim(),\n title: title.value,\n color: color.value,\n is_default: isDefault.value,\n is_spam: isSpam.value,\n is_closed: isClosed.value,\n }\n\n try {\n resolve(\n props.status === null\n ? await api.createStatus(input)\n : await api.saveStatus(props.status.id, input),\n )\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog\n v-model:open=\"open\"\n :title=\"status ? t('panel.settings') : t('panel.new-status')\"\n :width=\"520\"\n >\n <div class=\"wx-inbox-status-form\">\n <wx-form-item :label=\"t('panel.title')\" :error=\"errorOf('title')\" required>\n <wx-input v-model=\"title\" localized />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.status-key')\" :error=\"errorOf('key')\" required>\n <wx-input v-model=\"key\" placeholder=\"in-progress\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.status-color')\" :error=\"errorOf('color')\">\n <wx-select v-model=\"color\" :options=\"colors\" />\n </wx-form-item>\n\n <div class=\"wx-inbox-status-form__checks\">\n <wx-checkbox v-model=\"isDefault\" :label=\"t('panel.status-default')\" />\n <wx-checkbox v-model=\"isSpam\" :label=\"t('panel.status-spam')\" />\n <wx-checkbox v-model=\"isClosed\" :disabled=\"isSpam\" :label=\"t('panel.status-closed')\" />\n </div>\n </div>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">{{ t('panel.save') }}</wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-inbox-status-form {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n\n.wx-inbox-status-form__checks {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-16);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxListScreen,\n WxRowMenu,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n localizedValue,\n toast,\n useLocales,\n WxBadge,\n WxEmpty,\n WxSortableList,\n WxText,\n} from '@webx-ui/core'\nimport StatusDialog from './StatusDialog.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxStatus } from './types'\n\n/**\n * The states a submission can be in (§2.11).\n *\n * Rows rather than an enum, because every panel ends up wanting its own words — and the flags\n * are what the section reads, not the keys, so renaming \"New\" to whatever this client calls\n * it keeps it the status a new submission gets.\n *\n * Their order is the order of the tabs over the list of submissions, which is why it is\n * dragged rather than typed.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/inbox' })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst statuses = ref<InboxStatus[]>([])\nconst loading = ref(true)\n\nconst canManage = context.can('inbox.manage')\n\nconst edit = createModal<InboxStatus, { status: InboxStatus | null }>(StatusDialog)\n\nfunction name(status: InboxStatus): string {\n return localizedValue(status.title, locales.active.value, status.key)\n}\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n statuses.value = await api.statuses()\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nvoid load()\n\nasync function open(status: InboxStatus | null): Promise<void> {\n if (await edit({ status })) await load()\n}\n\nasync function remove(status: InboxStatus): Promise<void> {\n const agreed = await confirm({\n title: t('panel.delete-status-title', { status: name(status) }),\n message: t('panel.delete-status-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeStatus(status.id)\n toast.success(t('panel.deleted'))\n await load()\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nfunction actionsFor(status: InboxStatus): RowAction[] {\n if (!canManage) return []\n\n return [\n { key: 'edit', icon: 'edit', label: t('panel.settings'), run: () => void open(status) },\n // A status with submissions in them cannot go: they would have nothing to be in. The\n // line is left out rather than greyed, the way every list of the panel does it.\n ...(status.submissions_count === 0\n ? [\n {\n key: 'delete',\n icon: 'trash' as const,\n label: t('panel.delete'),\n danger: true,\n run: () => void remove(status),\n },\n ]\n : []),\n ]\n}\n\n/* What the section offers. Declared, because on a phone the head folds it into the ···. */\nconst actions = computed<ScreenAction[]>(() =>\n canManage\n ? [\n {\n key: 'new',\n label: t('panel.new-status'),\n icon: 'plus',\n primary: true,\n run: () => void open(null),\n },\n ]\n : [],\n)\n\nasync function reorder(): Promise<void> {\n try {\n await api.sortStatuses(statuses.value.map((status) => status.id))\n } catch (error) {\n toast.danger(message(error, t('panel.reorder-failed')))\n await load()\n }\n}\n</script>\n\n<template>\n <div class=\"wx-inbox-statuses\">\n <wx-list-screen\n :title=\"t('panel.statuses')\"\n :back=\"props.base\"\n :back-label=\"t('panel.forms')\"\n :actions=\"actions\"\n >\n <wx-empty v-if=\"!loading && statuses.length === 0\" :title=\"t('panel.no-statuses')\" />\n\n <wx-sortable-list\n v-else\n v-model=\"statuses\"\n plain\n item-key=\"id\"\n :item-label=\"name\"\n :disabled=\"!canManage\"\n :aria-label=\"t('panel.statuses')\"\n @move=\"reorder\"\n >\n <template #default=\"{ item }\">\n <div class=\"wx-inbox-status\">\n <wx-badge :type=\"item.color\">{{ name(item) }}</wx-badge>\n\n <wx-text size=\"sm\" tone=\"muted\" truncate>\n <code>{{ item.key }}</code>\n <template v-if=\"item.is_default\"> · {{ t('panel.status-default') }}</template>\n <template v-if=\"item.is_spam\"> · {{ t('panel.status-spam') }}</template>\n <template v-else-if=\"item.is_closed\"> · {{ t('panel.status-closed') }}</template>\n <template v-if=\"item.submissions_count\">\n · {{ t('panel.in-use') }} ({{ item.submissions_count }})\n </template>\n </wx-text>\n </div>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-row-menu :actions=\"actionsFor(item)\" :label=\"name(item)\" />\n </template>\n </wx-sortable-list>\n </wx-list-screen>\n </div>\n</template>\n\n<style scoped>\n.wx-inbox-statuses {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--wx-space-12);\n}\n\n.wx-inbox-statuses > .wx-list-screen {\n align-self: stretch;\n}\n\n.wx-inbox-status {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n flex: 1 1 auto;\n min-width: 0;\n flex-wrap: wrap;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxDate,\n WxNotes,\n WxScreenHead,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n localizedValue,\n toast,\n useLocales,\n WxAction,\n WxAlert,\n WxBadge,\n WxCard,\n WxDescriptions,\n WxDescriptionsItem,\n WxEmpty,\n WxFileCard,\n WxSelect,\n WxSkeleton,\n WxTab,\n WxTabs,\n WxText,\n WxTimeline,\n WxTimelineItem,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxRecipient, InboxStatus, InboxSubmission, SubmissionEvent } from './types'\n\n/**\n * One submission, on a screen of its own (§11).\n *\n * A dialog over the list would have kept the filters under the reader's hand, and it was\n * rejected for one reason: a submission needs an address somebody can send. It goes into the\n * mail to whoever deals with it, it gets pasted into a chat, an agent links to it. What the\n * dialog would have given back is paid for here instead — the list's whole state travels in\n * the address, so the way out lands exactly where the reader was, and the arrows walk the same\n * filtered pile.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/inbox' })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* The notes feed is the panel's own, and so is the word for it: a second \"Notes\" in this\n module's dictionary would be the same line translated twice. */\nconst panel = useTranslate('webx-admin')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst submission = ref<InboxSubmission | null>(null)\nconst statuses = ref<InboxStatus[]>([])\nconst admins = ref<InboxRecipient[]>([])\nconst loading = ref(true)\n\nconst canUpdate = computed(() => context.can('inbox.update'))\n\nconst id = computed(() => Number(route.params.id))\n\n/** Everything the list was looking at, carried along so the arrows walk the same pile. */\nconst filter = computed(() => ({\n view: typeof route.query.view === 'string' ? route.query.view : undefined,\n search: typeof route.query.search === 'string' ? route.query.search : undefined,\n assignee: typeof route.query.assignee === 'string' ? route.query.assignee : undefined,\n}))\n\n/** Back to the list, on the form, the tab and the page it was left at. */\nconst backTo = computed(() => ({ path: props.base, query: { ...route.query } }))\n\nconst statusOptions = computed(() =>\n statuses.value.map((status) => ({ value: status.id, label: name(status) })),\n)\n\n/* Nobody is not an option in the list but the empty state of the control: a select whose\n first line means \"none\" is one somebody picks by accident, and `clearable` already says\n it. */\nconst assigneeOptions = computed(() =>\n admins.value.map((admin) => ({ value: admin.id, label: admin.name })),\n)\n\nfunction name(status: InboxStatus): string {\n return localizedValue(status.title, locales.active.value, status.key)\n}\n\nconst heading = computed(() => t('panel.submission', { id: String(id.value) }))\n\nconst formTitle = computed(() => {\n const form = submission.value?.form\n\n return form === undefined\n ? ''\n : localizedValue(form.title ?? {}, locales.active.value, form.slug ?? '')\n})\n\n/**\n * Where a reply goes.\n *\n * The form says which field holds the sender's address (`email_field`); without one, the first\n * answer that was asked as an e-mail is the honest guess, and where there is none the button\n * is simply not there — a `mailto:` with nothing after it opens an empty window.\n */\nconst replyTo = computed(() => {\n const values = submission.value?.values ?? []\n const answer = values.find((value) => value.type === 'email' && (value.value ?? '') !== '')\n\n return answer?.value ?? null\n})\n\nconst mailto = computed(() => {\n if (replyTo.value === null) return null\n\n const subject = encodeURIComponent(`${formTitle.value} — ${heading.value}`)\n\n return `mailto:${replyTo.value}?subject=${subject}`\n})\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n submission.value = await api.submission(id.value, filter.value)\n } catch (error) {\n toast.danger(message(error))\n void router.replace(backTo.value)\n } finally {\n loading.value = false\n }\n}\n\nasync function lists(): Promise<void> {\n try {\n statuses.value = await api.statuses()\n\n // Only where there is something to do with them: assigning is `inbox.update`, and the\n // list of administrators is not a reader's business.\n if (canUpdate.value) {\n admins.value = await api.recipients()\n }\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\n/* The arrows change the address without leaving the screen, so the record has to follow it. */\nwatch(id, () => void load(), { immediate: true })\n\nvoid lists()\n\nasync function save(input: { status_id?: number; assignee_id?: number | null }): Promise<void> {\n try {\n submission.value = await api.saveSubmission(id.value, input)\n toast.success(t('panel.saved'))\n } catch (error) {\n toast.danger(message(error))\n await load()\n }\n}\n\nfunction onStatus(value: unknown): void {\n if (typeof value === 'number') void save({ status_id: value })\n}\n\nfunction onAssignee(value: unknown): void {\n void save({ assignee_id: typeof value === 'number' ? value : null })\n}\n\n/*\n * What the screen offers: answering it, and — behind the `···` — what is done to the pile it\n * came from. Replying is the main action by §18.3, so it is the one that keeps a button of its\n * own once the head runs out of room.\n */\nconst actions = computed<ScreenAction[]>(() => {\n const list: ScreenAction[] = []\n\n if (mailto.value) {\n list.push({\n key: 'reply',\n label: t('panel.reply'),\n icon: 'mail',\n primary: true,\n href: mailto.value,\n target: '_self',\n })\n }\n\n if (canUpdate.value && submission.value !== null) {\n list.push(\n {\n key: 'unread',\n icon: 'eye-off',\n label: t('panel.mark-unread'),\n menu: true,\n run: () => void unread(),\n },\n {\n key: 'delete',\n icon: 'trash',\n label: t('panel.delete'),\n danger: true,\n run: () => void remove(),\n },\n )\n }\n\n return list\n})\n\nasync function unread(): Promise<void> {\n try {\n await api.massSubmissions({ ids: [id.value], action: 'unread' })\n // Straight back to the list: a submission marked unread and then left open is one the\n // next request would mark read again.\n void router.push(backTo.value)\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function remove(): Promise<void> {\n const agreed = await confirm({\n title: t('panel.delete-submission-title'),\n message: t('panel.delete-submission-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeSubmission(id.value)\n toast.success(t('panel.deleted'))\n void router.push(backTo.value)\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nfunction go(to: number | null): void {\n if (to === null) return\n\n void router.push({ path: `${props.base}/submissions/${to}`, query: { ...route.query } })\n}\n\n/**\n * A status the log names, in the words the panel calls it by.\n *\n * The log stores the key on purpose — read months later, the row it pointed at may have been\n * renamed or deleted, and history must not be rewritten by either. So the key is translated\n * where the panel still has that status, and shown as it stands where it does not: `spam` is\n * a poorer line than \"Спам\", and an invented one would be worse than both.\n */\nfunction statusName(key: string): string {\n const status = statuses.value.find((one) => one.key === key)\n\n return status === undefined ? key : name(status)\n}\n\n/** One line of the log, in words rather than as a pair of columns. */\nfunction line(event: SubmissionEvent): string {\n switch (event.type) {\n case 'created':\n return t('panel.event-created')\n case 'status':\n return t('panel.event-status', { to: statusName(event.to ?? '') })\n case 'assignee':\n return event.to === null || event.to === ''\n ? t('panel.event-unassigned')\n : t('panel.event-assignee', { to: event.to })\n case 'note':\n return t('panel.event-note')\n case 'notified':\n return t('panel.event-notified')\n default:\n return event.type\n }\n}\n\nfunction kilobytes(size: number): string {\n return `${Math.max(1, Math.round(size / 1024))} KB`\n}\n\n/** The metadata worth showing, in the order somebody reads it, with the empty ones left out. */\nconst details = computed(() => {\n const meta = submission.value?.meta ?? {}\n\n const rows: { label: string; value: string; link?: boolean }[] = []\n\n if (typeof meta.page === 'string' && meta.page !== '') {\n rows.push({ label: t('panel.meta-page'), value: meta.page, link: true })\n }\n\n // Where on that page the form stood — the footer, an article — beside the page it answers.\n const placement = submission.value?.placement\n if (typeof placement === 'string' && placement !== '') {\n rows.push({ label: t('panel.meta-placement'), value: placement })\n }\n\n if (typeof meta.referrer === 'string' && meta.referrer !== '') {\n rows.push({ label: t('panel.meta-referrer'), value: meta.referrer, link: true })\n }\n\n for (const [key, value] of Object.entries(meta.utm ?? {})) {\n rows.push({ label: key, value: String(value) })\n }\n\n if (typeof meta.locale === 'string' && meta.locale !== '') {\n rows.push({ label: t('panel.meta-locale'), value: meta.locale })\n }\n\n if (typeof meta.ip === 'string' && meta.ip !== '') {\n rows.push({ label: t('panel.meta-ip'), value: meta.ip })\n }\n\n if (typeof meta.user_agent === 'string' && meta.user_agent !== '') {\n rows.push({ label: t('panel.meta-agent'), value: meta.user_agent })\n }\n\n return rows\n})\n</script>\n\n<template>\n <div class=\"wx-submission\">\n <wx-screen-head :title=\"heading\" :subtitle=\"formTitle\" :back=\"backTo\" :actions=\"actions\">\n <!--\n The same pile the reader was looking at, one step at a time. Not an action with a word\n on it, so not something the head can fold into a menu: an arrow with nowhere to go is\n disabled rather than hidden, because a control that changes shape at the ends is one\n that moves under the hand.\n -->\n <template #extra>\n <wx-action\n icon=\"chevron-left\"\n size=\"lg\"\n :title=\"t('panel.previous')\"\n :disabled=\"!submission?.previous_id\"\n @click=\"go(submission?.previous_id ?? null)\"\n />\n <wx-action\n icon=\"chevron-right\"\n size=\"lg\"\n :title=\"t('panel.next')\"\n :disabled=\"!submission?.next_id\"\n @click=\"go(submission?.next_id ?? null)\"\n />\n </template>\n </wx-screen-head>\n\n <wx-skeleton v-if=\"loading\" :rows=\"6\" />\n\n <div v-else-if=\"submission\" class=\"wx-submission__panes\">\n <div class=\"wx-submission__main\">\n <wx-card :title=\"t('panel.answers')\">\n <wx-empty\n v-if=\"submission.values.length === 0\"\n size=\"sm\"\n :description=\"t('panel.no-answers')\"\n />\n <!-- The labels are the snapshot written when it arrived, never the field's current\n words: a submission from a year ago has to read as it did (§2.2). -->\n <wx-descriptions v-else :columns=\"1\" layout=\"vertical\">\n <wx-descriptions-item\n v-for=\"value in submission.values\"\n :key=\"value.id\"\n :label=\"value.label ?? value.name\"\n >\n <p class=\"wx-submission__value\">{{ value.value || '—' }}</p>\n </wx-descriptions-item>\n </wx-descriptions>\n </wx-card>\n\n <wx-card v-if=\"submission.files.length > 0\" :title=\"t('panel.attachments')\">\n <div class=\"wx-submission__files\">\n <!-- Through the panel and not from the disk: the bytes are behind the same\n permission as the submission, for as long as the reader has it (§8). -->\n <wx-file-card\n v-for=\"file in submission.files\"\n :key=\"file.id\"\n :name=\"file.name\"\n :type=\"file.mime ?? undefined\"\n :download-url=\"file.url\"\n :download-label=\"t('panel.download')\"\n size=\"sm\"\n >\n <template #meta>{{ kilobytes(file.size) }}</template>\n </wx-file-card>\n </div>\n </wx-card>\n\n <!--\n Everything about the submission rather than in it, behind one strip.\n\n Three cards stacked down a column is three headings to read past before the eye gets\n to the one that was wanted, and on a phone it is three screens of scrolling. They are\n not read together — a note is written while replying, the log is opened when\n something looks wrong, the metadata once — so only one of them is ever the answer.\n Pills rather than a line, and inside the card rather than over it: this is one card\n changing its contents, not a place in the panel that can be navigated to. The strip is\n the card's heading — which is why there is no other one.\n -->\n <wx-card class=\"wx-submission__more\">\n <wx-tabs variant=\"pill\" :aria-label=\"heading\">\n <wx-tab value=\"notes\" :label=\"panel('notes.title')\">\n <!-- The feed is the panel's own, not this module's: the same one will hang off\n an order and a client (§2.17). Its heading is the tab. -->\n <wx-notes\n :id=\"submission.id\"\n type=\"inbox_submission\"\n title=\"\"\n :can=\"canUpdate\"\n @change=\"load\"\n />\n </wx-tab>\n\n <wx-tab value=\"log\" :label=\"t('panel.log')\">\n <wx-timeline size=\"sm\">\n <wx-timeline-item v-for=\"event in submission.events\" :key=\"event.id\">\n <!-- What happened on one line and who did it when on the next: three inline\n pieces in a row run into each other, and a log is read down. -->\n <wx-text size=\"sm\" as=\"p\" class=\"wx-submission__event\">{{ line(event) }}</wx-text>\n <p class=\"wx-submission__by\">\n <wx-text size=\"sm\" tone=\"muted\">\n {{ event.author?.name ?? t('panel.system') }}\n </wx-text>\n <wx-date :value=\"event.created_at\" />\n </p>\n </wx-timeline-item>\n </wx-timeline>\n </wx-tab>\n\n <wx-tab value=\"details\" :label=\"t('panel.details')\">\n <div class=\"wx-submission__fields\">\n <wx-descriptions :columns=\"1\" layout=\"vertical\" size=\"sm\">\n <wx-descriptions-item :label=\"t('panel.received')\">\n <wx-date :value=\"submission.created_at\" tone=\"default\" />\n </wx-descriptions-item>\n <wx-descriptions-item :label=\"t('panel.meta-source')\">\n <wx-badge :type=\"submission.source === 'panel' ? 'info' : 'default'\">\n {{\n submission.source === 'panel'\n ? t('panel.source-panel')\n : t('panel.source-web')\n }}\n </wx-badge>\n </wx-descriptions-item>\n <wx-descriptions-item v-for=\"row in details\" :key=\"row.label\" :label=\"row.label\">\n <a v-if=\"row.link\" :href=\"row.value\" target=\"_blank\" rel=\"noreferrer\">{{\n row.value\n }}</a>\n <span v-else class=\"wx-submission__detail\">{{ row.value }}</span>\n </wx-descriptions-item>\n </wx-descriptions>\n\n <!-- An unsent notification is a mark on the submission, not a lost one\n (§2.10), and the only place it is ever said out loud is here. -->\n <wx-alert v-if=\"submission.notify_error\" type=\"warning\" :closable=\"false\">\n {{ t('panel.notify-failed') }}\n </wx-alert>\n <wx-text v-else-if=\"submission.notified_at\" size=\"sm\" tone=\"muted\">\n {{ t('panel.notified') }}\n </wx-text>\n <wx-text v-else size=\"sm\" tone=\"muted\">{{ t('panel.not-notified') }}</wx-text>\n </div>\n </wx-tab>\n </wx-tabs>\n </wx-card>\n </div>\n\n <aside class=\"wx-submission__aside\">\n <wx-card>\n <div class=\"wx-submission__fields\">\n <label class=\"wx-submission__field\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.status') }}</wx-text>\n <wx-select\n :model-value=\"submission.status?.id ?? null\"\n :options=\"statusOptions\"\n :disabled=\"!canUpdate\"\n @update:model-value=\"onStatus\"\n />\n </label>\n\n <label class=\"wx-submission__field\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.assignee') }}</wx-text>\n <wx-select\n :model-value=\"submission.assignee?.id ?? null\"\n :options=\"assigneeOptions\"\n :disabled=\"!canUpdate\"\n clearable\n :placeholder=\"t('panel.unassigned')\"\n @update:model-value=\"onAssignee\"\n />\n </label>\n </div>\n </wx-card>\n </aside>\n </div>\n </div>\n</template>\n\n<style scoped>\n.wx-submission {\n display: flex;\n flex-direction: column;\n /* The panel says how far apart things stand, and it says something different on a phone\n than on a desktop (8, 12, 16). Writing the desktop number here is what made this screen\n the one place in the panel with desktop air on a 375px screen. */\n gap: var(--wx-gap, var(--wx-space-16));\n min-width: 0;\n /* The panes below decide their own layout from the width of the screen rather than of the\n window: the panel has a sidebar, and the window knows nothing about it. */\n container-type: inline-size;\n}\n\n.wx-submission__panes {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n min-width: 0;\n}\n\n.wx-submission__main,\n.wx-submission__aside {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n min-width: 0;\n}\n\n/* The answers are what the screen is for, so they take the room; everything about the\n submission rather than in it stands beside them. */\n@container (min-width: 900px) {\n .wx-submission__panes {\n flex-direction: row;\n align-items: flex-start;\n }\n\n .wx-submission__main {\n flex: 1 1 auto;\n }\n\n .wx-submission__aside {\n flex: 0 0 320px;\n max-width: 320px;\n }\n}\n\n.wx-submission__value {\n margin: 0;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.wx-submission__detail {\n overflow-wrap: anywhere;\n}\n\n.wx-submission__event {\n margin: 0;\n}\n\n.wx-submission__by {\n display: flex;\n align-items: baseline;\n gap: var(--wx-space-6);\n flex-wrap: wrap;\n margin: 0;\n}\n\n.wx-submission__files {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-8);\n}\n\n.wx-submission__fields {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n\n.wx-submission__field {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-4);\n}\n</style>\n","import type { AdminModule } from '@webx-ui/module-admin'\nimport FormEditorPage from './FormEditorPage.vue'\nimport InboxPage from './InboxPage.vue'\nimport StatusesPage from './StatusesPage.vue'\nimport SubmissionPage from './SubmissionPage.vue'\n\nexport interface InboxOptions {\n /** Where the section lives inside the panel. */\n path?: string\n /**\n * Whether the panel opens on this section.\n *\n * On by default, and that is the point of the module: a panel with an inbox is a panel\n * somebody opens in the morning to see what came in overnight, and the pages, the blocks\n * and the settings are what they do afterwards (§2.18). A panel whose front page is\n * something else says so here.\n */\n landing?: boolean\n}\n\n/**\n * Forms and submissions as a section of the panel.\n *\n * The id matches the module the server reports, which is what makes the entry appear in the\n * navigation: the section shows up when both halves are installed, and stays out of the way\n * when only one is.\n */\nexport function inbox(options: InboxOptions = {}): AdminModule {\n const path = options.path ?? '/inbox'\n\n return {\n id: 'inbox',\n path,\n landing: options.landing ?? true,\n routes: [\n // The section's own path travels as a prop, so a panel that mounted it somewhere else\n // still links between its screens correctly.\n { path, name: 'webx.inbox', component: InboxPage, props: { base: path } },\n {\n path: `${path}/statuses`,\n name: 'webx.inbox.statuses',\n component: StatusesPage,\n props: { base: path },\n },\n {\n path: `${path}/forms/:id(\\\\d+)`,\n name: 'webx.inbox.form',\n component: FormEditorPage,\n props: { base: path },\n },\n // A submission has an address of its own, not a dialog over the list (§11): it goes in\n // the mail to whoever deals with it, it gets pasted into a chat, an agent links to it.\n {\n path: `${path}/submissions/:id(\\\\d+)`,\n name: 'webx.inbox.submission',\n component: SubmissionPage,\n props: { base: path },\n },\n ],\n }\n}\n"],"names":["model","_useModel","__props","props","locales","useLocales","active","computed","chosen","locale","text","value","next","base","_unref","_createBlock","WxLocales","_createVNode","WxRichText","$event","createInboxApi","admin","data","body","nothing","id","input","ids","formId","query","listQuery","fields","search","key","suffix","inboxMessages","seeded","useInboxMessages","i18n","useAdmin","FIELD_TYPES","STATUS_COLORS","resolve","dismiss","open","useModal","context","api","t","useTranslate","message","useErrorText","saving","ref","errors","name","type","title","placeholder","help","options","isEnabled","isRequired","isFullsize","inTable","watch","field","types","one","hasChoices","choices","extensions","set","addChoice","removeChoice","index","_","at","setChoice","patch","choice","errorOf","save","error","toast","WxDialog","WxSpace","WxButton","_createElementVNode","_hoisted_1","_hoisted_2","WxFormItem","WxSelect","WxInput","_createElementBlock","_Fragment","LocalizedRichText","_cache","_openBlock","_hoisted_3","WxText","_renderList","label","WxAction","WxIcon","_createTextVNode","_hoisted_4","WxInputNumber","WxDatePicker","WxTagsInput","WxCheckbox","_hoisted_5","edit","createModal","FieldDialog","localizedValue","marks","empty","saved","remove","confirm","actionsFor","reorder","WxCard","WxEmpty","WxSortableList","_withCtx","item","_toDisplayString","WxBadge","WxRowMenu","option","fallback","honeypot","seconds","throttle","captcha","captchas","WxSwitch","blade","block","columns","listed","copy","WxTable","row","settings","heading","submit","redirect","admins","recipients","emailField","onMounted","adminOptions","emailOptions","isAdmin","recipient","add","setAdmin","setEmail","email","WxAlert","route","useRoute","router","useRouter","form","loading","reactive","canManage","backTo","load","loaded","WxSkeleton","WxScreenHead","WxTabs","WxTab","FormGeneral","FieldList","FormNotifications","FormAntispam","FormEmbed","WxActionBar","slug","values","asked","hasFiles","WxTextarea","WxRadioGroup","WxCheckboxGroup","CARDS","emit","__emit","root","useTemplateRef","width","useElementWidth","asCards","cardsBelow","panel","page","statuses","selected","moving","canUpdate","SubmissionCreateDialog","view","placementOptions","placement","hasPlacements","applied","narrow","views","counts","items","status","answer","column","answers","rowMenuWidth","emptyText","statusOptions","formName","state","onState","wanted","statusList","mass","moveTo","statusId","action","byHand","made","exportHref","actions","__expose","_keys","rows","WxAvatar","WxTooltip","WxDate","WxEntityCard","WxFilterChips","forms","pane","columnInline","formsOpen","create","FormCreateDialog","module","current","choose","close","duplicate","rest","list","WxListScreen","WxListDetail","inline","_normalizeClass","WxIndicator","SubmissionList","color","isDefault","isSpam","isClosed","colors","StatusDialog","submission","filter","assigneeOptions","formTitle","replyTo","mailto","subject","lists","onStatus","onAssignee","unread","go","to","statusName","line","event","kilobytes","size","details","meta","WxDescriptions","WxDescriptionsItem","file","WxFileCard","WxNotes","WxTimeline","WxTimelineItem","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","inbox","path","InboxPage","StatusesPage","FormEditorPage","SubmissionPage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/LocalizedRichText.vue","../src/api.ts","../src/messages.ts","../src/i18n.ts","../src/types.ts","../src/FieldDialog.vue","../src/FieldList.vue","../src/options.ts","../src/FormAntispam.vue","../src/FormEmbed.vue","../src/FormGeneral.vue","../src/recipients.ts","../src/FormNotifications.vue","../src/FormEditorPage.vue","../src/FormCreateDialog.vue","../src/SubmissionCreateDialog.vue","../src/SubmissionList.vue","../src/InboxPage.vue","../src/StatusDialog.vue","../src/StatusesPage.vue","../src/SubmissionPage.vue","../src/module.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useLocales, WxLocales, WxRichText, type LocalizedValue } from '@webx-ui/core'\n\n/**\n * Rich text in every language the site publishes in.\n *\n * `WxRichText` holds one string, the way `WxInput` does without `localized`; what a localized\n * field adds is the picker and the map underneath it. This is that, for the one place in this\n * module that needs it — the thank-you, which is printed raw on the site and is therefore\n * written where formatting is possible.\n *\n * With no content languages at all — a panel assembled by hand, a test — the value stays a\n * plain string, which is exactly what `useLocalized` does in the same situation and what the\n * server accepts for a form written before the site had a second language.\n */\nconst model = defineModel<LocalizedValue | string>({ default: '' })\n\nconst props = withDefaults(defineProps<{ placeholder?: string; minHeight?: string }>(), {\n placeholder: undefined,\n minHeight: '160px',\n})\n\nconst locales = useLocales()\n\nconst active = computed(() => {\n const chosen = locales.active.value\n const known = locales.list.value.some((locale) => locale.code === chosen)\n\n return known ? chosen : (locales.list.value[0]?.code ?? '')\n})\n\nconst text = computed({\n get: () => {\n const value = model.value\n\n if (typeof value === 'string') {\n // A string under a localized field belongs to the first language: that is where the\n // words were written, and hiding them would look like losing them.\n return active.value === '' || active.value === locales.list.value[0]?.code ? value : ''\n }\n\n return value[active.value] ?? ''\n },\n set: (next: string) => {\n if (active.value === '') {\n model.value = next\n\n return\n }\n\n const base = typeof model.value === 'string' ? { [active.value]: model.value } : model.value\n\n model.value = { ...base, [active.value]: next }\n },\n})\n</script>\n\n<template>\n <wx-locales v-if=\"locales.list.value.length > 0\">\n <wx-rich-text v-model=\"text\" :placeholder=\"props.placeholder\" :min-height=\"props.minHeight\" />\n </wx-locales>\n\n <wx-rich-text\n v-else\n v-model=\"text\"\n :placeholder=\"props.placeholder\"\n :min-height=\"props.minHeight\"\n />\n</template>\n","import type { AdminContext } from '@webx-ui/module-admin'\nimport type {\n FieldInput,\n FormInput,\n InboxField,\n InboxForm,\n InboxRecipient,\n InboxStatus,\n InboxSubmission,\n StatusInput,\n SubmissionInput,\n SubmissionMassInput,\n SubmissionQuery,\n SubmissionsPage,\n} from './types'\n\nexport interface InboxApi {\n /** Every form, in the order of the column, with what is waiting in each. */\n forms(): Promise<InboxForm[]>\n /** One form with its fields — what the editor opens. */\n form(id: number): Promise<InboxForm>\n createForm(input: FormInput): Promise<InboxForm>\n saveForm(id: number, input: FormInput): Promise<InboxForm>\n /** Refused with a 422 when the form has submissions: it is switched off, not deleted. */\n removeForm(id: number): Promise<void>\n /** A copy, switched off, with the questions and none of the answers. */\n duplicateForm(id: number): Promise<InboxForm>\n sortForms(ids: number[]): Promise<void>\n\n fields(formId: number): Promise<InboxField[]>\n createField(formId: number, input: FieldInput): Promise<InboxField>\n saveField(id: number, input: FieldInput): Promise<InboxField>\n /** Softly: the answers already given through it keep reading. */\n removeField(id: number): Promise<void>\n sortFields(formId: number, ids: number[]): Promise<void>\n\n statuses(): Promise<InboxStatus[]>\n createStatus(input: StatusInput): Promise<InboxStatus>\n saveStatus(id: number, input: StatusInput): Promise<InboxStatus>\n /** Refused with a 422 while submissions are still in it. */\n removeStatus(id: number): Promise<void>\n sortStatuses(ids: number[]): Promise<void>\n\n /** The administrators a form can be told to write to: the ones who may read the section. */\n recipients(): Promise<InboxRecipient[]>\n\n /** One form's submissions, with the columns of the list and the counts of its tabs. */\n submissions(formId: number, query?: SubmissionQuery): Promise<SubmissionsPage>\n /**\n * One of them, open. Opening it marks it read.\n *\n * The filters travel with it so that the neighbours it reports are the ones either side of\n * it in the list somebody was actually looking at.\n */\n submission(id: number, query?: SubmissionQuery): Promise<InboxSubmission>\n /** Typed in by hand — a call that came by telephone. `fields` is by machine name. */\n createSubmission(formId: number, fields: Record<string, unknown>): Promise<InboxSubmission>\n saveSubmission(id: number, input: SubmissionInput): Promise<InboxSubmission>\n removeSubmission(id: number): Promise<void>\n /** The notification once more, to whoever the form names now. Refused for a form naming nobody. */\n notifySubmission(id: number): Promise<InboxSubmission>\n /** A pile moved, marked or thrown away at once. */\n massSubmissions(input: SubmissionMassInput): Promise<{ count: number }>\n /**\n * Where the spreadsheet is. An address rather than a request: a download is the browser's\n * own job, and fetching a file into memory to hand it back to the browser is work for\n * nothing.\n */\n exportUrl(formId: number, query?: SubmissionQuery): string\n}\n\n/** Everything under `/inbox`, below the panel's API path. */\nexport function createInboxApi(admin: AdminContext): InboxApi {\n const base = `${admin.apiPath}/inbox`\n const data = <T>(body: { data: T }): T => body.data\n const nothing = (): void => undefined\n\n return {\n forms: () => admin.http.get<{ data: InboxForm[] }>(`${base}/forms`).then(data),\n form: (id) => admin.http.get<{ data: InboxForm }>(`${base}/forms/${id}`).then(data),\n createForm: (input) => admin.http.post<{ data: InboxForm }>(`${base}/forms`, input).then(data),\n saveForm: (id, input) =>\n admin.http.put<{ data: InboxForm }>(`${base}/forms/${id}`, input).then(data),\n removeForm: (id) => admin.http.delete(`${base}/forms/${id}`).then(nothing),\n duplicateForm: (id) =>\n admin.http.post<{ data: InboxForm }>(`${base}/forms/${id}/duplicate`, {}).then(data),\n sortForms: (ids) => admin.http.post(`${base}/forms/sorting`, { ids }).then(nothing),\n\n fields: (formId) =>\n admin.http.get<{ data: InboxField[] }>(`${base}/forms/${formId}/fields`).then(data),\n createField: (formId, input) =>\n admin.http.post<{ data: InboxField }>(`${base}/forms/${formId}/fields`, input).then(data),\n saveField: (id, input) =>\n admin.http.put<{ data: InboxField }>(`${base}/fields/${id}`, input).then(data),\n removeField: (id) => admin.http.delete(`${base}/fields/${id}`).then(nothing),\n sortFields: (formId, ids) =>\n admin.http.post(`${base}/forms/${formId}/fields/sorting`, { ids }).then(nothing),\n\n statuses: () => admin.http.get<{ data: InboxStatus[] }>(`${base}/statuses`).then(data),\n createStatus: (input) =>\n admin.http.post<{ data: InboxStatus }>(`${base}/statuses`, input).then(data),\n saveStatus: (id, input) =>\n admin.http.put<{ data: InboxStatus }>(`${base}/statuses/${id}`, input).then(data),\n removeStatus: (id) => admin.http.delete(`${base}/statuses/${id}`).then(nothing),\n sortStatuses: (ids) => admin.http.post(`${base}/statuses/sorting`, { ids }).then(nothing),\n\n recipients: () => admin.http.get<{ data: InboxRecipient[] }>(`${base}/recipients`).then(data),\n\n submissions: (formId, query = {}) =>\n admin.http\n .get<{\n data: SubmissionsPage['data']\n meta: Omit<SubmissionsPage, 'data' | 'columns' | 'counts' | 'placements'>\n columns: SubmissionsPage['columns']\n counts: SubmissionsPage['counts']\n placements?: SubmissionsPage['placements']\n }>(`${base}/forms/${formId}/submissions`, { query: listQuery(query) })\n .then((body) => ({\n ...body.meta,\n data: body.data,\n columns: body.columns,\n counts: body.counts,\n // Optional on the wire: a server from before placements answers without them.\n placements: body.placements ?? [],\n })),\n\n submission: (id, query = {}) =>\n admin.http\n .get<{ data: InboxSubmission }>(`${base}/submissions/${id}`, { query: listQuery(query) })\n .then(data),\n\n createSubmission: (formId, fields) =>\n admin.http\n .post<{ data: InboxSubmission }>(`${base}/forms/${formId}/submissions`, { fields })\n .then(data),\n\n saveSubmission: (id, input) =>\n admin.http.put<{ data: InboxSubmission }>(`${base}/submissions/${id}`, input).then(data),\n\n removeSubmission: (id) => admin.http.delete(`${base}/submissions/${id}`).then(nothing),\n\n notifySubmission: (id) =>\n admin.http.post<{ data: InboxSubmission }>(`${base}/submissions/${id}/notify`).then(data),\n\n massSubmissions: (input) =>\n admin.http.post<{ data: { count: number } }>(`${base}/submissions/mass`, input).then(data),\n\n exportUrl: (formId, query = {}) => {\n const search = new URLSearchParams()\n\n for (const [key, value] of Object.entries(listQuery(query))) {\n if (value !== undefined && value !== null && value !== '') {\n search.set(key, String(value))\n }\n }\n\n const suffix = search.toString()\n\n return `${base}/forms/${formId}/submissions/export${suffix === '' ? '' : `?${suffix}`}`\n },\n }\n}\n\n/**\n * The filters as query parameters, with the empty ones left out.\n *\n * `page` and `per_page` go too, because the same shape is what the export is asked for — the\n * server ignores them there, and a second almost-identical builder is a second thing to get\n * out of step.\n */\nfunction listQuery(query: SubmissionQuery): Record<string, string | number | undefined> {\n return {\n view: query.view === undefined || query.view === '' ? undefined : query.view,\n search: query.search === undefined || query.search === '' ? undefined : query.search,\n assignee: query.assignee ?? undefined,\n placement: query.placement ?? undefined,\n sort: query.sort ?? undefined,\n page: query.page,\n per_page: query.per_page,\n }\n}\n","import type { Messages } from '@webx-ui/module-admin'\n\n/**\n * What this package says, in English — the same keys `webx-ui/module-inbox` ships as\n * `lang/en/*.php`, so a key never reaches the screen while the dictionary is still on its way.\n *\n * The server's dictionary wins over these. There is no second dictionary inside this package:\n * a module translated into ten languages with an English dialog in the middle of it is worse\n * than one that is not translated at all, and the only way to notice that gap is to compare\n * the two lists — which `messages.test.ts` does.\n *\n * Placeholders are Laravel's, `:like-this`: the same line is read from a PHP file and from\n * here, and only one of the two spellings can be right.\n */\nexport const inboxMessages: Record<string, Messages> = {\n module: {\n title: 'Inbox',\n },\n\n panel: {\n forms: 'Forms',\n 'new-form': 'New form',\n 'no-forms': 'No forms yet.',\n 'no-forms-help': 'A form is a few questions and a list of who hears the answers.',\n unread: 'Unread',\n submissions: 'Submissions in all',\n off: 'Off',\n settings: 'Settings',\n duplicate: 'Duplicate',\n delete: 'Delete',\n 'delete-form-title': 'Delete “:form”?',\n 'delete-form-text': 'The form and its questions go. This cannot be undone.',\n cancel: 'Cancel',\n save: 'Save',\n saved: 'Saved.',\n deleted: 'Deleted.',\n duplicated: 'A copy was made.',\n failed: 'Some values were not accepted. Check the highlighted fields.',\n 'reorder-failed': 'The new order could not be saved.',\n 'new-form-title': 'New form',\n title: 'Title',\n slug: 'Address',\n 'slug-help': 'What the form is called on the site and where it posts.',\n 'is-enabled': 'Active',\n 'is-enabled-help': 'A form that is off is neither drawn nor accepted.',\n 'tab-general': 'General',\n 'tab-fields': 'Fields',\n 'tab-notifications': 'Notifications',\n 'tab-antispam': 'Antispam',\n 'tab-embed': 'Embedding',\n 'after-sending': 'After sending',\n 'thank-you-heading': 'Heading',\n 'thank-you-text': 'Text',\n 'submit-text': 'Text on the button',\n redirect: 'Go to this address instead',\n 'redirect-help': 'Left empty, the thank-you takes the form’s place on the page.',\n recipients: 'Who is written to',\n 'recipients-help': 'Nobody here means nobody is told. The submission is kept either way.',\n 'no-recipients': 'Nobody yet.',\n 'add-admin': 'Add an administrator',\n 'add-email': 'Add an address',\n remove: 'Remove',\n 'remove-recipient-title': 'Remove this recipient?',\n 'remove-recipient-text': 'They stop being told when something arrives.',\n 'email-field': 'The field holding the sender’s address',\n 'email-field-help': 'A reply to the notification then goes to whoever wrote in.',\n 'no-email-field': 'None',\n honeypot: 'Hidden field',\n 'honeypot-help': 'A field nobody sees and a robot fills in.',\n 'min-seconds': 'Fastest a person could send it, in seconds',\n 'min-seconds-help': 'Zero switches the check off.',\n throttle: 'Sends a minute from one address',\n 'throttle-help': 'Zero switches the limit off.',\n captcha: 'Captcha',\n 'captcha-help': 'The keys belong to the site and are set in its settings, not here.',\n 'captcha-off': 'Off',\n 'captcha-recaptcha': 'reCAPTCHA',\n 'captcha-turnstile': 'Turnstile',\n 'embed-blade': 'On a page of the site',\n 'embed-blade-help':\n 'Put the tag where the form belongs. The markup is published and rewritten by the site.',\n 'embed-block': 'In the block builder',\n 'embed-block-help':\n 'A block type prints the same tag, so an editor drops the form in without touching a template.',\n 'embed-names': 'Names of the fields',\n 'embed-names-help':\n 'A hidden field is filled in by the page: the address it was sent from, a product, a campaign.',\n copy: 'Copy',\n copied: 'Copied.',\n statuses: 'Statuses',\n 'new-status': 'New status',\n 'status-key': 'Key',\n 'status-color': 'Colour',\n 'status-default': 'Given to a new submission',\n 'status-spam': 'Spam',\n 'status-closed': 'Nothing further expected',\n 'in-use': 'In use',\n 'delete-status-title': 'Delete “:status”?',\n 'delete-status-text': 'Only a status nothing is in can go.',\n 'no-statuses': 'No statuses yet.',\n 'color-default': 'Grey',\n 'color-primary': 'Blue',\n 'color-success': 'Green',\n 'color-warning': 'Amber',\n 'color-info': 'Cyan',\n 'color-danger': 'Red',\n\n // The submissions: the list on the right of the section, and one of them opened.\n id: 'ID',\n received: 'Received',\n status: 'Status',\n assignee: 'Assignee',\n unassigned: 'Nobody',\n 'submissions-empty': 'Nothing has come in through this form yet.',\n 'search-submissions': 'Search the answers',\n 'view-all': 'All',\n 'view-unread': 'Unread',\n export: 'Export',\n 'new-submission': 'New submission',\n 'new-submission-title': 'A submission by hand',\n 'new-submission-help':\n 'For one that came by telephone or on paper. It is written the same way and lands in the same list.',\n created: 'Added.',\n submission: 'Submission :id',\n previous: 'Previous',\n next: 'Next',\n 'mark-read': 'Mark as read',\n 'mark-unread': 'Mark as unread',\n 'delete-submission-title': 'Delete this submission?',\n 'delete-submission-text': 'It goes with its attachments. This cannot be undone.',\n selected: ':count selected',\n 'move-to': 'Move to',\n 'delete-selected-title': 'Delete :count submissions?',\n answers: 'Answers',\n attachments: 'Attachments',\n details: 'Details',\n 'meta-page': 'Page',\n 'meta-placement': 'Placement',\n 'any-placement': 'Any placement',\n 'placement-none': 'Not specified',\n 'meta-referrer': 'Came from',\n 'meta-ip': 'Address',\n 'meta-agent': 'Browser',\n 'meta-locale': 'Language',\n 'meta-source': 'How it arrived',\n 'source-web': 'From the site',\n 'source-panel': 'Typed in',\n notified: 'The notification went out',\n 'not-notified': 'No notification was sent',\n 'notify-failed': 'The notification could not be sent',\n reply: 'Reply by mail',\n log: 'What has happened',\n 'event-created': 'Arrived',\n 'event-status': 'Status: :to',\n 'event-assignee': 'Given to :to',\n 'event-unassigned': 'Left to nobody',\n 'event-note': 'A note was added',\n 'event-notified': 'The notification went out',\n 'event-handled': 'Handed to :name',\n 'event-handler-error': ':name failed: :error',\n system: 'System',\n 'no-answers': 'Nothing was filled in.',\n download: 'Download',\n 'no-files-by-hand':\n 'A file cannot be attached by hand: the files a submission carries are what was posted with it.',\n 'submissions-none': 'Nothing here under this filter.',\n 'notifies-nobody': 'Nobody is told about this form',\n 'notifies-nobody-text':\n 'Every submission is kept here, but no letter goes out. Add a recipient on the Notifications tab.',\n 'notifies-nobody-short': 'Nobody is told',\n 'recipient-admin_deleted': 'This administrator no longer exists and gets no letter.',\n 'recipient-admin_inactive': 'This administrator is switched off and gets no letter.',\n 'recipient-invalid_email': 'This is not an e-mail address.',\n 'event-no-recipients': 'Nobody was told: the form names no recipients',\n 'notified-nobody': 'No notification: the form names nobody to tell',\n 'notify-queued': 'The notification is waiting in the queue',\n 'notify-again': 'Send the notification again',\n 'notify-sent-again': 'The notification has been sent again',\n 'notify-recipient-queued': 'waiting',\n 'notify-recipient-delivered': 'sent',\n 'notify-recipient-failed': 'failed',\n 'event-notify-queued': 'The notification was queued',\n 'event-notify-failed': 'The notification to :to failed',\n },\n\n fields: {\n field: 'Field',\n 'new-field': 'New field',\n 'edit-field': 'Field',\n 'no-fields': 'No questions yet.',\n 'no-fields-help': 'A form with no fields draws nothing on the page.',\n 'save-first': 'Save the form first, then write its questions.',\n delete: 'Delete',\n 'delete-title': 'Delete “:field”?',\n 'delete-text': 'It stops being asked. Answers already given keep it.',\n cancel: 'Cancel',\n save: 'Save',\n name: 'Name',\n 'name-help': 'What the field is called in the HTML. Left empty, it answers to f17.',\n type: 'Type',\n title: 'Label',\n placeholder: 'Placeholder',\n help: 'Hint under the field',\n 'is-enabled': 'Shown',\n 'is-required': 'Required',\n 'is-fullsize': 'Full width',\n 'in-table': 'A column in the list',\n choices: 'Choices',\n 'choice-value': 'Value',\n 'choice-label': 'Label',\n 'add-choice': 'Add a choice',\n 'no-choices': 'No choices yet. A field with none accepts nothing.',\n maxlength: 'Longest answer, in characters',\n rows: 'Height, in lines',\n pattern: 'Pattern the answer has to match',\n 'pattern-help': 'The browser’s own, written without delimiters: [0-9+ ()-]{6,}',\n earliest: 'Earliest date',\n latest: 'Latest date',\n 'min-choices': 'Fewest ticks',\n 'max-choices': 'Most ticks',\n 'consent-text': 'The sentence beside the tick',\n 'consent-text-help': 'A link is allowed here: it is printed as written.',\n 'max-size': 'Largest file, in kilobytes',\n extensions: 'Extensions allowed',\n 'extensions-help': 'Comma separated. Empty means the list the site allows.',\n multiple: 'Several files at once',\n 'type-text': 'Text',\n 'type-email': 'E-mail',\n 'type-tel': 'Telephone',\n 'type-textarea': 'Long text',\n 'type-select': 'Drop-down',\n 'type-radio': 'One of several',\n 'type-checkbox': 'Several of several',\n 'type-consent': 'Consent',\n 'type-date': 'Date',\n 'type-file': 'File',\n 'type-hidden': 'Hidden',\n },\n}\n","import { useAdmin } from '@webx-ui/module-admin'\nimport { inboxMessages } from './messages'\n\nconst seeded = new WeakSet<object>()\n\n/** Puts this package's English under the panel's dictionary, once per panel. */\nexport function useInboxMessages(): void {\n try {\n const { i18n } = useAdmin()\n\n if (!seeded.has(i18n)) {\n i18n.defaults('webx-inbox', inboxMessages)\n seeded.add(i18n)\n }\n } catch {\n // Outside a panel there is no dictionary to seed, and `useTranslate` falls back on its own.\n }\n}\n","import type { LocalizedValue } from '@webx-ui/core'\n\n/** The kinds of question a form can ask (§4). Mirrors `WebxUi\\Inbox\\Fields\\FieldType`. */\nexport const FIELD_TYPES = [\n 'text',\n 'email',\n 'tel',\n 'textarea',\n 'select',\n 'radio',\n 'checkbox',\n 'consent',\n 'date',\n 'file',\n 'hidden',\n] as const\n\nexport type FieldType = (typeof FIELD_TYPES)[number]\n\n/** Tones of `WxBadge`, which is what a status is coloured with — never a hex value. */\nexport const STATUS_COLORS = ['default', 'primary', 'success', 'warning', 'info', 'danger'] as const\n\nexport type StatusColor = (typeof STATUS_COLORS)[number]\n\n/** One written-down answer of a `select`, `radio` or `checkbox`. */\nexport interface FieldChoice {\n value: string\n label: LocalizedValue | string\n}\n\n/**\n * What a field may be configured with. Which keys mean anything depends on the type (§4), and\n * the server keeps only the ones that do.\n */\nexport interface FieldOptions {\n maxlength?: number\n rows?: number\n pattern?: string\n min?: number | string\n max?: number | string\n choices?: FieldChoice[]\n text?: LocalizedValue | string\n max_size?: number\n extensions?: string[]\n multiple?: boolean\n [key: string]: unknown\n}\n\nexport interface InboxField {\n id: number\n form_id: number\n /** What somebody typed, or null. */\n name: string | null\n /** What the HTML will actually say — `f17` for a field nobody named. */\n key: string\n type: FieldType\n title: LocalizedValue\n placeholder: LocalizedValue\n help: LocalizedValue\n options: FieldOptions\n is_enabled: boolean\n is_required: boolean\n is_fullsize: boolean\n in_table: boolean\n position: number\n /* A table row, so the index signature `WxTable` asks of what it draws. */\n [key: string]: unknown\n}\n\n/** A field as the dialog saves it. */\nexport interface FieldInput {\n name: string | null\n type: FieldType\n title: LocalizedValue\n placeholder?: LocalizedValue\n help?: LocalizedValue\n options?: FieldOptions\n is_enabled: boolean\n is_required: boolean\n is_fullsize: boolean\n in_table: boolean\n}\n\n/** Who a notification goes to: somebody with an account, or an address typed in. */\nexport type Recipient = { admin_id: number } | { email: string }\n\n/** Why a recipient the form names would not get a letter. */\nexport type RecipientProblem = 'admin_deleted' | 'admin_inactive' | 'invalid_email'\n\n/** A recipient as the server reads it today: who it is, and whether a letter would reach it. */\nexport interface RecipientState {\n type: 'admin' | 'email'\n admin_id?: number\n name?: string | null\n email: string | null\n receives: boolean\n problem: RecipientProblem | null\n}\n\n/** The settings of a form (§5). Every key is literal, dots included. */\nexport interface FormOptions {\n 'thank-you.heading'?: LocalizedValue\n 'thank-you.text'?: LocalizedValue\n 'design.submit-text'?: LocalizedValue\n redirect?: string\n recipients?: Recipient[]\n email_field?: string\n 'antispam.honeypot'?: boolean\n 'antispam.min_seconds'?: number\n 'antispam.throttle'?: number\n 'antispam.captcha'?: 'off' | 'recaptcha' | 'turnstile'\n [key: string]: unknown\n}\n\nexport interface InboxForm {\n id: number\n slug: string\n title: LocalizedValue\n is_enabled: boolean\n options: FormOptions\n /**\n * Who a submission would be written to, read from `options.recipients` as saved. Optional\n * only because a server older than this field does not send it.\n */\n recipients?: RecipientState[]\n /** False when a submission would be written to nobody at all. */\n notifies?: boolean\n position: number\n /** Only where the query counted them — null on a form loaded on its own. */\n submissions_count: number | null\n /** Unread and not spam. */\n unread_count: number | null\n /** Only on a form asked for by id, or one just written. */\n fields?: InboxField[]\n created_at: string | null\n updated_at: string | null\n}\n\n/** A form as its editor saves it. */\nexport interface FormInput {\n slug: string\n title: LocalizedValue\n is_enabled: boolean\n options: FormOptions\n}\n\nexport interface InboxStatus {\n id: number\n key: string\n title: LocalizedValue\n color: StatusColor\n is_default: boolean\n is_spam: boolean\n is_closed: boolean\n position: number\n submissions_count: number | null\n}\n\nexport interface StatusInput {\n key: string\n title: LocalizedValue\n color: StatusColor\n is_default: boolean\n is_spam: boolean\n is_closed: boolean\n}\n\n/** Somebody with an account who may read the section, for the recipients list. */\nexport interface InboxRecipient {\n id: number\n name: string\n email: string\n}\n\n/** An administrator as a name beside something else — an assignee, the author of a log line. */\nexport interface InboxAdmin {\n id: number\n name: string\n email: string\n}\n\n/** One column of the list: a field of the form that was marked `in_table`. */\nexport interface SubmissionColumn {\n key: string\n label: string\n type: FieldType\n}\n\n/** What each tab above the list would hold, under the filters that are on. */\nexport interface SubmissionCounts {\n all: number\n unread: number\n /** By the status's key, spam included — its own tab has to say how much is in it. */\n statuses: Record<string, number>\n}\n\n/** A page as Laravel's `->paginate()` serialises it, which is what `WxTable` reads. */\nexport interface InboxPage<T> {\n data: T[]\n current_page: number\n last_page: number\n per_page: number\n total: number\n from: number | null\n to: number | null\n}\n\n/** One line of the list. The answers are keyed by the field's machine name. */\nexport interface SubmissionRow {\n id: number\n values: Record<string, string | null>\n status: InboxStatus | null\n assignee: InboxAdmin | null\n is_read: boolean\n source: string\n /** Where on the site the form stood (`footer`, `article`), or null when the page did not say. */\n placement: string | null\n files_count: number\n created_at: string | null\n /* A table row, so the index signature `WxTable` asks of what it draws. */\n [key: string]: unknown\n}\n\n/**\n * The list, and the two things that travel with it: what its columns are, and what each tab\n * above it would hold.\n */\nexport interface SubmissionsPage extends InboxPage<SubmissionRow> {\n columns: SubmissionColumn[]\n counts: SubmissionCounts\n /**\n * Every place on the site the form has been sent from, `null` for the page that did not say —\n * over the whole form rather than the filter, so the placement filter can always be undone.\n * More than one is what makes that filter worth showing.\n */\n placements: (string | null)[]\n}\n\n/** One answer, with the question as it was asked at the time (§2.2). */\nexport interface SubmissionValue {\n id: number\n field_id: number | null\n name: string\n label: string | null\n type: string\n value: string | null\n payload: unknown\n}\n\nexport interface SubmissionAttachment {\n id: number\n field_id: number | null\n name: string\n size: number\n mime: string | null\n /** Through the panel, behind the same permission as the submission (§8). */\n url: string\n}\n\n/** One line of what has happened to a submission. Never edited, never deleted. */\nexport interface SubmissionEvent {\n id: number\n type:\n | 'created'\n | 'status'\n | 'assignee'\n | 'note'\n | 'notified'\n | 'handled'\n | 'handler_error'\n | 'no_recipients'\n | 'notify_queued'\n | 'notify_failed'\n | string\n from: string | null\n to: string | null\n /** Null is the system — the submission arriving, the notification going out. */\n author: { id: number; name: string | null } | null\n created_at: string | null\n}\n\n/**\n * Whether the letter about a submission left (§9). `queued` is handed to the site's queue and\n * not sent yet — on a site with a queue, sending is a worker's job, and a worker can be missing.\n */\nexport type NotifyState = 'none' | 'queued' | 'delivered' | 'failed'\n\nexport interface SubmissionNotification {\n state: NotifyState\n error: string | null\n queued_at: string | null\n delivered_at: string | null\n /** Empty on a submission from before the letters were watched one by one. */\n recipients: {\n address: string\n state: 'queued' | 'delivered' | 'failed'\n error: string | null\n at: string\n }[]\n}\n\n/** What the intake saw around the submission: the page, the language, the campaign. */\nexport interface SubmissionMeta {\n ip?: string\n user_agent?: string\n page?: string\n referrer?: string\n utm?: Record<string, string>\n locale?: string\n [key: string]: unknown\n}\n\nexport interface InboxSubmission {\n id: number\n form: { id: number; slug: string | null; title: LocalizedValue | null }\n status: InboxStatus | null\n assignee: InboxAdmin | null\n values: SubmissionValue[]\n files: SubmissionAttachment[]\n meta: SubmissionMeta\n events: SubmissionEvent[]\n is_read: boolean\n source: string\n /** Where on the site the form stood (`footer`, `article`), or null when the page did not say. */\n placement: string | null\n notified_at: string | null\n notify_error: string | null\n /** The same two read as a state, with how each letter went. */\n notification: SubmissionNotification\n /** The neighbours in the list this was opened from, so the arrows walk the same pile. */\n previous_id: number | null\n next_id: number | null\n created_at: string | null\n updated_at: string | null\n}\n\n/** Everything the list asks the server for. The tab is `view`, the rest are filters. */\nexport interface SubmissionQuery {\n view?: string\n search?: string\n /** An administrator's id, or `none` — the pile nobody has picked up. */\n assignee?: string | null\n /** A placement, or `none` — the submissions whose page did not say. */\n placement?: string | null\n sort?: string | null\n page?: number\n per_page?: number\n}\n\n/** A submission changed by hand: the status, the assignee, a typo in an answer. */\nexport interface SubmissionInput {\n status_id?: number\n assignee_id?: number | null\n /** Machine name → the corrected text. The snapshot beside it is never rewritten. */\n values?: Record<string, string | null>\n}\n\n/** A pile dealt with at once. */\nexport interface SubmissionMassInput {\n ids: number[]\n action: 'status' | 'read' | 'unread' | 'delete'\n status_id?: number\n}\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n toast,\n useModal,\n WxAction,\n WxButton,\n WxIcon,\n WxCheckbox,\n WxDialog,\n WxFormItem,\n WxInput,\n WxInputNumber,\n WxSelect,\n WxSpace,\n WxDatePicker,\n WxTagsInput,\n WxText,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport LocalizedRichText from './LocalizedRichText.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport { FIELD_TYPES, type FieldChoice, type FieldOptions, type FieldType } from './types'\nimport type { InboxField, InboxForm } from './types'\n\n/**\n * One question, written.\n *\n * The settings shown are the ones the chosen type has and no others (§4): a `select` has\n * choices, a `textarea` has a height, a `file` has a size and a list of extensions. Changing\n * the type changes what is asked for, and the server keeps only what belongs — a leftover\n * `choices` array on a text field would be a column of empty strings in an export a year from\n * now.\n */\nconst props = defineProps<{ field: InboxField | null; form: InboxForm }>()\n\nconst { resolve, dismiss, open } = useModal<InboxField>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nconst name = ref('')\nconst type = ref<FieldType>('text')\nconst title = ref<LocalizedValue>({})\nconst placeholder = ref<LocalizedValue>({})\nconst help = ref<LocalizedValue>({})\nconst options = ref<FieldOptions>({})\nconst isEnabled = ref(true)\nconst isRequired = ref(false)\nconst isFullsize = ref(true)\nconst inTable = ref(false)\n\nwatch(\n () => props.field,\n (field) => {\n name.value = field?.name ?? ''\n type.value = field?.type ?? 'text'\n title.value = { ...(field?.title ?? {}) }\n placeholder.value = { ...(field?.placeholder ?? {}) }\n help.value = { ...(field?.help ?? {}) }\n options.value = { ...(field?.options ?? {}) }\n isEnabled.value = field?.is_enabled ?? true\n isRequired.value = field?.is_required ?? false\n isFullsize.value = field?.is_fullsize ?? true\n inTable.value = field?.in_table ?? false\n errors.value = {}\n },\n { immediate: true },\n)\n\nconst types = computed(() =>\n FIELD_TYPES.map((one) => ({ value: one, label: t(`fields.type-${one}`) })),\n)\n\nconst hasChoices = computed(() => ['select', 'radio', 'checkbox'].includes(type.value))\n\nconst choices = computed<FieldChoice[]>(() =>\n Array.isArray(options.value.choices) ? options.value.choices : [],\n)\n\n/** Extensions are typed as a list of words, which is what they are — not a sentence. */\nconst extensions = computed({\n get: () => (Array.isArray(options.value.extensions) ? options.value.extensions : []),\n set: (value: string[]) =>\n set(\n 'extensions',\n value.map((one) => one.replace(/^\\./, '')),\n ),\n})\n\nfunction set(key: string, value: unknown): void {\n options.value = { ...options.value, [key]: value }\n}\n\nfunction addChoice(): void {\n set('choices', [...choices.value, { value: '', label: {} }])\n}\n\nfunction removeChoice(index: number): void {\n set(\n 'choices',\n choices.value.filter((_, at) => at !== index),\n )\n}\n\nfunction setChoice(index: number, patch: Partial<FieldChoice>): void {\n set(\n 'choices',\n choices.value.map((choice, at) => (at === index ? { ...choice, ...patch } : choice)),\n )\n}\n\nfunction errorOf(field: string): string | undefined {\n return errors.value[field]?.[0]\n}\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n const input = {\n name: name.value.trim() === '' ? null : name.value.trim(),\n type: type.value,\n title: title.value,\n placeholder: placeholder.value,\n help: help.value,\n options: options.value,\n is_enabled: isEnabled.value,\n is_required: isRequired.value,\n is_fullsize: isFullsize.value,\n in_table: inTable.value,\n }\n\n try {\n resolve(\n props.field === null\n ? await api.createField(props.form.id, input)\n : await api.saveField(props.field.id, input),\n )\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog\n v-model:open=\"open\"\n :title=\"field ? t('fields.edit-field') : t('fields.new-field')\"\n :width=\"720\"\n >\n <div class=\"wx-inbox-field-form\">\n <div class=\"wx-inbox-field-form__row\">\n <wx-form-item :label=\"t('fields.type')\">\n <wx-select v-model=\"type\" :options=\"types\" />\n </wx-form-item>\n\n <wx-form-item\n :label=\"t('fields.name')\"\n :help=\"t('fields.name-help')\"\n :error=\"errorOf('name')\"\n >\n <wx-input v-model=\"name\" placeholder=\"email\" />\n </wx-form-item>\n </div>\n\n <wx-form-item :label=\"t('fields.title')\" :error=\"errorOf('title')\" required>\n <wx-input v-model=\"title\" localized />\n </wx-form-item>\n\n <!-- A hidden field has neither: nobody reads a placeholder they cannot see. -->\n <template v-if=\"type !== 'hidden'\">\n <wx-form-item v-if=\"type !== 'consent'\" :label=\"t('fields.placeholder')\">\n <wx-input v-model=\"placeholder\" localized />\n </wx-form-item>\n\n <wx-form-item :label=\"t('fields.help')\">\n <wx-input v-model=\"help\" localized />\n </wx-form-item>\n </template>\n\n <!-- The sentence beside the tick, which is printed raw on the site: it is a sentence\n with a link in it, not a caption. -->\n <wx-form-item\n v-if=\"type === 'consent'\"\n :label=\"t('fields.consent-text')\"\n :help=\"t('fields.consent-text-help')\"\n >\n <localized-rich-text\n :model-value=\"(options.text as LocalizedValue) ?? {}\"\n min-height=\"100px\"\n @update:model-value=\"(value) => set('text', value)\"\n />\n </wx-form-item>\n\n <div v-if=\"hasChoices\" class=\"wx-inbox-choices\">\n <wx-text size=\"sm\" weight=\"medium\">{{ t('fields.choices') }}</wx-text>\n\n <wx-text v-if=\"choices.length === 0\" size=\"sm\" tone=\"placeholder\">\n {{ t('fields.no-choices') }}\n </wx-text>\n\n <div v-for=\"(choice, index) in choices\" :key=\"index\" class=\"wx-inbox-choices__row\">\n <wx-input\n :model-value=\"choice.value\"\n :placeholder=\"t('fields.choice-value')\"\n @update:model-value=\"(value) => setChoice(index, { value: String(value) })\"\n />\n <wx-input\n :model-value=\"choice.label\"\n localized\n :placeholder=\"t('fields.choice-label')\"\n @update:model-value=\"(label) => setChoice(index, { label: label as LocalizedValue })\"\n />\n <wx-action icon=\"trash\" :title=\"t('fields.delete')\" @click=\"removeChoice(index)\" />\n </div>\n\n <wx-button variant=\"outline\" size=\"sm\" @click=\"addChoice\">\n <template #icon><wx-icon name=\"plus\" /></template>\n {{ t('fields.add-choice') }}\n </wx-button>\n </div>\n\n <div class=\"wx-inbox-field-form__row\">\n <wx-form-item v-if=\"type === 'textarea'\" :label=\"t('fields.rows')\">\n <wx-input-number\n :model-value=\"(options.rows as number) ?? 5\"\n :min=\"2\"\n :max=\"30\"\n @update:model-value=\"(value) => set('rows', value)\"\n />\n </wx-form-item>\n\n <wx-form-item\n v-if=\"['text', 'email', 'textarea'].includes(type)\"\n :label=\"t('fields.maxlength')\"\n >\n <wx-input-number\n :model-value=\"(options.maxlength as number) ?? null\"\n :min=\"1\"\n :max=\"20000\"\n @update:model-value=\"(value) => set('maxlength', value)\"\n />\n </wx-form-item>\n\n <wx-form-item\n v-if=\"type === 'tel'\"\n :label=\"t('fields.pattern')\"\n :help=\"t('fields.pattern-help')\"\n >\n <wx-input\n :model-value=\"(options.pattern as string) ?? ''\"\n @update:model-value=\"(value) => set('pattern', value)\"\n />\n </wx-form-item>\n\n <template v-if=\"type === 'date'\">\n <wx-form-item :label=\"t('fields.earliest')\">\n <wx-date-picker\n clearable\n :model-value=\"(options.min as string) ?? null\"\n @update:model-value=\"(value) => set('min', value)\"\n />\n </wx-form-item>\n <wx-form-item :label=\"t('fields.latest')\">\n <wx-date-picker\n clearable\n :model-value=\"(options.max as string) ?? null\"\n @update:model-value=\"(value) => set('max', value)\"\n />\n </wx-form-item>\n </template>\n\n <template v-if=\"type === 'checkbox'\">\n <wx-form-item :label=\"t('fields.min-choices')\">\n <wx-input-number\n :model-value=\"(options.min as number) ?? null\"\n :min=\"0\"\n @update:model-value=\"(value) => set('min', value)\"\n />\n </wx-form-item>\n <wx-form-item :label=\"t('fields.max-choices')\">\n <wx-input-number\n :model-value=\"(options.max as number) ?? null\"\n :min=\"0\"\n @update:model-value=\"(value) => set('max', value)\"\n />\n </wx-form-item>\n </template>\n\n <wx-form-item v-if=\"type === 'file'\" :label=\"t('fields.max-size')\">\n <wx-input-number\n :model-value=\"(options.max_size as number) ?? null\"\n :min=\"1\"\n @update:model-value=\"(value) => set('max_size', value)\"\n />\n </wx-form-item>\n </div>\n\n <template v-if=\"type === 'file'\">\n <wx-form-item :label=\"t('fields.extensions')\" :help=\"t('fields.extensions-help')\">\n <wx-tags-input v-model=\"extensions\" />\n </wx-form-item>\n\n <wx-checkbox\n :model-value=\"Boolean(options.multiple)\"\n :label=\"t('fields.multiple')\"\n @update:model-value=\"(value) => set('multiple', value)\"\n />\n </template>\n\n <div class=\"wx-inbox-field-form__checks\">\n <wx-checkbox v-model=\"isEnabled\" :label=\"t('fields.is-enabled')\" />\n <wx-checkbox v-model=\"isRequired\" :label=\"t('fields.is-required')\" />\n <wx-checkbox\n v-if=\"type !== 'hidden'\"\n v-model=\"isFullsize\"\n :label=\"t('fields.is-fullsize')\"\n />\n <wx-checkbox v-model=\"inTable\" :label=\"t('fields.in-table')\" />\n </div>\n </div>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('fields.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">{{ t('fields.save') }}</wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-inbox-field-form {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n\n.wx-inbox-field-form__row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-12);\n}\n\n.wx-inbox-field-form__row > * {\n flex: 1 1 200px;\n min-width: 0;\n}\n\n/* Empty when the type has nothing to configure, and then it should take no room at all. */\n.wx-inbox-field-form__row:empty {\n display: none;\n}\n\n.wx-inbox-field-form__checks {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-16);\n}\n\n.wx-inbox-choices {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-8);\n align-items: flex-start;\n}\n\n.wx-inbox-choices__row {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n width: 100%;\n}\n\n.wx-inbox-choices__row > :first-child {\n flex: 0 1 180px;\n min-width: 0;\n}\n\n.wx-inbox-choices__row > :nth-child(2) {\n flex: 1 1 auto;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxRowMenu,\n type RowAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n localizedValue,\n toast,\n useLocales,\n WxBadge,\n WxButton,\n WxIcon,\n WxCard,\n WxEmpty,\n WxSortableList,\n WxText,\n} from '@webx-ui/core'\nimport FieldDialog from './FieldDialog.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxField, InboxForm } from './types'\n\n/**\n * The questions the form asks, in the order it asks them.\n *\n * A list with a grip rather than a table, because the order is the thing being edited here\n * and a table cannot be dragged. Each question is saved on its own, in its own dialog: a\n * field is a row with an identity that answers point at (§2.1), not a value of the form.\n */\nconst props = defineProps<{ form: InboxForm; canManage: boolean }>()\n\nconst fields = defineModel<InboxField[]>({ required: true })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst edit = createModal<InboxField, { field: InboxField | null; form: InboxForm }>(FieldDialog)\n\nfunction name(field: InboxField): string {\n return localizedValue(field.title, locales.active.value, field.key)\n}\n\n/** What the row says about itself, under its name: the type, then what is true of it. */\nfunction marks(field: InboxField): string[] {\n return [\n t(`fields.type-${field.type}`),\n ...(field.is_required ? [t('fields.is-required')] : []),\n ...(field.in_table ? [t('fields.in-table')] : []),\n ...(field.is_fullsize ? [] : [t('fields.is-fullsize')]),\n ]\n}\n\nconst empty = computed(() => fields.value.length === 0)\n\nasync function open(field: InboxField | null): Promise<void> {\n const saved = await edit({ field, form: props.form })\n\n if (!saved) return\n\n fields.value =\n field === null\n ? [...fields.value, saved]\n : fields.value.map((one) => (one.id === saved.id ? saved : one))\n}\n\nasync function remove(field: InboxField): Promise<void> {\n const agreed = await confirm({\n title: t('fields.delete-title', { field: name(field) }),\n message: t('fields.delete-text'),\n confirmText: t('fields.delete'),\n cancelText: t('fields.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeField(field.id)\n fields.value = fields.value.filter((one) => one.id !== field.id)\n toast.success(t('panel.deleted'))\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nfunction actionsFor(field: InboxField): RowAction[] {\n if (!props.canManage) return []\n\n return [\n { key: 'edit', icon: 'edit', label: t('fields.edit-field'), run: () => void open(field) },\n {\n key: 'delete',\n icon: 'trash',\n label: t('fields.delete'),\n danger: true,\n run: () => void remove(field),\n },\n ]\n}\n\n/** The whole order, every time — the list is already in it on screen. */\nasync function reorder(): Promise<void> {\n try {\n await api.sortFields(\n props.form.id,\n fields.value.map((field) => field.id),\n )\n } catch (error) {\n toast.danger(message(error, t('panel.reorder-failed')))\n }\n}\n</script>\n\n<template>\n <wx-card :title=\"t('panel.tab-fields')\">\n <template v-if=\"canManage\" #extra>\n <wx-button type=\"primary\" size=\"sm\" @click=\"open(null)\">\n <template #icon><wx-icon name=\"plus\" /></template>\n {{ t('fields.new-field') }}\n </wx-button>\n </template>\n\n <wx-empty\n v-if=\"empty\"\n :title=\"t('fields.no-fields')\"\n :description=\"t('fields.no-fields-help')\"\n />\n\n <wx-sortable-list\n v-else\n v-model=\"fields\"\n plain\n item-key=\"id\"\n :item-label=\"name\"\n :disabled=\"!canManage\"\n :aria-label=\"t('panel.tab-fields')\"\n @move=\"reorder\"\n >\n <template #default=\"{ item }\">\n <div class=\"wx-inbox-field\">\n <div class=\"wx-inbox-field__name\">\n <wx-text weight=\"medium\" truncate>{{ name(item) }}</wx-text>\n <wx-badge v-if=\"!item.is_enabled\" type=\"default\">{{ t('panel.off') }}</wx-badge>\n </div>\n <wx-text size=\"sm\" tone=\"muted\" truncate>\n <code>fields[{{ item.key }}]</code> · {{ marks(item).join(' · ') }}\n </wx-text>\n </div>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-row-menu :actions=\"actionsFor(item)\" :label=\"name(item)\" />\n </template>\n </wx-sortable-list>\n </wx-card>\n</template>\n\n<style scoped>\n.wx-inbox-field {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-2);\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.wx-inbox-field__name {\n display: flex;\n align-items: center;\n gap: var(--wx-space-6);\n min-width: 0;\n}\n</style>\n","import { computed, type Ref, type WritableComputedRef } from 'vue'\nimport type { FormOptions } from './types'\n\n/**\n * One setting of a form, as something a control can be bound to.\n *\n * The keys are literal and several of them have dots in them — `thank-you.heading` is one key\n * (§5) — so nothing here splits on a dot, and a whole new object is written on every change\n * rather than a property being set in place: the editor holds the options as one value, and a\n * mutation underneath it is a change nothing is told about.\n *\n * An empty value is not written as an empty value: it is taken out. The server does the same\n * when it saves, and a form whose settings are twelve blank strings reads as configured when\n * it is not.\n */\nexport function option<T>(\n options: Ref<FormOptions>,\n key: string,\n fallback: T,\n): WritableComputedRef<T> {\n return computed({\n get: () => (options.value[key] ?? fallback) as T,\n set: (value: T) => {\n const next = { ...options.value }\n\n if (value === '' || value === null || value === undefined) {\n delete next[key]\n } else {\n next[key] = value\n }\n\n options.value = next\n },\n })\n}\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { WxCard, WxFormItem, WxInputNumber, WxSelect, WxSwitch } from '@webx-ui/core'\nimport { option } from './options'\nimport type { FormOptions } from './types'\n\n/**\n * The four layers in front of the door (§7), as the three anybody would want to change.\n *\n * The origin check is not here: it is not a dial, it is a fact about where the site is served\n * from, and it lives in the configuration with the rest of the deployment. The captcha keys\n * are not here either — they are the site's, one pair for every form, and a secret repeated\n * in each form's settings is a secret scattered over rows (§5).\n */\nconst options = defineModel<FormOptions>({ required: true })\n\nconst t = useTranslate('webx-inbox')\n\nconst honeypot = option<boolean>(options, 'antispam.honeypot', true)\nconst seconds = option<number>(options, 'antispam.min_seconds', 3)\nconst throttle = option<number>(options, 'antispam.throttle', 5)\nconst captcha = option<string>(options, 'antispam.captcha', 'off')\n\nconst captchas = computed(() => [\n { value: 'off', label: t('panel.captcha-off') },\n { value: 'recaptcha', label: t('panel.captcha-recaptcha') },\n { value: 'turnstile', label: t('panel.captcha-turnstile') },\n])\n</script>\n\n<template>\n <wx-card>\n <wx-form-item :label=\"t('panel.honeypot')\" :help=\"t('panel.honeypot-help')\">\n <wx-switch v-model=\"honeypot\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.min-seconds')\" :help=\"t('panel.min-seconds-help')\">\n <wx-input-number v-model=\"seconds\" :min=\"0\" :max=\"120\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.throttle')\" :help=\"t('panel.throttle-help')\">\n <wx-input-number v-model=\"throttle\" :min=\"0\" :max=\"120\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.captcha')\" :help=\"t('panel.captcha-help')\">\n <wx-select v-model=\"captcha\" :options=\"captchas\" />\n </wx-form-item>\n </wx-card>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { toast, WxAction, WxCard, WxTable, WxText, type TableColumn } from '@webx-ui/core'\nimport { useInboxMessages } from './i18n'\nimport type { InboxField, InboxForm } from './types'\n\n/**\n * How the form gets onto a page.\n *\n * Two answers and both are one line, because the module's whole public half is one tag (§10):\n * a template prints it, and a block type prints the same thing so that an editor never opens\n * a template at all.\n *\n * Under them, the names. A hidden field is filled in by the page it stands on — the address\n * somebody wrote from, the product they were looking at, the campaign that brought them — and\n * the only way to fill one in is to know what it is called (§2.6).\n */\nconst props = defineProps<{ form: InboxForm; slug: string; fields: InboxField[] }>()\n\nuseInboxMessages()\nconst t = useTranslate('webx-inbox')\n\nconst blade = computed(() => `<x-webx-inbox::form slug=\"${props.slug}\" />`)\n\nconst block = computed(\n () =>\n `{{-- resources/views/blocks/contact.blade.php --}}\\n<x-webx-inbox::form slug=\"${props.slug}\" />`,\n)\n\nconst columns = computed<TableColumn<InboxField>[]>(() => [\n { key: 'key', label: t('fields.name') },\n { key: 'title', label: t('fields.title') },\n { key: 'type', label: t('fields.type'), hideBelow: 520 },\n])\n\n/** Only the ones a page can actually fill in or a visitor can actually answer. */\nconst listed = computed(() => props.fields.filter((field) => field.is_enabled))\n\nasync function copy(text: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text)\n toast.success(t('panel.copied'))\n } catch {\n // A browser that refuses the clipboard — an insecure origin, a denied permission — still\n // shows the line, and selecting it by hand is what anybody does next anyway.\n }\n}\n</script>\n\n<template>\n <div class=\"wx-inbox-embed\">\n <wx-card :title=\"t('panel.embed-blade')\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.embed-blade-help') }}</wx-text>\n\n <div class=\"wx-inbox-embed__snippet\">\n <code>{{ blade }}</code>\n <wx-action icon=\"copy\" :title=\"t('panel.copy')\" @click=\"copy(blade)\" />\n </div>\n </wx-card>\n\n <wx-card :title=\"t('panel.embed-block')\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.embed-block-help') }}</wx-text>\n\n <div class=\"wx-inbox-embed__snippet\">\n <code>{{ block }}</code>\n <wx-action icon=\"copy\" :title=\"t('panel.copy')\" @click=\"copy(block)\" />\n </div>\n </wx-card>\n\n <wx-card :title=\"t('panel.embed-names')\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.embed-names-help') }}</wx-text>\n\n <wx-table\n :data=\"listed\"\n :columns=\"columns\"\n row-key=\"id\"\n flush\n :empty-text=\"t('fields.no-fields')\"\n >\n <template #cell-key=\"{ row }\">\n <wx-text mono size=\"sm\">fields[{{ row.key }}]</wx-text>\n </template>\n\n <template #cell-title=\"{ row }\">\n {{ Object.values(row.title)[0] ?? row.key }}\n </template>\n\n <template #cell-type=\"{ row }\">\n {{ t(`fields.type-${row.type}`) }}\n </template>\n </wx-table>\n </wx-card>\n </div>\n</template>\n\n<style scoped>\n.wx-inbox-embed {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-16);\n}\n\n.wx-inbox-embed__snippet {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n margin-top: var(--wx-space-12);\n padding: var(--wx-space-10) var(--wx-space-12);\n border: 1px solid var(--wx-border-default);\n border-radius: var(--wx-radius-md);\n background: var(--wx-bg-subtle);\n}\n\n.wx-inbox-embed__snippet code {\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n white-space: pre;\n font-family: var(--wx-font-family-mono);\n font-size: var(--wx-font-size-sm);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { WxCard, WxFormItem, WxInput, WxSwitch, type LocalizedValue } from '@webx-ui/core'\nimport LocalizedRichText from './LocalizedRichText.vue'\nimport { option } from './options'\nimport type { FormOptions } from './types'\n\n/**\n * What the form is, and what it says once it has been sent.\n *\n * The two halves are on two cards because they are read at two different times: the first is\n * set up once, the second is the sentence a visitor sees and is rewritten whenever the\n * marketing does.\n */\ndefineProps<{ errors: Record<string, string[]> }>()\n\nconst settings = defineModel<{ slug: string; title: LocalizedValue; is_enabled: boolean }>(\n 'settings',\n { required: true },\n)\n\nconst options = defineModel<FormOptions>('options', { required: true })\n\nconst t = useTranslate('webx-inbox')\n\nconst heading = option<LocalizedValue>(options, 'thank-you.heading', {})\nconst text = option<LocalizedValue>(options, 'thank-you.text', {})\nconst submit = option<LocalizedValue>(options, 'design.submit-text', {})\nconst redirect = option<string>(options, 'redirect', '')\n</script>\n\n<template>\n <div class=\"wx-inbox-general\">\n <wx-card>\n <wx-form-item :label=\"t('panel.title')\" :error=\"errors.title?.[0]\" required>\n <wx-input v-model=\"settings.title\" localized />\n </wx-form-item>\n\n <wx-form-item\n :label=\"t('panel.slug')\"\n :help=\"t('panel.slug-help')\"\n :error=\"errors.slug?.[0]\"\n required\n >\n <wx-input v-model=\"settings.slug\" placeholder=\"contact\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.is-enabled')\" :help=\"t('panel.is-enabled-help')\">\n <wx-switch v-model=\"settings.is_enabled\" />\n </wx-form-item>\n </wx-card>\n\n <wx-card :title=\"t('panel.after-sending')\">\n <wx-form-item :label=\"t('panel.submit-text')\">\n <wx-input v-model=\"submit\" localized />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.thank-you-heading')\">\n <wx-input v-model=\"heading\" localized />\n </wx-form-item>\n\n <!-- Printed raw on the site, which is why it is written where formatting is possible. -->\n <wx-form-item :label=\"t('panel.thank-you-text')\">\n <localized-rich-text v-model=\"text\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.redirect')\" :help=\"t('panel.redirect-help')\">\n <wx-input v-model=\"redirect\" placeholder=\"/thank-you\" />\n </wx-form-item>\n </wx-card>\n </div>\n</template>\n\n<style scoped>\n.wx-inbox-general {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-16);\n}\n</style>\n","import type { Recipient, RecipientProblem, RecipientState } from './types'\n\n/**\n * Whether a letter would reach somebody, judged on the recipients as they stand in the editor.\n *\n * The server says it for what was saved (`InboxForm.recipients`): who is deleted, who is\n * switched off. The editor has to say it before a save too, so this reads the list being edited\n * and borrows the server's verdict only for the administrators it already knows about — one\n * picked a moment ago from the list of people who may read the section is somebody who exists.\n */\n\n/** Loose on purpose: the server checks the address for real, this only spots an empty line. */\nconst ADDRESS = /^[^\\s@]+@[^\\s@]+$/\n\nexport function isAdmin(recipient: Recipient): recipient is { admin_id: number } {\n return 'admin_id' in recipient\n}\n\n/** Why this recipient would not get a letter, or null when it would. */\nexport function problemOf(\n recipient: Recipient,\n reported: RecipientState[] = [],\n): RecipientProblem | null {\n if (isAdmin(recipient)) {\n const known = reported.find(\n (one) => one.type === 'admin' && one.admin_id === recipient.admin_id,\n )\n\n return known?.problem ?? null\n }\n\n return ADDRESS.test((recipient.email ?? '').trim()) ? null : 'invalid_email'\n}\n\n/** Whether anybody on the list would be written to. */\nexport function reachesAnybody(\n recipients: Recipient[] | undefined,\n reported: RecipientState[] = [],\n): boolean {\n return (recipients ?? []).some((recipient) => problemOf(recipient, reported) === null)\n}\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport { useAdmin, useTranslate } from '@webx-ui/module-admin'\nimport {\n confirm,\n WxAction,\n WxAlert,\n WxButton,\n WxIcon,\n WxCard,\n WxFormItem,\n WxInput,\n WxSelect,\n WxSpace,\n WxText,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { option } from './options'\nimport { isAdmin, problemOf } from './recipients'\nimport type { FormOptions, InboxField, InboxRecipient, Recipient, RecipientState } from './types'\n\n/**\n * Who hears that something arrived (§9).\n *\n * Two kinds of recipient and they are not interchangeable. An administrator is written to at\n * the address on their account and in the language they keep the panel in, so changing either\n * changes it everywhere; a typed address is written to in the language the submission came in.\n * The list offered is not every administrator but the ones who may open a submission — a\n * notification is a link, and sending one to somebody who gets a 403 looks like the panel is\n * broken rather than like the form is.\n */\nconst props = defineProps<{\n fields: InboxField[]\n errors: Record<string, string[]>\n /** What the server said about the saved list: who is deleted or switched off. */\n reported?: RecipientState[]\n}>()\n\nconst options = defineModel<FormOptions>({ required: true })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst t = useTranslate('webx-inbox')\n\nconst admins = ref<InboxRecipient[]>([])\n\nconst recipients = option<Recipient[]>(options, 'recipients', [])\nconst emailField = option<string>(options, 'email_field', '')\n\nonMounted(async () => {\n try {\n admins.value = await api.recipients()\n } catch {\n // Only the shortcut is gone: an address can still be typed, and that is the half of this\n // that has to work.\n }\n})\n\nconst adminOptions = computed(() =>\n admins.value.map((admin) => ({ value: admin.id, label: `${admin.name} · ${admin.email}` })),\n)\n\n/** The fields that could hold the sender's address, plus the option of naming none. */\nconst emailOptions = computed(() => [\n { value: '', label: t('panel.no-email-field') },\n ...props.fields\n .filter((field) => field.type === 'email')\n .map((field) => ({ value: field.key, label: field.key })),\n])\n\n/*\n * Only the administrators' problems are said beside the row: an address being typed is not\n * wrong yet, and the server refuses a bad one on save in words of its own.\n */\nfunction adminProblem(recipient: Recipient): string | null {\n if (!isAdmin(recipient)) return null\n\n const problem = problemOf(recipient, props.reported)\n\n return problem === null ? null : t(`panel.recipient-${problem}`)\n}\n\nfunction add(recipient: Recipient): void {\n recipients.value = [...recipients.value, recipient]\n}\n\n/**\n * A recipient goes behind a question, unless there is nothing there to lose.\n *\n * The row that was just added and never filled in is a blank line, and asking about a blank\n * line teaches the reader to click through the question without reading it — which is the\n * one thing a confirmation must not do.\n */\nasync function remove(index: number): Promise<void> {\n const recipient = recipients.value[index]\n const written =\n recipient !== undefined && (isAdmin(recipient) || (recipient.email ?? '').trim() !== '')\n\n if (written) {\n const agreed = await confirm({\n title: t('panel.remove-recipient-title'),\n message: t('panel.remove-recipient-text'),\n confirmText: t('panel.remove'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n }\n\n recipients.value = recipients.value.filter((_, at) => at !== index)\n}\n\nfunction setAdmin(index: number, id: number): void {\n recipients.value = recipients.value.map((one, at) => (at === index ? { admin_id: id } : one))\n}\n\nfunction setEmail(index: number, email: string): void {\n recipients.value = recipients.value.map((one, at) => (at === index ? { email } : one))\n}\n</script>\n\n<template>\n <wx-card :title=\"t('panel.recipients')\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.recipients-help') }}</wx-text>\n\n <wx-alert\n v-if=\"errors['options.recipients']\"\n type=\"danger\"\n variant=\"soft\"\n :description=\"errors['options.recipients']?.[0]\"\n />\n\n <div class=\"wx-inbox-recipients\">\n <wx-text v-if=\"recipients.length === 0\" size=\"sm\" tone=\"placeholder\">\n {{ t('panel.no-recipients') }}\n </wx-text>\n\n <div v-for=\"(recipient, index) in recipients\" :key=\"index\" class=\"wx-inbox-recipients__item\">\n <div class=\"wx-inbox-recipients__row\">\n <wx-select\n v-if=\"isAdmin(recipient)\"\n :model-value=\"recipient.admin_id\"\n :options=\"adminOptions\"\n @update:model-value=\"(id) => setAdmin(index, Number(id))\"\n />\n <wx-input\n v-else\n :model-value=\"recipient.email\"\n type=\"email\"\n placeholder=\"sales@example.com\"\n @update:model-value=\"(email) => setEmail(index, String(email))\"\n />\n\n <!-- Red, like every other way of taking something away in the panel: the colour is\n what tells the two buttons of a row apart before either is read. -->\n <wx-action icon=\"trash\" tone=\"danger\" :title=\"t('panel.remove')\" @click=\"remove(index)\" />\n </div>\n <wx-text v-if=\"adminProblem(recipient)\" size=\"sm\" tone=\"danger\">\n {{ adminProblem(recipient) }}\n </wx-text>\n </div>\n </div>\n\n <wx-space size=\"sm\">\n <wx-button\n variant=\"outline\"\n icon=\"user\"\n :disabled=\"adminOptions.length === 0\"\n @click=\"add({ admin_id: Number(adminOptions[0]?.value) })\"\n >\n {{ t('panel.add-admin') }}\n </wx-button>\n <wx-button variant=\"outline\" @click=\"add({ email: '' })\">\n <template #icon><wx-icon name=\"mail\" /></template>\n {{ t('panel.add-email') }}\n </wx-button>\n </wx-space>\n\n <wx-form-item :label=\"t('panel.email-field')\" :help=\"t('panel.email-field-help')\">\n <wx-select v-model=\"emailField\" :options=\"emailOptions\" />\n </wx-form-item>\n </wx-card>\n</template>\n\n<style scoped>\n/*\n * As wide as a field, because that is what each row is: an address is typed into it and read\n * back off it. The rows are not form items — one of them is a select, the next an input, and\n * both carry a bin — so the cap that a form item applies has to be said here.\n */\n.wx-inbox-recipients {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-8);\n margin-block: var(--wx-space-12);\n max-width: var(--wx-field-max-width, 640px);\n}\n\n.wx-inbox-recipients__item {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-4);\n}\n\n.wx-inbox-recipients__row {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n}\n\n.wx-inbox-recipients__row > :first-child {\n flex: 1 1 auto;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, reactive, ref, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useAdmin, useErrorText, useTranslate, WxScreenHead } from '@webx-ui/module-admin'\nimport {\n localizedValue,\n toast,\n useLocales,\n WxActionBar,\n WxAlert,\n WxBadge,\n WxButton,\n WxCard,\n WxSkeleton,\n WxTab,\n WxTabs,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport FieldList from './FieldList.vue'\nimport FormAntispam from './FormAntispam.vue'\nimport FormEmbed from './FormEmbed.vue'\nimport FormGeneral from './FormGeneral.vue'\nimport FormNotifications from './FormNotifications.vue'\nimport { createInboxApi } from './api'\nimport { reachesAnybody } from './recipients'\nimport { useInboxMessages } from './i18n'\nimport type { FormOptions, InboxField, InboxForm, Recipient } from './types'\n\n/**\n * One form: what it is called, what it asks, who hears about it, and how it is put on a page.\n *\n * Five tabs and one save. The fields are the exception — a question is written in its own\n * dialog and saved on its own, because it is a row with an identity (§2.1) and because a\n * dragged order that waited for a save button would be an order nobody trusts.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/inbox' })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst form = ref<InboxForm | null>(null)\nconst fields = ref<InboxField[]>([])\nconst loading = ref(true)\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nconst settings = reactive<{ slug: string; title: LocalizedValue; is_enabled: boolean }>({\n slug: '',\n title: {},\n is_enabled: true,\n})\n\nconst options = ref<FormOptions>({})\n\nconst TABS = ['general', 'fields', 'notifications', 'antispam', 'embed']\n\n/* Opened on the tab the address names, so the audit's \"open\" lands on the recipients. */\nconst tab = ref(TABS.includes(String(route.query.tab)) ? String(route.query.tab) : 'general')\n\n/*\n * Said above the tabs and not only inside Notifications: a form that tells nobody works in\n * every way somebody can see — the site thanks the visitor, the panel keeps the enquiry — so\n * the only place the gap shows is a line nobody went looking for.\n */\nconst silent = computed(\n () =>\n settings.is_enabled &&\n !reachesAnybody(options.value.recipients as Recipient[] | undefined, form.value?.recipients),\n)\n\nconst canManage = computed(() => context.can('inbox.manage'))\n\nconst id = computed(() => Number(route.params.id))\n\nconst name = computed(() =>\n form.value === null ? '' : localizedValue(settings.title, locales.active.value, settings.slug),\n)\n\n/** Where a submission would come back to: the section, with this form already chosen. */\nconst backTo = computed(() => `${props.base}?form=${id.value}`)\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n const loaded = await api.form(id.value)\n\n form.value = loaded\n fields.value = loaded.fields ?? []\n settings.slug = loaded.slug\n settings.title = { ...loaded.title }\n settings.is_enabled = loaded.is_enabled\n options.value = { ...loaded.options }\n } catch (error) {\n toast.danger(message(error))\n void router.replace(props.base)\n } finally {\n loading.value = false\n }\n}\n\nwatch(id, () => void load(), { immediate: true })\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n try {\n const saved = await api.saveForm(id.value, {\n slug: settings.slug.trim(),\n title: settings.title,\n is_enabled: settings.is_enabled,\n options: options.value,\n })\n\n form.value = saved\n toast.success(t('panel.saved'))\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <!--\n Not a screen that fills its column, whatever the first draft said. `data-wx-fill` makes the\n screen exactly as tall as the window, and nothing inside these tabs scrolls on its own — so\n a form longer than the window grew straight through the box, and the save bar, which is the\n next thing in the column, was drawn across the middle of it with fields still going on\n underneath. What this screen wants is the ordinary thing: the page scrolls, the bar sticks\n to the bottom of it, and `WxMain` gives the screen a floor to push that bar down to.\n -->\n <div class=\"wx-inbox-editor\">\n <!-- On a card, like everything else on this screen: a bare skeleton flush against the\n page is a shape the form that follows it never takes, so the screen jumps twice —\n once when the card appears around it, once when the fields land inside. -->\n <wx-card v-if=\"loading\">\n <wx-skeleton title :rows=\"8\" />\n </wx-card>\n\n <template v-else-if=\"form\">\n <wx-screen-head\n class=\"wx-inbox-editor__head\"\n :title=\"name\"\n :subtitle=\"form.slug\"\n :back=\"backTo\"\n :back-label=\"t('panel.forms')\"\n >\n <template #title-after>\n <wx-badge v-if=\"!settings.is_enabled\" type=\"default\">{{ t('panel.off') }}</wx-badge>\n </template>\n </wx-screen-head>\n\n <!--\n Every tab is mounted at once and the hidden ones keep their state: somebody who wrote\n a thank-you, went to look at the fields and came back should find it still written.\n -->\n <wx-alert\n v-if=\"silent\"\n class=\"wx-inbox-editor__silent\"\n type=\"warning\"\n variant=\"soft\"\n :closable=\"false\"\n :title=\"t('panel.notifies-nobody')\"\n :description=\"t('panel.notifies-nobody-text')\"\n />\n\n <wx-tabs v-model=\"tab\" class=\"wx-inbox-editor__tabs\" keep-alive>\n <wx-tab value=\"general\" :label=\"t('panel.tab-general')\">\n <form-general v-model:settings=\"settings\" v-model:options=\"options\" :errors=\"errors\" />\n </wx-tab>\n\n <wx-tab value=\"fields\" :label=\"t('panel.tab-fields')\">\n <field-list v-model=\"fields\" :form=\"form\" :can-manage=\"canManage\" />\n </wx-tab>\n\n <wx-tab value=\"notifications\" :label=\"t('panel.tab-notifications')\">\n <form-notifications\n v-model=\"options\"\n :fields=\"fields\"\n :errors=\"errors\"\n :reported=\"form.recipients\"\n />\n </wx-tab>\n\n <wx-tab value=\"antispam\" :label=\"t('panel.tab-antispam')\">\n <form-antispam v-model=\"options\" />\n </wx-tab>\n\n <wx-tab value=\"embed\" :label=\"t('panel.tab-embed')\">\n <form-embed :form=\"form\" :slug=\"settings.slug\" :fields=\"fields\" />\n </wx-tab>\n </wx-tabs>\n\n <wx-action-bar v-if=\"canManage\">\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">{{ t('panel.save') }}</wx-button>\n </wx-action-bar>\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-inbox-editor {\n display: flex;\n flex-direction: column;\n /* The panel's own step, which is smaller on a phone than on a desktop. */\n gap: var(--wx-gap, var(--wx-space-16));\n}\n\n/* The tabs take what is left of the column, so the save bar under them is at its bottom\n rather than under the last field. Nothing inside them scrolls on its own — the page does. */\n/* The address it posts to, in the type an address is written in. */\n.wx-inbox-editor__head :deep(.wx-screen-head__subtitle) {\n font-family: var(--wx-font-family-mono);\n}\n\n.wx-inbox-editor__tabs {\n flex: 1 1 auto;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n toast,\n useModal,\n WxButton,\n WxDialog,\n WxFormItem,\n WxInput,\n WxSpace,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxForm } from './types'\n\n/**\n * A form, started.\n *\n * Two fields, because a form has nothing else until it has questions: what it is called and\n * where it answers. Everything else — who is written to, what happens after sending, the\n * antispam — belongs to the editor, and asking for it before the form exists would be a\n * dialog longer than the screen it leads to.\n *\n * The address is typed rather than made out of the title. A page's address is a sentence\n * transliterated; a form's is a short word somebody chooses once and then writes into a\n * template by hand, and guessing `svyazhites-s-nami` for them helps nobody.\n */\nconst { resolve, dismiss, open } = useModal<InboxForm>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst title = ref<LocalizedValue>({})\nconst slug = ref('')\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nfunction errorOf(field: string): string | undefined {\n return errors.value[field]?.[0]\n}\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n try {\n resolve(\n await api.createForm({\n title: title.value,\n slug: slug.value.trim(),\n is_enabled: true,\n options: {},\n }),\n )\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog v-model:open=\"open\" :title=\"t('panel.new-form-title')\" :width=\"520\">\n <div class=\"wx-inbox-create\">\n <wx-form-item :label=\"t('panel.title')\" :error=\"errorOf('title')\" required>\n <wx-input v-model=\"title\" localized autofocus />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.slug')\" :help=\"t('panel.slug-help')\" :error=\"errorOf('slug')\">\n <wx-input v-model=\"slug\" placeholder=\"contact\" />\n </wx-form-item>\n </div>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">\n {{ t('panel.save') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-inbox-create {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n localizedValue,\n toast,\n useLocales,\n useModal,\n WxAlert,\n WxButton,\n WxCheckbox,\n WxCheckboxGroup,\n WxDatePicker,\n WxDialog,\n WxFormItem,\n WxInput,\n WxRadioGroup,\n WxSelect,\n WxSkeleton,\n WxSpace,\n WxTextarea,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxField, InboxForm, InboxSubmission } from './types'\n\n/**\n * A submission typed in by hand — a call that came by telephone, a form filled in on paper.\n *\n * The same questions the site asks, drawn from the same fields, and sent to the same intake:\n * the rules are the form's own, so a required field is required here too and a refusal reads\n * the same way. The one thing the panel cannot do is attach a visitor's file, because there is\n * no visitor — the files a submission carries are what was posted with it.\n */\nconst props = defineProps<{ form: InboxForm }>()\n\nconst { resolve, dismiss, open } = useModal<InboxSubmission>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst fields = ref<InboxField[]>([])\nconst loading = ref(true)\nconst saving = ref(false)\nconst values = ref<Record<string, unknown>>({})\nconst errors = ref<Record<string, string[]>>({})\n\n/** Everything the form actually asks, files excepted. */\nconst asked = computed(() => fields.value.filter((field) => field.type !== 'file'))\n\nconst hasFiles = computed(() => fields.value.some((field) => field.type === 'file'))\n\nfunction errorOf(field: InboxField): string | undefined {\n return errors.value[`fields.${field.key}`]?.[0]\n}\n\nfunction label(field: InboxField): string {\n return localizedValue(field.title, locales.active.value, field.key)\n}\n\nfunction text(value: unknown, fallback = ''): string {\n return localizedValue(\n value as Parameters<typeof localizedValue>[0],\n locales.active.value,\n fallback,\n )\n}\n\n/** The written-down answers of a `select`, `radio` or `checkbox`, in the panel's language. */\nfunction choices(field: InboxField): { value: string; label: string }[] {\n return (field.options.choices ?? []).map((choice) => ({\n value: choice.value,\n label: text(choice.label, choice.value),\n }))\n}\n\nasync function load(): Promise<void> {\n try {\n const form = await api.form(props.form.id)\n\n fields.value = (form.fields ?? []).filter((field) => field.is_enabled)\n\n for (const field of fields.value) {\n values.value[field.key] =\n field.type === 'checkbox' ? [] : field.type === 'consent' ? false : ''\n }\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nvoid load()\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n try {\n resolve(await api.createSubmission(props.form.id, values.value))\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog v-model:open=\"open\" :title=\"t('panel.new-submission-title')\" :width=\"560\">\n <div class=\"wx-inbox-by-hand\">\n <wx-alert type=\"info\" :closable=\"false\">{{ t('panel.new-submission-help') }}</wx-alert>\n\n <wx-skeleton v-if=\"loading\" :rows=\"4\" />\n\n <template v-else>\n <wx-form-item\n v-for=\"field in asked\"\n :key=\"field.id\"\n :label=\"label(field)\"\n :help=\"text(field.help)\"\n :error=\"errorOf(field)\"\n :required=\"field.is_required\"\n >\n <wx-textarea\n v-if=\"field.type === 'textarea'\"\n v-model=\"values[field.key] as string\"\n :rows=\"field.options.rows ?? 4\"\n :placeholder=\"text(field.placeholder)\"\n />\n <wx-select\n v-else-if=\"field.type === 'select'\"\n v-model=\"values[field.key] as string\"\n :options=\"choices(field)\"\n clearable\n :placeholder=\"text(field.placeholder)\"\n />\n <wx-radio-group\n v-else-if=\"field.type === 'radio'\"\n v-model=\"values[field.key] as string\"\n :options=\"choices(field)\"\n />\n <wx-checkbox-group\n v-else-if=\"field.type === 'checkbox'\"\n v-model=\"values[field.key] as string[]\"\n :options=\"choices(field)\"\n />\n <!-- The sentence beside the tick is the form's own and may carry a link, so it is\n the field's label rather than text written here. -->\n <wx-checkbox\n v-else-if=\"field.type === 'consent'\"\n v-model=\"values[field.key] as boolean\"\n :label=\"text(field.options.text, label(field))\"\n />\n <wx-date-picker\n v-else-if=\"field.type === 'date'\"\n v-model=\"values[field.key] as string\"\n :placeholder=\"text(field.placeholder)\"\n />\n <wx-input\n v-else\n v-model=\"values[field.key] as string\"\n :type=\"field.type === 'email' ? 'email' : field.type === 'tel' ? 'tel' : 'text'\"\n :placeholder=\"text(field.placeholder)\"\n :maxlength=\"field.options.maxlength\"\n />\n </wx-form-item>\n\n <!-- Said rather than silently left out: a form whose point is the attachment would\n otherwise look like it had lost a field. -->\n <wx-alert v-if=\"hasFiles\" type=\"warning\" :closable=\"false\">\n {{ t('panel.no-files-by-hand') }}\n </wx-alert>\n </template>\n </div>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" :disabled=\"loading\" @click=\"save\">\n {{ t('panel.save') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-inbox-by-hand {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, useTemplateRef, watch } from 'vue'\nimport { useRoute, useRouter, type LocationQueryRaw } from 'vue-router'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxDate,\n rowMenuWidth,\n WxFilterChips,\n WxRowMenu,\n WxScreenHead,\n type AppliedFilter,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n localizedValue,\n toast,\n useLocales,\n WxAvatar,\n WxBadge,\n WxButton,\n WxIcon,\n WxSelect,\n WxTable,\n WxTabs,\n WxText,\n WxEntityCard,\n WxFormItem,\n WxTooltip,\n useElementWidth,\n type TabItem,\n type TableColumn,\n type TableState,\n} from '@webx-ui/core'\nimport SubmissionCreateDialog from './SubmissionCreateDialog.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type {\n InboxForm,\n InboxStatus,\n InboxSubmission,\n SubmissionRow,\n SubmissionsPage,\n} from './types'\n\n/**\n * What has come in through the chosen form — the right-hand side of the section (§11).\n *\n * Its columns are the form's own `in_table` fields and arrive with the rows, so this never has\n * to fetch the form to know what it is drawing. Which of them survive a narrow pane is decided\n * here and not by the form: the first answer identifies the row and stays at any width, and\n * each one after it goes a step earlier than the last. Pairing two of them into one cell — the\n * e-mail under the name — would mean guessing which fields mean what, and the panel does not\n * know that about somebody else's form.\n *\n * The state of the list lives in the address: coming back from a submission has to land on the\n * same form, the same tab and the same page, or the screen costs exactly that over the dialog\n * it was chosen instead of (§11).\n */\nconst props = withDefaults(\n defineProps<{\n form: InboxForm\n /** Where the section is mounted. */\n base?: string\n }>(),\n { base: '/inbox' },\n)\n\nconst emit = defineEmits<{\n /** Something changed that the column of forms counts. */\n changed: []\n}>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseInboxMessages()\n\n/** Where a row stops being a row. */\nconst CARDS = 640\n\nconst root = useTemplateRef<HTMLElement>('root')\nconst width = useElementWidth(root)\nconst asCards = computed(() => width.value > 0 && width.value < CARDS)\n\n/**\n * One decision about it, not two.\n *\n * The pane measures itself and the table measures itself, and between the two stands the\n * pane's own step — so the same number meant two different widths, and in the band between\n * them the table drew cards out of the full set of columns: five lines of \"Label: value\" for\n * one enquiry, which is exactly what the card exists instead of. The table is told rather\n * than left to work it out: never, or always, and by the same measurement the columns use.\n */\nconst cardsBelow = computed(() => (asCards.value ? Number.POSITIVE_INFINITY : 0))\n\nconst t = useTranslate('webx-inbox')\nconst panel = useTranslate('webx-admin')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst page = ref<SubmissionsPage | null>(null)\nconst statuses = ref<InboxStatus[]>([])\nconst loading = ref(false)\nconst selected = ref<SubmissionRow[]>([])\nconst moving = ref(false)\n\nconst canUpdate = computed(() => context.can('inbox.update'))\n\nconst add = createModal<InboxSubmission, { form: InboxForm }>(SubmissionCreateDialog)\n\n/** The tab, kept in the address so the way back lands on it. */\nconst view = computed({\n get: () =>\n typeof route.query.view === 'string' && route.query.view !== '' ? route.query.view : 'all',\n set: (value: string) => {\n // A new tab is a new list: the page it was on belongs to the tab it was on.\n void router.replace({\n query: { ...route.query, view: value === 'all' ? undefined : value, page: undefined },\n })\n },\n})\n\n/** Everything the list is looking at, as it travels to the server and into the address. */\nconst query = computed(() => ({\n view: view.value,\n search: typeof route.query.search === 'string' ? route.query.search : '',\n assignee: typeof route.query.assignee === 'string' ? route.query.assignee : null,\n placement: typeof route.query.placement === 'string' ? route.query.placement : null,\n sort: typeof route.query.sort === 'string' ? route.query.sort : null,\n page: Number(route.query.page ?? 1) || 1,\n}))\n\n/*\n * Where on the site the form has been sent from — the footer, an article (layout regions §11).\n *\n * The list carries the places with its rows, over the whole form rather than the filter, so the\n * filter costs no request of its own and its choices never shrink to the one already picked. It\n * is offered only when there is more than one place: one form in one place is nothing to filter.\n * And it stays while a placement is in the address, or a filter that arrived by link could not be\n * taken off.\n */\nconst placementOptions = computed(() =>\n (page.value?.placements ?? []).map((placement) =>\n placement === null\n ? { value: 'none', label: t('panel.placement-none') }\n : { value: placement, label: placement },\n ),\n)\n\nconst hasPlacements = computed(\n () => placementOptions.value.length > 1 || query.value.placement !== null,\n)\n\nconst applied = computed<AppliedFilter[]>(() => {\n const placement = query.value.placement\n\n if (placement === null) return []\n\n const label =\n placementOptions.value.find((option) => option.value === placement)?.label ??\n (placement === 'none' ? t('panel.placement-none') : placement)\n\n return [\n {\n key: 'placement',\n label: `${t('panel.meta-placement')}: ${label}`,\n clear: () => narrow(undefined),\n },\n ]\n})\n\nfunction narrow(placement: unknown): void {\n void router.replace({\n query: {\n ...route.query,\n placement: typeof placement === 'string' && placement !== '' ? placement : undefined,\n page: undefined,\n },\n })\n}\n\nconst views = computed<TabItem[]>(() => {\n const counts = page.value?.counts\n\n const items: TabItem[] = [\n { value: 'all', label: t('panel.view-all'), badge: counts?.all || undefined },\n { value: 'unread', label: t('panel.view-unread'), badge: counts?.unread || undefined },\n ]\n\n for (const status of statuses.value) {\n items.push({\n value: status.key,\n label: name(status),\n badge: counts?.statuses[status.key] || undefined,\n })\n }\n\n return items\n})\n\n/**\n * The n-th answer of a submission, for the card that has no columns to put them in.\n *\n * By position rather than by name, because a form's fields are the form's own: the first answer\n * is what the row is recognised by wherever it came from, and the second is the next most likely\n * way to reach whoever wrote it.\n */\nfunction answer(row: SubmissionRow, index: number): string {\n const column = page.value?.columns?.[index]\n\n return column ? (row.values[column.key] ?? '') : ''\n}\n\nconst columns = computed<TableColumn<SubmissionRow>[]>(() => {\n const answers = page.value?.columns ?? []\n\n /*\n * Narrow, a submission is one entity rather than five labelled lines: who wrote it, the next\n * answer under that, and the state of it beside the date. Five lines of \"Label: value\" is four\n * hundred pixels for one enquiry, and an inbox is read in a list.\n */\n if (asCards.value) return [{ key: 'card', label: '' }]\n\n return [\n ...answers.map((column, index) => ({\n key: `values.${column.key}`,\n label: column.label,\n sortable: true,\n // The first answer is what the row is recognised by and stays at any width; every one\n // after it is worth less than the room it takes, so it goes a step sooner. The steps are\n // wide — 640, 960 — because an answer is a sentence and not a number: two of them plus\n // the status and the date is already what a 755px pane holds without scrolling sideways,\n // which is what the pane beside the forms actually is on a 1280 screen (§11).\n hideBelow: index === 0 ? undefined : 320 + index * 320,\n })),\n // A floor rather than a width: the cell holds a badge, sometimes an avatar and sometimes\n // a paperclip, and a fixed width that any of them overflows makes the whole table scroll\n // sideways by two pixels.\n { key: 'status', label: t('panel.status'), minWidth: 100 },\n {\n key: 'created_at',\n label: t('panel.received'),\n sortable: true,\n width: 120,\n // \"today at 16:22\" is three words the table will break over two lines given half a\n // chance, and a date read down a column has to be one line to be read at all.\n cellClass: 'wx-submissions__when',\n hideBelow: 520,\n // Kept on the card, unlike most dates: \"when did this come in\" is one of the two\n // questions a submission is looked at for, and the other one is who sent it.\n },\n { key: 'actions', label: '', width: rowMenuWidth, align: 'right', hideOnCards: true },\n ]\n})\n\n/**\n * Two different nothings, said differently.\n *\n * \"Nothing has ever come in through this form\" is a fact about the form; \"nothing matches\" is\n * a fact about the tab somebody is standing on. Saying the first one on a filtered tab tells a\n * reader their form is dead when it is not.\n */\nconst emptyText = computed(() =>\n query.value.view === 'all' &&\n query.value.search === '' &&\n query.value.assignee === null &&\n query.value.placement === null\n ? t('panel.submissions-empty')\n : t('panel.submissions-none'),\n)\n\nconst statusOptions = computed(() =>\n statuses.value.map((status) => ({ value: status.id, label: name(status) })),\n)\n\nfunction name(status: InboxStatus): string {\n return localizedValue(status.title, locales.active.value, status.key)\n}\n\nfunction formName(): string {\n return localizedValue(props.form.title, locales.active.value, props.form.slug)\n}\n\nasync function load(state?: TableState): Promise<void> {\n loading.value = true\n\n try {\n page.value = await api.submissions(props.form.id, {\n view: query.value.view,\n search: state?.search ?? query.value.search,\n assignee: query.value.assignee,\n placement: query.value.placement,\n sort: state?.sort ? `${state.sort.order === 'desc' ? '-' : ''}${state.sort.key}` : null,\n page: state?.page ?? query.value.page,\n per_page: state?.perPage,\n })\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\n/**\n * The table reports everything it knows in one event, and that is the one place the address is\n * written from — so a page, a sort and a search all survive opening a submission and coming\n * back, and none of them has its own half of the bookkeeping.\n */\nfunction onState(state: TableState): void {\n const wanted: LocationQueryRaw = {\n ...route.query,\n search: state.search === '' ? undefined : state.search,\n sort:\n state.sort === null\n ? undefined\n : `${state.sort.order === 'desc' ? '-' : ''}${state.sort.key}`,\n page: state.page === 1 ? undefined : String(state.page),\n }\n\n void router.replace({ query: wanted })\n void load(state)\n}\n\n/* The form changes under the pane — the left column is a list, not a navigation — so the list\n has to notice rather than go on showing the previous form's submissions. One source per value,\n not a getter returning an array: that array is new on every change of the address, so a page\n turn would clear the selection and ask a second time, racing the request `onState` sent. */\nwatch([() => props.form.id, view, () => query.value.assignee, () => query.value.placement], () => {\n selected.value = []\n void load()\n})\n\nvoid load()\nvoid statusList()\n\nasync function statusList(): Promise<void> {\n try {\n statuses.value = await api.statuses()\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\n/** Opening one carries the whole filter along, so its arrows walk the list it came from. */\nfunction open(row: SubmissionRow): void {\n void router.push({ path: `${props.base}/submissions/${row.id}`, query: { ...route.query } })\n}\n\nfunction actionsFor(row: SubmissionRow): RowAction[] {\n if (!canUpdate.value) return []\n\n return [\n {\n key: 'read',\n icon: row.is_read ? 'eye-off' : 'eye',\n label: row.is_read ? t('panel.mark-unread') : t('panel.mark-read'),\n run: () => void mass([row.id], row.is_read ? 'unread' : 'read'),\n },\n {\n key: 'delete',\n icon: 'trash',\n label: t('panel.delete'),\n danger: true,\n run: () => void remove([row.id]),\n },\n ]\n}\n\nasync function moveTo(statusId: unknown): Promise<void> {\n if (typeof statusId !== 'number') return\n\n moving.value = true\n await mass(\n selected.value.map((row) => row.id),\n 'status',\n statusId,\n )\n moving.value = false\n}\n\nasync function remove(ids: number[]): Promise<void> {\n const agreed = await confirm({\n title:\n ids.length === 1\n ? t('panel.delete-submission-title')\n : t('panel.delete-selected-title', { count: ids.length }),\n message: t('panel.delete-submission-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n await mass(ids, 'delete')\n}\n\nasync function mass(\n ids: number[],\n action: 'status' | 'read' | 'unread' | 'delete',\n statusId?: number,\n): Promise<void> {\n if (ids.length === 0) return\n\n try {\n await api.massSubmissions({ ids, action, status_id: statusId })\n selected.value = []\n await load()\n emit('changed')\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function byHand(): Promise<void> {\n const made = await add({ form: props.form })\n\n if (!made) return\n\n toast.success(t('panel.created'))\n await load()\n emit('changed')\n void router.push({ path: `${props.base}/submissions/${made.id}`, query: { ...route.query } })\n}\n\n/**\n * A plain link and not a fetch: the browser downloads files, and pulling a spreadsheet into\n * memory to hand it straight back is work for nothing. It carries the filter that is on, so\n * what comes out is what is on screen.\n */\nconst exportHref = computed(() =>\n api.exportUrl(props.form.id, {\n view: query.value.view,\n search: query.value.search,\n assignee: query.value.assignee,\n placement: query.value.placement,\n sort: query.value.sort,\n }),\n)\n\n/*\n * The tools of the pane are what is done to this list of answers, and that is one thing:\n * take them away as a file.\n *\n * What the form is — its fields, its letters, its address — belongs to the form's own ··· in\n * the list of forms. And writing a submission is the section's own action, so it stands in\n * the head of the section beside its name (§11); the dialog is still this component's, which\n * is why it is exposed rather than moved: what is created has to land in this list, in this\n * filter, and be counted in these tabs.\n */\nconst actions = computed<ScreenAction[]>(() => [\n { key: 'export', label: t('panel.export'), icon: 'download', href: exportHref.value },\n])\n\ndefineExpose({ create: byHand })\n</script>\n\n<template>\n <div ref=\"root\" class=\"wx-submissions\">\n <wx-screen-head\n class=\"wx-submissions__head\"\n :level=\"3\"\n :title=\"formName()\"\n :subtitle=\"form.slug\"\n :actions=\"actions\"\n />\n\n <!--\n `items` and one panel: the table stays mounted while the tab changes, so the search\n somebody typed does not go with it.\n -->\n <wx-tabs\n v-model=\"view\"\n class=\"wx-submissions__views\"\n :items=\"views\"\n :collapse-below=\"560\"\n :aria-label=\"t('panel.status')\"\n >\n <wx-table\n :data=\"page\"\n :columns=\"columns\"\n row-key=\"id\"\n searchable\n clickable\n hover\n flush\n :loading=\"loading\"\n :selectable=\"canUpdate\"\n :select-row-label=\"panel('filters.select-row')\"\n :select-all-label=\"panel('filters.select-all')\"\n :row-class=\"(row: SubmissionRow) => (row.is_read ? undefined : 'is-unread')\"\n :search-placeholder=\"t('panel.search-submissions')\"\n :empty-text=\"emptyText\"\n :cards-below=\"cardsBelow\"\n :filters-count=\"applied.length\"\n @row-click=\"open\"\n @state-change=\"onState\"\n @selection-change=\"(_keys: unknown, rows: SubmissionRow[]) => (selected = rows)\"\n >\n <!-- The pile only offers what can be done to all of it at once; one row's own menu\n keeps the rest. -->\n <template v-if=\"selected.length > 0\" #actions>\n <div class=\"wx-submissions__mass\">\n <wx-text size=\"sm\" weight=\"medium\">\n {{ t('panel.selected', { count: selected.length }) }}\n </wx-text>\n <wx-select\n :model-value=\"null\"\n :options=\"statusOptions\"\n :placeholder=\"t('panel.move-to')\"\n :disabled=\"moving\"\n size=\"sm\"\n style=\"width: 180px\"\n @update:model-value=\"moveTo\"\n />\n <wx-button\n size=\"sm\"\n variant=\"outline\"\n type=\"danger\"\n icon=\"trash\"\n @click=\"remove(selected.map((row) => row.id))\"\n >\n {{ t('panel.delete') }}\n </wx-button>\n </div>\n </template>\n\n <template v-if=\"hasPlacements\" #filters>\n <wx-form-item :label=\"t('panel.meta-placement')\">\n <wx-select\n :model-value=\"query.placement\"\n :options=\"placementOptions\"\n :placeholder=\"t('panel.any-placement')\"\n clearable\n size=\"sm\"\n @update:model-value=\"narrow\"\n />\n </wx-form-item>\n </template>\n\n <template v-if=\"applied.length > 0\" #applied>\n <wx-filter-chips :filters=\"applied\" />\n </template>\n\n <template #cell-status=\"{ row }\">\n <div class=\"wx-submissions__state\">\n <wx-badge v-if=\"row.status\" :type=\"row.status.color\">{{ name(row.status) }}</wx-badge>\n <!-- The assignee is an avatar beside the status rather than a column: at the\n width this pane has, a column of names costs an answer (§11). -->\n <wx-avatar\n v-if=\"row.assignee\"\n :name=\"row.assignee.name\"\n :title=\"row.assignee.name\"\n size=\"xs\"\n tone=\"auto\"\n />\n <wx-tooltip v-if=\"row.files_count > 0\" :content=\"t('panel.attachments')\">\n <wx-icon name=\"file\" size=\"sm\" />\n </wx-tooltip>\n </div>\n </template>\n\n <template #cell-created_at=\"{ row }\">\n <wx-date :value=\"row.created_at\" compact />\n </template>\n\n <template #cell-card=\"{ row }\">\n <wx-entity-card variant=\"plain\" shape=\"circle\" :title=\"answer(row, 0)\">\n <template #subtitle>{{ answer(row, 1) }}</template>\n\n <template #meta>\n <wx-badge v-if=\"row.status\" :type=\"row.status.color\" size=\"sm\">\n {{ name(row.status) }}\n </wx-badge>\n <wx-avatar\n v-if=\"row.assignee\"\n :name=\"row.assignee.name\"\n :title=\"row.assignee.name\"\n size=\"xs\"\n tone=\"auto\"\n />\n <wx-icon v-if=\"row.files_count > 0\" name=\"file\" size=\"sm\" />\n <wx-date :value=\"row.created_at\" />\n </template>\n </wx-entity-card>\n </template>\n\n <template #card-actions=\"{ row }\">\n <wx-row-menu :actions=\"actionsFor(row)\" :label=\"String(row.id)\" />\n </template>\n\n <template #cell-actions=\"{ row }\">\n <wx-row-menu :actions=\"actionsFor(row)\" :label=\"String(row.id)\" />\n </template>\n </wx-table>\n </wx-tabs>\n </div>\n</template>\n\n<style scoped>\n/*\n * One step, and everything in the pane keeps it.\n *\n * The panel's own — 8 on a phone and 16 on a desktop — and not a number of this screen's own.\n * Written as 16 here, the pane kept desktop air on a 375px screen: the head, the tabs and the\n * rows each took a line of nothing between them, and four rows fitted where six do now.\n *\n * It is the pane that holds it, so the name of the form, the tabs, the search box and the rows\n * all begin on the same line down the left. The table used to add a step of its own inside\n * this one — measured on a phone: the head at 17 and the search at 33 — and two insets, one\n * for the words and one for the list they are about, read as two panels stacked rather than as\n * one screen.\n */\n.wx-submissions {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n padding: var(--wx-gap, var(--wx-space-16));\n min-width: 0;\n}\n\n/* The address the form posts to, in the type an address is written in. */\n.wx-submissions__head :deep(.wx-screen-head__subtitle) {\n font-family: var(--wx-font-family-mono);\n}\n\n/*\n * The tabs and the rows they filter are one thing, so they stand closer than two things do.\n * `WxTabs` leaves the panel's step under the strip, which is right where a card follows it;\n * here what follows is the search box of the same table, and a full step between a filter and\n * what it filters reads as a gap between two screens.\n */\n.wx-submissions__views :deep(.wx-tabs__panels) {\n padding-top: var(--wx-space-8);\n}\n\n.wx-submissions__mass {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n flex-wrap: wrap;\n}\n\n/* `:deep()` because the cell is the table's element and the class is ours — a scoped rule\n would be looking for our attribute on somebody else's markup (CLAUDE.md §4). */\n.wx-submissions :deep(.wx-submissions__when) {\n white-space: nowrap;\n}\n\n.wx-submissions__state {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--wx-space-6);\n min-width: 0;\n}\n\n/*\n * What nobody has opened yet, said on the whole row. `:deep()` because the row is the table's\n * element and the class is ours — a scoped rule would be looking for our attribute on somebody\n * else's markup (CLAUDE.md §4).\n */\n.wx-submissions :deep(.is-unread) {\n font-weight: var(--wx-font-weight-medium);\n}\n\n.wx-submissions :deep(.is-unread) td:first-child {\n box-shadow: inset 2px 0 0 0 var(--wx-color-primary);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, useTemplateRef, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxListScreen,\n WxRowMenu,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n localizedValue,\n toast,\n useLocales,\n WxAction,\n WxButton,\n WxCard,\n WxEmpty,\n WxIcon,\n WxIndicator,\n WxListDetail,\n WxSkeleton,\n WxSortableList,\n WxText,\n} from '@webx-ui/core'\nimport FormCreateDialog from './FormCreateDialog.vue'\nimport SubmissionList from './SubmissionList.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxForm } from './types'\n\n/**\n * The section: the forms of the site on the left, what came in through one of them on the\n * right (§11, §2.12).\n *\n * One screen rather than two, and that is the decision this is built around. The columns of\n * the list are the fields of the chosen form, so a list of everything would have no columns\n * to speak of; and the two questions somebody opens this section to ask — \"what is new\" and\n * \"what does this form ask\" — are one click apart instead of one screen apart.\n *\n * Which of the two is the screen and which is the chooser is the second decision. The forms\n * are the chooser: they are the `filters` column of the pane, so on a phone they fold into a\n * panel and the submissions are what the section opens on. The other way round — forms as the\n * list, submissions as the record beside it — is what this was, and it cost the reader a\n * screen: somebody who opens the section is asking what came in, and was shown a list of\n * three form names instead, every time.\n *\n * One form is therefore always open (the first, unless the address names another), and what\n * is here is the column: the forms, in the order somebody dragged them, with what is waiting\n * in each.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/inbox' })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst forms = ref<InboxForm[]>([])\nconst loading = ref(true)\n\n/** The list of submissions, for the one action of its own that the section's head carries. */\nconst pane = useTemplateRef<{ create: () => void }>('pane')\n\n/**\n * Whether the forms still have a column, and whether their panel is up.\n *\n * Both live here rather than inside the pane because the way to the forms is in the head of\n * the section, beside its other actions — a button that appears exactly when the column is\n * gone. The pane says when that is.\n */\nconst columnInline = ref(true)\nconst formsOpen = ref(false)\n\nconst canManage = computed(() => context.can('inbox.manage'))\n\nconst create = createModal<InboxForm, Record<string, never>>(FormCreateDialog)\n\nconst title = computed(\n () =>\n context.state.manifest?.modules.find((module) => module.id === 'inbox')?.title ??\n t('module.title'),\n)\n\n/**\n * Which form is open, kept in the address.\n *\n * So that coming back from a submission lands on the form it belonged to (§11) — and so that\n * a link to \"the callback form\" is a link somebody can send.\n */\nconst current = computed<number | null>(() => {\n const asked = route.query.form\n\n return typeof asked === 'string' && asked !== '' ? Number(asked) : null\n})\n\nconst chosen = computed(() => forms.value.find((form) => form.id === current.value) ?? null)\n\nfunction name(form: InboxForm): string {\n return localizedValue(form.title, locales.active.value, form.slug)\n}\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n forms.value = await api.forms()\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nvoid load()\n\n/**\n * One form is always open, and the address always says which.\n *\n * The section is the submissions, so the first form stands in until somebody picks another —\n * on a phone especially, where the alternative is opening the panel before seeing anything at\n * all. It covers the address that names no form, the address that names one that has since\n * been deleted, and the list arriving after the address did; `replace`, because none of the\n * three is a place worth going back to.\n */\nwatch([forms, chosen], () => {\n if (forms.value.length === 0 || chosen.value !== null) return\n\n void router.replace({ query: { ...route.query, form: String(forms.value[0].id) } })\n})\n\nfunction choose(form: InboxForm, close: () => void): void {\n void router.replace({ query: { ...route.query, form: String(form.id) } })\n /* Picked from the panel: the panel has done its job. It is a column on a wide screen, and\n closing what is not open does nothing there. */\n close()\n}\n\nfunction edit(form: InboxForm): void {\n void router.push(`${props.base}/forms/${form.id}`)\n}\n\nfunction actionsFor(form: InboxForm): RowAction[] {\n if (!canManage.value) return []\n\n return [\n { key: 'settings', icon: 'settings', label: t('panel.settings'), run: () => edit(form) },\n { key: 'duplicate', icon: 'copy', label: t('panel.duplicate'), run: () => duplicate(form) },\n // A form that has taken submissions is switched off, never deleted (§2.4). The line is\n // left out rather than greyed: a menu is a list of what is possible.\n ...(form.submissions_count === 0\n ? [\n {\n key: 'delete',\n icon: 'trash' as const,\n label: t('panel.delete'),\n danger: true,\n run: () => remove(form),\n },\n ]\n : []),\n ]\n}\n\nasync function add(): Promise<void> {\n const made = await create({})\n\n if (made) {\n await load()\n edit(made)\n }\n}\n\nasync function duplicate(form: InboxForm): Promise<void> {\n try {\n const copy = await api.duplicateForm(form.id)\n toast.success(t('panel.duplicated'))\n await load()\n edit(copy)\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function remove(form: InboxForm): Promise<void> {\n const agreed = await confirm({\n title: t('panel.delete-form-title', { form: name(form) }),\n message: t('panel.delete-form-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeForm(form.id)\n toast.success(t('panel.deleted'))\n\n /* The address named the form that is gone; what stands in its place is decided above. */\n if (current.value === form.id) {\n const rest = { ...route.query }\n delete rest.form\n void router.replace({ query: rest })\n }\n\n await load()\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\n/**\n * The whole order, every time.\n *\n * The list is already in its new order on screen — `WxSortableList` reorders the model before\n * it says anything — so this only has to agree with what is there, and a failure has to put\n * the list back rather than leave the screen disagreeing with the database.\n */\nasync function reorder(): Promise<void> {\n try {\n await api.sortForms(forms.value.map((form) => form.id))\n } catch (error) {\n toast.danger(message(error, t('panel.reorder-failed')))\n await load()\n }\n}\n\n/**\n * What the section offers. Declared, because on a phone the head folds it into the ···.\n *\n * The one it exists for is a submission, not a form: this is the inbox, and the section is\n * opened dozens of times for what came in for every once that a form is added. A new form is\n * the `+` over the list of forms — beside the thing it makes one more of — and what used to\n * stand here as the primary button was that, which is why it was the biggest thing on the\n * screen and almost never what anybody wanted.\n */\nconst actions = computed<ScreenAction[]>(() => {\n const list: ScreenAction[] = []\n\n if (canManage.value) {\n list.push({\n key: 'statuses',\n label: t('panel.statuses'),\n icon: 'tag',\n run: () => void router.push(`${props.base}/statuses`),\n })\n }\n\n /* The dialog belongs to the list: what is written has to land in it, in the filter that is\n on, and be counted in its tabs. The head only asks for it. */\n if (context.can('inbox.update') && chosen.value !== null) {\n list.push({\n key: 'new-submission',\n label: t('panel.new-submission'),\n icon: 'plus',\n primary: true,\n run: () => void pane.value?.create(),\n })\n }\n\n return list\n})\n</script>\n\n<template>\n <wx-list-screen :title=\"title\" :actions=\"actions\" :card=\"false\">\n <!--\n Written here rather than declared as an action, because an action folds behind the ···\n on a narrow head and this is only ever drawn on one: it is the way to the forms for a\n reader whose column of them is gone. It stands where the other actions of the section\n stand, beside the one that writes a submission.\n -->\n <template v-if=\"!columnInline\" #actions>\n <wx-button variant=\"outline\" @click=\"formsOpen = true\">\n <template #icon><wx-icon name=\"list\" /></template>\n {{ t('panel.forms') }}\n </wx-button>\n </template>\n\n <wx-card class=\"wx-inbox\" padding=\"none\">\n <wx-list-detail\n v-model:filters-open=\"formsOpen\"\n class=\"wx-inbox__panes\"\n :filters-width=\"270\"\n :detail-min=\"420\"\n :filters-title=\"t('panel.forms')\"\n @filters-inline=\"columnInline = $event\"\n >\n <!--\n The forms are what narrows the list, so they are the column that folds: on a phone\n this is a panel raised from the head of the submissions, and the submissions are\n the screen.\n -->\n <template #filters=\"{ inline, close }\">\n <wx-skeleton v-if=\"loading\" class=\"wx-inbox__loading\" :rows=\"5\" />\n\n <template v-else>\n <!--\n In the panel the `+` would stand alone on a line of its own under the drawer's\n own heading, which reads as a stray mark rather than as a control. There is\n room for the word here, so it takes it.\n -->\n <wx-button\n v-if=\"!inline && canManage\"\n class=\"wx-inbox__new-form\"\n variant=\"outline\"\n block\n @click=\"add\"\n >\n <template #icon><wx-icon name=\"plus\" /></template>\n {{ t('panel.new-form') }}\n </wx-button>\n\n <!--\n A grip and not the whole row: the row is what opens a form, and a list whose\n rows both open and drag is a list where one of the two happens by accident.\n -->\n <wx-sortable-list\n v-model=\"forms\"\n class=\"wx-inbox__forms\"\n :class=\"{ 'is-panel': !inline }\"\n plain\n size=\"sm\"\n item-key=\"id\"\n :item-label=\"name\"\n :disabled=\"!canManage\"\n :title=\"inline ? t('panel.forms') : undefined\"\n @move=\"reorder\"\n >\n <!--\n A new form is made where the forms are and not in the head of the section: it\n is one more of these, and it is asked for once for every few dozen times\n somebody opens the inbox to read what came in. An icon, because the word for\n it is already written beside it.\n -->\n <template v-if=\"inline && canManage\" #extra>\n <wx-action icon=\"plus\" size=\"sm\" :title=\"t('panel.new-form')\" @click=\"add\" />\n </template>\n\n <template #default=\"{ item }\">\n <button\n type=\"button\"\n class=\"wx-inbox-form\"\n :class=\"{ 'is-current': item.id === current, 'is-off': !item.is_enabled }\"\n @click=\"choose(item, close)\"\n >\n <!--\n A switched-off form is said by the name itself — struck through and grey —\n rather than by a badge beside it. The badge was a second thing on a line\n 270px wide that already holds a name, a count and the ···: it did not\n shrink, so it ran under the menu, and it said in a word what the type says\n at a glance.\n -->\n <span class=\"wx-inbox-form__name\">\n <wx-text truncate weight=\"medium\" :tone=\"item.is_enabled ? 'default' : 'muted'\">\n {{ name(item) }}\n </wx-text>\n\n <!--\n On the name's line, not under it. The list stacks what the slot hands it,\n so a count standing beside the form was a third line under the address —\n the row grew by a line to say a single digit. Unread first and in colour;\n the total behind it, quietly, because it is context rather than work.\n -->\n <!-- Only on a form that is switched on: one that is off tells nobody\n because nobody can send it. -->\n <wx-icon\n v-if=\"item.is_enabled && item.notifies === false\"\n class=\"wx-inbox-form__silent\"\n name=\"warning\"\n :label=\"t('panel.notifies-nobody-short')\"\n :title=\"t('panel.notifies-nobody-short')\"\n />\n <wx-indicator\n v-if=\"item.unread_count\"\n class=\"wx-inbox-form__count\"\n type=\"primary\"\n :value=\"item.unread_count\"\n :label=\"t('panel.unread')\"\n />\n <wx-indicator\n v-else-if=\"item.submissions_count\"\n class=\"wx-inbox-form__count\"\n type=\"neutral\"\n :value=\"item.submissions_count\"\n :label=\"t('panel.submissions')\"\n />\n </span>\n <wx-text size=\"sm\" tone=\"muted\" truncate>{{ item.slug }}</wx-text>\n </button>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-row-menu :actions=\"actionsFor(item)\" :label=\"name(item)\" />\n </template>\n </wx-sortable-list>\n </template>\n </template>\n\n <!--\n The submissions of the chosen form, and the screen. The pane is the list's, head\n and all: what is above the rows — which form this is, the way to another one where\n there is no column for them — belongs beside the tabs.\n\n Nothing chosen and nothing loading means the site has no forms yet, since a form\n that exists is picked for the reader. The word about it goes here rather than in\n the column, because here is what a phone shows.\n -->\n <template #list>\n <wx-skeleton v-if=\"loading\" class=\"wx-inbox__loading\" :rows=\"6\" />\n\n <submission-list\n v-else-if=\"chosen\"\n ref=\"pane\"\n :key=\"chosen.id\"\n :form=\"chosen\"\n :base=\"props.base\"\n @changed=\"load\"\n />\n\n <wx-empty v-else :title=\"t('panel.no-forms')\" :description=\"t('panel.no-forms-help')\" />\n </template>\n </wx-list-detail>\n </wx-card>\n </wx-list-screen>\n</template>\n\n<style>\n/*\n * What scrolls here is the page.\n *\n * The section used to be as tall as the window, with the rows scrolling inside a box of their\n * own: a second scroller inside the first, its bar running down the middle of the screen, and\n * a wheel that meant one thing over the rows and another an inch to the left. Page after page\n * of the panel scrolls as a page; this one now does too, and the card is as tall as what is\n * in it.\n *\n * The card's corners are still the screen's corners. The two panes inside are square and paint\n * their own background right up to the edge, so without the clip they covered the rounding —\n * four white notches poking out of the card, most visible where the column divider and the\n * bottom rule of the list meet it. `clip` rather than `hidden`: `hidden` would make this a\n * scroll container again, and everything sticky inside would pin itself to a box that never\n * moves (CLAUDE.md §4).\n */\n.wx-inbox > .wx-card__body {\n display: flex;\n flex-direction: column;\n overflow: clip;\n border-radius: inherit;\n}\n\n.wx-inbox__loading {\n padding: var(--wx-space-16);\n}\n\n.wx-inbox__forms {\n padding: var(--wx-space-8) var(--wx-space-12);\n}\n\n/* In the panel the sheet is the column, and it insets what it holds already: a second step\n inside the first stands the same list further from the edge than it stands anywhere else\n (CLAUDE.md §4). */\n.wx-inbox__forms.is-panel {\n padding: 0;\n}\n\n/*\n * A plain list draws its rows edge to edge, which is right until one of them is tinted: the\n * highlight then starts exactly at the first letter and ends exactly at the `···`, so the\n * chosen form reads as a stain rather than as a row, and it sits flush against the rule that\n * divides the two columns. The padding is inside the tint, not around it.\n */\n.wx-inbox__forms.is-plain .wx-sortable-list__row {\n padding-inline: var(--wx-space-8);\n}\n\n/*\n * Air under the rule that carries the column's name, and the rows' own step beside it.\n *\n * The first row started exactly where the line ended, and the first row here is usually the\n * tinted one — so the chosen form read as hanging off the heading rather than as the first of\n * a list. Visible in the dark theme first, where the tint is a shape of its own.\n *\n * The step is the one the rows take inside their tint (above), so the name of the column\n * begins where the names of the forms do and the `+` stands over the row of `···` rather\n * than eight pixels to the right of them. Measured: 338 against 330.\n */\n.wx-inbox__forms.is-plain .wx-sortable-list__head {\n margin-block-end: var(--wx-space-6);\n padding-inline: var(--wx-space-8);\n}\n\n.wx-inbox-form {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-2);\n align-items: flex-start;\n /* The row is the target, so it takes the row: a name of four letters should not leave\n three quarters of the line dead. */\n flex: 1 1 auto;\n min-width: 0;\n padding: 0;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n}\n\n.wx-inbox-form__name {\n display: flex;\n align-items: center;\n gap: var(--wx-space-6);\n min-width: 0;\n max-width: 100%;\n}\n\n/*\n * Switched off: struck through and grey. On the name alone and not on the line it stands in,\n * because what is off is the form — the count beside it is still true, and a decoration set\n * on the row would run through that too and could not be taken off a child. The grey comes\n * from the text's own `tone`, since `WxText` declares its colour on its own element and an\n * inherited one would never reach it (CLAUDE.md §4).\n */\n.wx-inbox-form.is-off .wx-inbox-form__name > .wx-text {\n text-decoration: line-through;\n}\n\n/*\n * The chosen form, marked on the whole row rather than on the name inside it: the row is what\n * was clicked, and a colour on the words alone leaves the grip and the menu looking like they\n * belong to something else. `:has()` because the row is the list's element and the class is\n * ours — the slot cannot reach the element it is drawn into.\n */\n.wx-inbox__forms .wx-sortable-list__row:has(.wx-inbox-form.is-current) {\n background: var(--wx-bg-subtle);\n border-radius: var(--wx-radius-sm);\n}\n\n.wx-inbox-form.is-current {\n color: var(--wx-color-primary);\n}\n\n.wx-inbox-form__silent {\n flex: none;\n color: var(--wx-color-warning);\n}\n\n.wx-inbox-form__count {\n flex: 0 0 auto;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n toast,\n useModal,\n WxButton,\n WxCheckbox,\n WxDialog,\n WxFormItem,\n WxInput,\n WxSelect,\n WxSpace,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport { STATUS_COLORS, type InboxStatus, type StatusColor } from './types'\n\n/**\n * One state, written.\n *\n * The colour is a tone rather than a swatch: the panel has a light theme and a dark one, and\n * a colour picked in one of them is unreadable in the other.\n *\n * Nothing here refuses a second default — the server clears the flag on whoever had it, which\n * is what somebody moving the default from one status to another means, and refusing the save\n * would be the other reading of the same click.\n */\nconst props = defineProps<{ status: InboxStatus | null }>()\n\nconst { resolve, dismiss, open } = useModal<InboxStatus>()\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst key = ref('')\nconst title = ref<LocalizedValue>({})\nconst color = ref<StatusColor>('default')\nconst isDefault = ref(false)\nconst isSpam = ref(false)\nconst isClosed = ref(false)\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nwatch(\n () => props.status,\n (status) => {\n key.value = status?.key ?? ''\n title.value = { ...(status?.title ?? {}) }\n color.value = status?.color ?? 'default'\n isDefault.value = status?.is_default ?? false\n isSpam.value = status?.is_spam ?? false\n isClosed.value = status?.is_closed ?? false\n errors.value = {}\n },\n { immediate: true },\n)\n\nconst colors = computed(() =>\n STATUS_COLORS.map((one) => ({ value: one, label: t(`panel.color-${one}`) })),\n)\n\nfunction errorOf(field: string): string | undefined {\n return errors.value[field]?.[0]\n}\n\nasync function save(): Promise<void> {\n saving.value = true\n errors.value = {}\n\n const input = {\n key: key.value.trim(),\n title: title.value,\n color: color.value,\n is_default: isDefault.value,\n is_spam: isSpam.value,\n is_closed: isClosed.value,\n }\n\n try {\n resolve(\n props.status === null\n ? await api.createStatus(input)\n : await api.saveStatus(props.status.id, input),\n )\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors) {\n errors.value = body.errors\n toast.danger(t('panel.failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog\n v-model:open=\"open\"\n :title=\"status ? t('panel.settings') : t('panel.new-status')\"\n :width=\"520\"\n >\n <div class=\"wx-inbox-status-form\">\n <wx-form-item :label=\"t('panel.title')\" :error=\"errorOf('title')\" required>\n <wx-input v-model=\"title\" localized />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.status-key')\" :error=\"errorOf('key')\" required>\n <wx-input v-model=\"key\" placeholder=\"in-progress\" />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.status-color')\" :error=\"errorOf('color')\">\n <wx-select v-model=\"color\" :options=\"colors\" />\n </wx-form-item>\n\n <div class=\"wx-inbox-status-form__checks\">\n <wx-checkbox v-model=\"isDefault\" :label=\"t('panel.status-default')\" />\n <wx-checkbox v-model=\"isSpam\" :label=\"t('panel.status-spam')\" />\n <wx-checkbox v-model=\"isClosed\" :disabled=\"isSpam\" :label=\"t('panel.status-closed')\" />\n </div>\n </div>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" @click=\"save\">{{ t('panel.save') }}</wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-inbox-status-form {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n\n.wx-inbox-status-form__checks {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-16);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxListScreen,\n WxRowMenu,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n localizedValue,\n toast,\n useLocales,\n WxBadge,\n WxEmpty,\n WxSortableList,\n WxText,\n} from '@webx-ui/core'\nimport StatusDialog from './StatusDialog.vue'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxStatus } from './types'\n\n/**\n * The states a submission can be in (§2.11).\n *\n * Rows rather than an enum, because every panel ends up wanting its own words — and the flags\n * are what the section reads, not the keys, so renaming \"New\" to whatever this client calls\n * it keeps it the status a new submission gets.\n *\n * Their order is the order of the tabs over the list of submissions, which is why it is\n * dragged rather than typed.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/inbox' })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst statuses = ref<InboxStatus[]>([])\nconst loading = ref(true)\n\nconst canManage = context.can('inbox.manage')\n\nconst edit = createModal<InboxStatus, { status: InboxStatus | null }>(StatusDialog)\n\nfunction name(status: InboxStatus): string {\n return localizedValue(status.title, locales.active.value, status.key)\n}\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n statuses.value = await api.statuses()\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nvoid load()\n\nasync function open(status: InboxStatus | null): Promise<void> {\n if (await edit({ status })) await load()\n}\n\nasync function remove(status: InboxStatus): Promise<void> {\n const agreed = await confirm({\n title: t('panel.delete-status-title', { status: name(status) }),\n message: t('panel.delete-status-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeStatus(status.id)\n toast.success(t('panel.deleted'))\n await load()\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nfunction actionsFor(status: InboxStatus): RowAction[] {\n if (!canManage) return []\n\n return [\n { key: 'edit', icon: 'edit', label: t('panel.settings'), run: () => void open(status) },\n // A status with submissions in them cannot go: they would have nothing to be in. The\n // line is left out rather than greyed, the way every list of the panel does it.\n ...(status.submissions_count === 0\n ? [\n {\n key: 'delete',\n icon: 'trash' as const,\n label: t('panel.delete'),\n danger: true,\n run: () => void remove(status),\n },\n ]\n : []),\n ]\n}\n\n/* What the section offers. Declared, because on a phone the head folds it into the ···. */\nconst actions = computed<ScreenAction[]>(() =>\n canManage\n ? [\n {\n key: 'new',\n label: t('panel.new-status'),\n icon: 'plus',\n primary: true,\n run: () => void open(null),\n },\n ]\n : [],\n)\n\nasync function reorder(): Promise<void> {\n try {\n await api.sortStatuses(statuses.value.map((status) => status.id))\n } catch (error) {\n toast.danger(message(error, t('panel.reorder-failed')))\n await load()\n }\n}\n</script>\n\n<template>\n <div class=\"wx-inbox-statuses\">\n <wx-list-screen\n :title=\"t('panel.statuses')\"\n :back=\"props.base\"\n :back-label=\"t('panel.forms')\"\n :actions=\"actions\"\n >\n <wx-empty v-if=\"!loading && statuses.length === 0\" :title=\"t('panel.no-statuses')\" />\n\n <wx-sortable-list\n v-else\n v-model=\"statuses\"\n plain\n item-key=\"id\"\n :item-label=\"name\"\n :disabled=\"!canManage\"\n :aria-label=\"t('panel.statuses')\"\n @move=\"reorder\"\n >\n <template #default=\"{ item }\">\n <div class=\"wx-inbox-status\">\n <wx-badge :type=\"item.color\">{{ name(item) }}</wx-badge>\n\n <wx-text size=\"sm\" tone=\"muted\" truncate>\n <code>{{ item.key }}</code>\n <template v-if=\"item.is_default\"> · {{ t('panel.status-default') }}</template>\n <template v-if=\"item.is_spam\"> · {{ t('panel.status-spam') }}</template>\n <template v-else-if=\"item.is_closed\"> · {{ t('panel.status-closed') }}</template>\n <template v-if=\"item.submissions_count\">\n · {{ t('panel.in-use') }} ({{ item.submissions_count }})\n </template>\n </wx-text>\n </div>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-row-menu :actions=\"actionsFor(item)\" :label=\"name(item)\" />\n </template>\n </wx-sortable-list>\n </wx-list-screen>\n </div>\n</template>\n\n<style scoped>\n.wx-inbox-statuses {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--wx-space-12);\n}\n\n.wx-inbox-statuses > .wx-list-screen {\n align-self: stretch;\n}\n\n.wx-inbox-status {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n flex: 1 1 auto;\n min-width: 0;\n flex-wrap: wrap;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxDate,\n WxNotes,\n WxScreenHead,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n localizedValue,\n toast,\n useLocales,\n WxAction,\n WxAlert,\n WxBadge,\n WxButton,\n WxCard,\n WxDescriptions,\n WxDescriptionsItem,\n WxEmpty,\n WxFileCard,\n WxSelect,\n WxSkeleton,\n WxTab,\n WxTabs,\n WxText,\n WxTimeline,\n WxTimelineItem,\n} from '@webx-ui/core'\nimport { createInboxApi } from './api'\nimport { useInboxMessages } from './i18n'\nimport type { InboxRecipient, InboxStatus, InboxSubmission, SubmissionEvent } from './types'\n\n/**\n * One submission, on a screen of its own (§11).\n *\n * A dialog over the list would have kept the filters under the reader's hand, and it was\n * rejected for one reason: a submission needs an address somebody can send. It goes into the\n * mail to whoever deals with it, it gets pasted into a chat, an agent links to it. What the\n * dialog would have given back is paid for here instead — the list's whole state travels in\n * the address, so the way out lands exactly where the reader was, and the arrows walk the same\n * filtered pile.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/inbox' })\n\nconst context = useAdmin()\nconst api = createInboxApi(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseInboxMessages()\n\nconst t = useTranslate('webx-inbox')\n/* The notes feed is the panel's own, and so is the word for it: a second \"Notes\" in this\n module's dictionary would be the same line translated twice. */\nconst panel = useTranslate('webx-admin')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst submission = ref<InboxSubmission | null>(null)\nconst statuses = ref<InboxStatus[]>([])\nconst admins = ref<InboxRecipient[]>([])\nconst loading = ref(true)\n\nconst canUpdate = computed(() => context.can('inbox.update'))\n\nconst id = computed(() => Number(route.params.id))\n\n/** Everything the list was looking at, carried along so the arrows walk the same pile. */\nconst filter = computed(() => ({\n view: typeof route.query.view === 'string' ? route.query.view : undefined,\n search: typeof route.query.search === 'string' ? route.query.search : undefined,\n assignee: typeof route.query.assignee === 'string' ? route.query.assignee : undefined,\n}))\n\n/** Back to the list, on the form, the tab and the page it was left at. */\nconst backTo = computed(() => ({ path: props.base, query: { ...route.query } }))\n\nconst statusOptions = computed(() =>\n statuses.value.map((status) => ({ value: status.id, label: name(status) })),\n)\n\n/* Nobody is not an option in the list but the empty state of the control: a select whose\n first line means \"none\" is one somebody picks by accident, and `clearable` already says\n it. */\nconst assigneeOptions = computed(() =>\n admins.value.map((admin) => ({ value: admin.id, label: admin.name })),\n)\n\nfunction name(status: InboxStatus): string {\n return localizedValue(status.title, locales.active.value, status.key)\n}\n\nconst heading = computed(() => t('panel.submission', { id: String(id.value) }))\n\nconst formTitle = computed(() => {\n const form = submission.value?.form\n\n return form === undefined\n ? ''\n : localizedValue(form.title ?? {}, locales.active.value, form.slug ?? '')\n})\n\n/**\n * Where a reply goes.\n *\n * The form says which field holds the sender's address (`email_field`); without one, the first\n * answer that was asked as an e-mail is the honest guess, and where there is none the button\n * is simply not there — a `mailto:` with nothing after it opens an empty window.\n */\nconst replyTo = computed(() => {\n const values = submission.value?.values ?? []\n const answer = values.find((value) => value.type === 'email' && (value.value ?? '') !== '')\n\n return answer?.value ?? null\n})\n\nconst mailto = computed(() => {\n if (replyTo.value === null) return null\n\n const subject = encodeURIComponent(`${formTitle.value} — ${heading.value}`)\n\n return `mailto:${replyTo.value}?subject=${subject}`\n})\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n submission.value = await api.submission(id.value, filter.value)\n } catch (error) {\n toast.danger(message(error))\n void router.replace(backTo.value)\n } finally {\n loading.value = false\n }\n}\n\nasync function lists(): Promise<void> {\n try {\n statuses.value = await api.statuses()\n\n // Only where there is something to do with them: assigning is `inbox.update`, and the\n // list of administrators is not a reader's business.\n if (canUpdate.value) {\n admins.value = await api.recipients()\n }\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\n/* The arrows change the address without leaving the screen, so the record has to follow it. */\nwatch(id, () => void load(), { immediate: true })\n\nvoid lists()\n\nasync function save(input: { status_id?: number; assignee_id?: number | null }): Promise<void> {\n try {\n submission.value = await api.saveSubmission(id.value, input)\n toast.success(t('panel.saved'))\n } catch (error) {\n toast.danger(message(error))\n await load()\n }\n}\n\nfunction onStatus(value: unknown): void {\n if (typeof value === 'number') void save({ status_id: value })\n}\n\nfunction onAssignee(value: unknown): void {\n void save({ assignee_id: typeof value === 'number' ? value : null })\n}\n\n/*\n * What the screen offers: answering it, and — behind the `···` — what is done to the pile it\n * came from. Replying is the main action by §18.3, so it is the one that keeps a button of its\n * own once the head runs out of room.\n */\nconst actions = computed<ScreenAction[]>(() => {\n const list: ScreenAction[] = []\n\n if (mailto.value) {\n list.push({\n key: 'reply',\n label: t('panel.reply'),\n icon: 'mail',\n primary: true,\n href: mailto.value,\n target: '_self',\n })\n }\n\n if (canUpdate.value && submission.value !== null) {\n list.push(\n {\n key: 'unread',\n icon: 'eye-off',\n label: t('panel.mark-unread'),\n menu: true,\n run: () => void unread(),\n },\n {\n key: 'notify',\n icon: 'mail',\n label: t('panel.notify-again'),\n menu: true,\n run: () => void notifyAgain(),\n },\n {\n key: 'delete',\n icon: 'trash',\n label: t('panel.delete'),\n danger: true,\n run: () => void remove(),\n },\n )\n }\n\n return list\n})\n\n/*\n * The letter once more — after the mail settings were fixed, or for one stuck in a queue that\n * no worker reads. A form that names nobody is refused by the server, and that is said here.\n */\nasync function notifyAgain(): Promise<void> {\n try {\n submission.value = await api.notifySubmission(id.value)\n toast.success(t('panel.notify-sent-again'))\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nconst notification = computed(() => submission.value?.notification ?? null)\n\nfunction recipientState(state: string): string {\n return t(`panel.notify-recipient-${state}`)\n}\n\nasync function unread(): Promise<void> {\n try {\n await api.massSubmissions({ ids: [id.value], action: 'unread' })\n // Straight back to the list: a submission marked unread and then left open is one the\n // next request would mark read again.\n void router.push(backTo.value)\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function remove(): Promise<void> {\n const agreed = await confirm({\n title: t('panel.delete-submission-title'),\n message: t('panel.delete-submission-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeSubmission(id.value)\n toast.success(t('panel.deleted'))\n void router.push(backTo.value)\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nfunction go(to: number | null): void {\n if (to === null) return\n\n void router.push({ path: `${props.base}/submissions/${to}`, query: { ...route.query } })\n}\n\n/**\n * A status the log names, in the words the panel calls it by.\n *\n * The log stores the key on purpose — read months later, the row it pointed at may have been\n * renamed or deleted, and history must not be rewritten by either. So the key is translated\n * where the panel still has that status, and shown as it stands where it does not: `spam` is\n * a poorer line than \"Спам\", and an invented one would be worse than both.\n */\nfunction statusName(key: string): string {\n const status = statuses.value.find((one) => one.key === key)\n\n return status === undefined ? key : name(status)\n}\n\nconst namesNobody = computed(\n () => submission.value?.events?.some((event) => event.type === 'no_recipients') ?? false,\n)\n\n/** One line of the log, in words rather than as a pair of columns. */\nfunction line(event: SubmissionEvent): string {\n switch (event.type) {\n case 'created':\n return t('panel.event-created')\n case 'status':\n return t('panel.event-status', { to: statusName(event.to ?? '') })\n case 'assignee':\n return event.to === null || event.to === ''\n ? t('panel.event-unassigned')\n : t('panel.event-assignee', { to: event.to })\n case 'note':\n return t('panel.event-note')\n case 'notified':\n return t('panel.event-notified')\n // A handler of `webx-inbox.handlers`: `from` is its class, shown by its own short name.\n case 'handled':\n return t('panel.event-handled', { name: handlerName(event.from) })\n case 'handler_error':\n return t('panel.event-handler-error', {\n name: handlerName(event.from),\n error: event.to ?? '',\n })\n case 'no_recipients':\n return t('panel.event-no-recipients')\n case 'notify_queued':\n return t('panel.event-notify-queued')\n case 'notify_failed':\n return t('panel.event-notify-failed', { to: event.to ?? '' })\n default:\n return event.type\n }\n}\n\nfunction handlerName(name: string | null): string {\n return (name ?? '').split('\\\\').pop() ?? ''\n}\n\nfunction kilobytes(size: number): string {\n return `${Math.max(1, Math.round(size / 1024))} KB`\n}\n\n/** The metadata worth showing, in the order somebody reads it, with the empty ones left out. */\nconst details = computed(() => {\n const meta = submission.value?.meta ?? {}\n\n const rows: { label: string; value: string; link?: boolean }[] = []\n\n if (typeof meta.page === 'string' && meta.page !== '') {\n rows.push({ label: t('panel.meta-page'), value: meta.page, link: true })\n }\n\n // Where on that page the form stood — the footer, an article — beside the page it answers.\n const placement = submission.value?.placement\n if (typeof placement === 'string' && placement !== '') {\n rows.push({ label: t('panel.meta-placement'), value: placement })\n }\n\n if (typeof meta.referrer === 'string' && meta.referrer !== '') {\n rows.push({ label: t('panel.meta-referrer'), value: meta.referrer, link: true })\n }\n\n for (const [key, value] of Object.entries(meta.utm ?? {})) {\n rows.push({ label: key, value: String(value) })\n }\n\n if (typeof meta.locale === 'string' && meta.locale !== '') {\n rows.push({ label: t('panel.meta-locale'), value: meta.locale })\n }\n\n if (typeof meta.ip === 'string' && meta.ip !== '') {\n rows.push({ label: t('panel.meta-ip'), value: meta.ip })\n }\n\n if (typeof meta.user_agent === 'string' && meta.user_agent !== '') {\n rows.push({ label: t('panel.meta-agent'), value: meta.user_agent })\n }\n\n return rows\n})\n</script>\n\n<template>\n <div class=\"wx-submission\">\n <wx-screen-head :title=\"heading\" :subtitle=\"formTitle\" :back=\"backTo\" :actions=\"actions\">\n <!--\n The same pile the reader was looking at, one step at a time. Not an action with a word\n on it, so not something the head can fold into a menu: an arrow with nowhere to go is\n disabled rather than hidden, because a control that changes shape at the ends is one\n that moves under the hand.\n -->\n <template #extra>\n <wx-action\n icon=\"chevron-left\"\n size=\"lg\"\n :title=\"t('panel.previous')\"\n :disabled=\"!submission?.previous_id\"\n @click=\"go(submission?.previous_id ?? null)\"\n />\n <wx-action\n icon=\"chevron-right\"\n size=\"lg\"\n :title=\"t('panel.next')\"\n :disabled=\"!submission?.next_id\"\n @click=\"go(submission?.next_id ?? null)\"\n />\n </template>\n </wx-screen-head>\n\n <wx-skeleton v-if=\"loading\" :rows=\"6\" />\n\n <div v-else-if=\"submission\" class=\"wx-submission__panes\">\n <div class=\"wx-submission__main\">\n <wx-card :title=\"t('panel.answers')\">\n <wx-empty\n v-if=\"submission.values.length === 0\"\n size=\"sm\"\n :description=\"t('panel.no-answers')\"\n />\n <!-- The labels are the snapshot written when it arrived, never the field's current\n words: a submission from a year ago has to read as it did (§2.2). -->\n <wx-descriptions v-else :columns=\"1\" layout=\"vertical\">\n <wx-descriptions-item\n v-for=\"value in submission.values\"\n :key=\"value.id\"\n :label=\"value.label ?? value.name\"\n >\n <p class=\"wx-submission__value\">{{ value.value || '—' }}</p>\n </wx-descriptions-item>\n </wx-descriptions>\n </wx-card>\n\n <wx-card v-if=\"submission.files.length > 0\" :title=\"t('panel.attachments')\">\n <div class=\"wx-submission__files\">\n <!-- Through the panel and not from the disk: the bytes are behind the same\n permission as the submission, for as long as the reader has it (§8). -->\n <wx-file-card\n v-for=\"file in submission.files\"\n :key=\"file.id\"\n :name=\"file.name\"\n :type=\"file.mime ?? undefined\"\n :download-url=\"file.url\"\n :download-label=\"t('panel.download')\"\n size=\"sm\"\n >\n <template #meta>{{ kilobytes(file.size) }}</template>\n </wx-file-card>\n </div>\n </wx-card>\n\n <!--\n Everything about the submission rather than in it, behind one strip.\n\n Three cards stacked down a column is three headings to read past before the eye gets\n to the one that was wanted, and on a phone it is three screens of scrolling. They are\n not read together — a note is written while replying, the log is opened when\n something looks wrong, the metadata once — so only one of them is ever the answer.\n Pills rather than a line, and inside the card rather than over it: this is one card\n changing its contents, not a place in the panel that can be navigated to. The strip is\n the card's heading — which is why there is no other one.\n -->\n <wx-card class=\"wx-submission__more\">\n <wx-tabs variant=\"pill\" :aria-label=\"heading\">\n <wx-tab value=\"notes\" :label=\"panel('notes.title')\">\n <!-- The feed is the panel's own, not this module's: the same one will hang off\n an order and a client (§2.17). Its heading is the tab. -->\n <wx-notes\n :id=\"submission.id\"\n type=\"inbox_submission\"\n title=\"\"\n :can=\"canUpdate\"\n @change=\"load\"\n />\n </wx-tab>\n\n <wx-tab value=\"log\" :label=\"t('panel.log')\">\n <wx-timeline size=\"sm\">\n <wx-timeline-item v-for=\"event in submission.events\" :key=\"event.id\">\n <!-- What happened on one line and who did it when on the next: three inline\n pieces in a row run into each other, and a log is read down. -->\n <wx-text size=\"sm\" as=\"p\" class=\"wx-submission__event\">{{ line(event) }}</wx-text>\n <p class=\"wx-submission__by\">\n <wx-text size=\"sm\" tone=\"muted\">\n {{ event.author?.name ?? t('panel.system') }}\n </wx-text>\n <wx-date :value=\"event.created_at\" />\n </p>\n </wx-timeline-item>\n </wx-timeline>\n </wx-tab>\n\n <wx-tab value=\"details\" :label=\"t('panel.details')\">\n <div class=\"wx-submission__fields\">\n <wx-descriptions :columns=\"1\" layout=\"vertical\" size=\"sm\">\n <wx-descriptions-item :label=\"t('panel.received')\">\n <wx-date :value=\"submission.created_at\" tone=\"default\" />\n </wx-descriptions-item>\n <wx-descriptions-item :label=\"t('panel.meta-source')\">\n <wx-badge :type=\"submission.source === 'panel' ? 'info' : 'default'\">\n {{\n submission.source === 'panel'\n ? t('panel.source-panel')\n : t('panel.source-web')\n }}\n </wx-badge>\n </wx-descriptions-item>\n <wx-descriptions-item v-for=\"row in details\" :key=\"row.label\" :label=\"row.label\">\n <a v-if=\"row.link\" :href=\"row.value\" target=\"_blank\" rel=\"noreferrer\">{{\n row.value\n }}</a>\n <span v-else class=\"wx-submission__detail\">{{ row.value }}</span>\n </wx-descriptions-item>\n </wx-descriptions>\n\n <!-- An unsent notification is a mark on the submission, not a lost one\n (§2.10). Queued is not sent: on a site with a queue a worker sends it,\n and a worker can be missing or hold old mail settings (§9). -->\n <wx-alert\n v-if=\"notification?.state === 'failed'\"\n type=\"warning\"\n :closable=\"false\"\n :title=\"t('panel.notify-failed')\"\n >\n <span class=\"wx-submission__detail\">{{ notification.error }}</span>\n </wx-alert>\n <wx-text v-else-if=\"notification?.state === 'queued'\" size=\"sm\" tone=\"muted\">\n {{ t('panel.notify-queued') }}\n </wx-text>\n <wx-text v-else-if=\"notification?.state === 'delivered'\" size=\"sm\" tone=\"muted\">\n {{ t('panel.notified') }}\n </wx-text>\n <!-- Nobody named is not a letter waiting in the queue, and says so. -->\n <wx-text v-else-if=\"namesNobody\" size=\"sm\" tone=\"muted\">\n {{ t('panel.notified-nobody') }}\n </wx-text>\n <wx-text v-else size=\"sm\" tone=\"muted\">{{ t('panel.not-notified') }}</wx-text>\n\n <ul\n v-if=\"notification && notification.recipients.length > 0\"\n class=\"wx-submission__recipients\"\n >\n <li v-for=\"one in notification.recipients\" :key=\"one.address\">\n <wx-text size=\"sm\">{{ one.address }}</wx-text>\n <wx-badge\n :type=\"\n one.state === 'failed'\n ? 'danger'\n : one.state === 'delivered'\n ? 'success'\n : 'default'\n \"\n >\n {{ recipientState(one.state) }}\n </wx-badge>\n </li>\n </ul>\n\n <div\n v-if=\"\n canUpdate &&\n (notification?.state === 'failed' || notification?.state === 'queued')\n \"\n >\n <wx-button size=\"sm\" @click=\"notifyAgain\">{{\n t('panel.notify-again')\n }}</wx-button>\n </div>\n </div>\n </wx-tab>\n </wx-tabs>\n </wx-card>\n </div>\n\n <aside class=\"wx-submission__aside\">\n <wx-card>\n <div class=\"wx-submission__fields\">\n <label class=\"wx-submission__field\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.status') }}</wx-text>\n <wx-select\n :model-value=\"submission.status?.id ?? null\"\n :options=\"statusOptions\"\n :disabled=\"!canUpdate\"\n @update:model-value=\"onStatus\"\n />\n </label>\n\n <label class=\"wx-submission__field\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.assignee') }}</wx-text>\n <wx-select\n :model-value=\"submission.assignee?.id ?? null\"\n :options=\"assigneeOptions\"\n :disabled=\"!canUpdate\"\n clearable\n :placeholder=\"t('panel.unassigned')\"\n @update:model-value=\"onAssignee\"\n />\n </label>\n </div>\n </wx-card>\n </aside>\n </div>\n </div>\n</template>\n\n<style scoped>\n.wx-submission {\n display: flex;\n flex-direction: column;\n /* The panel says how far apart things stand, and it says something different on a phone\n than on a desktop (8, 12, 16). Writing the desktop number here is what made this screen\n the one place in the panel with desktop air on a 375px screen. */\n gap: var(--wx-gap, var(--wx-space-16));\n min-width: 0;\n /* The panes below decide their own layout from the width of the screen rather than of the\n window: the panel has a sidebar, and the window knows nothing about it. */\n container-type: inline-size;\n}\n\n.wx-submission__panes {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n min-width: 0;\n}\n\n.wx-submission__main,\n.wx-submission__aside {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n min-width: 0;\n}\n\n/* The answers are what the screen is for, so they take the room; everything about the\n submission rather than in it stands beside them. */\n@container (min-width: 900px) {\n .wx-submission__panes {\n flex-direction: row;\n align-items: flex-start;\n }\n\n .wx-submission__main {\n flex: 1 1 auto;\n }\n\n .wx-submission__aside {\n flex: 0 0 320px;\n max-width: 320px;\n }\n}\n\n.wx-submission__value {\n margin: 0;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.wx-submission__detail {\n overflow-wrap: anywhere;\n}\n\n.wx-submission__recipients {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-4);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.wx-submission__recipients li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--wx-space-8);\n overflow-wrap: anywhere;\n}\n\n.wx-submission__event {\n margin: 0;\n}\n\n.wx-submission__by {\n display: flex;\n align-items: baseline;\n gap: var(--wx-space-6);\n flex-wrap: wrap;\n margin: 0;\n}\n\n.wx-submission__files {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-8);\n}\n\n.wx-submission__fields {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n\n.wx-submission__field {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-4);\n}\n</style>\n","import type { AdminModule } from '@webx-ui/module-admin'\nimport FormEditorPage from './FormEditorPage.vue'\nimport InboxPage from './InboxPage.vue'\nimport StatusesPage from './StatusesPage.vue'\nimport SubmissionPage from './SubmissionPage.vue'\n\nexport interface InboxOptions {\n /** Where the section lives inside the panel. */\n path?: string\n /**\n * Whether the panel opens on this section.\n *\n * On by default, and that is the point of the module: a panel with an inbox is a panel\n * somebody opens in the morning to see what came in overnight, and the pages, the blocks\n * and the settings are what they do afterwards (§2.18). A panel whose front page is\n * something else says so here.\n */\n landing?: boolean\n}\n\n/**\n * Forms and submissions as a section of the panel.\n *\n * The id matches the module the server reports, which is what makes the entry appear in the\n * navigation: the section shows up when both halves are installed, and stays out of the way\n * when only one is.\n */\nexport function inbox(options: InboxOptions = {}): AdminModule {\n const path = options.path ?? '/inbox'\n\n return {\n id: 'inbox',\n path,\n landing: options.landing ?? true,\n routes: [\n // The section's own path travels as a prop, so a panel that mounted it somewhere else\n // still links between its screens correctly.\n { path, name: 'webx.inbox', component: InboxPage, props: { base: path } },\n {\n path: `${path}/statuses`,\n name: 'webx.inbox.statuses',\n component: StatusesPage,\n props: { base: path },\n },\n {\n path: `${path}/forms/:id(\\\\d+)`,\n name: 'webx.inbox.form',\n component: FormEditorPage,\n props: { base: path },\n },\n // A submission has an address of its own, not a dialog over the list (§11): it goes in\n // the mail to whoever deals with it, it gets pasted into a chat, an agent links to it.\n {\n path: `${path}/submissions/:id(\\\\d+)`,\n name: 'webx.inbox.submission',\n component: SubmissionPage,\n props: { base: path },\n },\n ],\n }\n}\n"],"names":["model","_useModel","__props","props","locales","useLocales","active","computed","chosen","locale","text","value","next","base","_unref","_createBlock","WxLocales","_createVNode","WxRichText","$event","createInboxApi","admin","data","body","nothing","id","input","ids","formId","query","listQuery","fields","search","key","suffix","inboxMessages","seeded","useInboxMessages","i18n","useAdmin","FIELD_TYPES","STATUS_COLORS","resolve","dismiss","open","useModal","context","api","t","useTranslate","message","useErrorText","saving","ref","errors","name","type","title","placeholder","help","options","isEnabled","isRequired","isFullsize","inTable","watch","field","types","one","hasChoices","choices","extensions","set","addChoice","removeChoice","index","_","at","setChoice","patch","choice","errorOf","save","error","toast","WxDialog","WxSpace","WxButton","_createElementVNode","_hoisted_1","_hoisted_2","WxFormItem","WxSelect","WxInput","_createElementBlock","_Fragment","LocalizedRichText","_cache","_openBlock","_hoisted_3","WxText","_renderList","label","WxAction","WxIcon","_createTextVNode","_hoisted_4","WxInputNumber","WxDatePicker","WxTagsInput","WxCheckbox","_hoisted_5","edit","createModal","FieldDialog","localizedValue","marks","empty","saved","remove","confirm","actionsFor","reorder","WxCard","WxEmpty","WxSortableList","_withCtx","item","_toDisplayString","WxBadge","WxRowMenu","option","fallback","honeypot","seconds","throttle","captcha","captchas","WxSwitch","blade","block","columns","listed","copy","WxTable","row","settings","heading","submit","redirect","ADDRESS","isAdmin","recipient","problemOf","reported","reachesAnybody","recipients","admins","emailField","onMounted","adminOptions","emailOptions","adminProblem","problem","add","setAdmin","setEmail","email","WxAlert","route","useRoute","router","useRouter","form","loading","reactive","tab","silent","canManage","backTo","load","loaded","WxSkeleton","WxScreenHead","WxTabs","WxTab","FormGeneral","FieldList","FormNotifications","FormAntispam","FormEmbed","WxActionBar","slug","values","asked","hasFiles","WxTextarea","WxRadioGroup","WxCheckboxGroup","CARDS","emit","__emit","root","useTemplateRef","width","useElementWidth","asCards","cardsBelow","panel","page","statuses","selected","moving","canUpdate","SubmissionCreateDialog","view","placementOptions","placement","hasPlacements","applied","narrow","views","counts","items","status","answer","column","answers","rowMenuWidth","emptyText","statusOptions","formName","state","onState","wanted","statusList","mass","moveTo","statusId","action","byHand","made","exportHref","actions","__expose","_keys","rows","WxAvatar","WxTooltip","WxDate","WxEntityCard","WxFilterChips","forms","pane","columnInline","formsOpen","create","FormCreateDialog","module","current","choose","close","duplicate","rest","list","WxListScreen","WxListDetail","inline","_normalizeClass","WxIndicator","SubmissionList","color","isDefault","isSpam","isClosed","colors","StatusDialog","submission","filter","assigneeOptions","formTitle","replyTo","mailto","subject","lists","onStatus","onAssignee","unread","notifyAgain","notification","recipientState","go","to","statusName","namesNobody","event","line","handlerName","kilobytes","size","details","meta","WxDescriptions","WxDescriptionsItem","file","WxFileCard","WxNotes","WxTimeline","WxTimelineItem","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","inbox","path","InboxPage","StatusesPage","FormEditorPage","SubmissionPage"],"mappings":"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"}
|