@webx-ui/module-notifications 0.1.0 → 0.2.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/ChannelPage-C47YoMPO.js +427 -0
- package/dist/ChannelPage-C47YoMPO.js.map +1 -0
- package/dist/ChannelsField.d.ts +1 -1
- package/dist/NotificationsPage-qWdhMayl.js +669 -0
- package/dist/NotificationsPage-qWdhMayl.js.map +1 -0
- package/dist/index-DIeEPPSh.js +1279 -0
- package/dist/index-DIeEPPSh.js.map +1 -0
- package/dist/index.d.ts +14 -2
- package/dist/index.js +25 -2344
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-DIeEPPSh.js","sources":["../src/messages.ts","../src/i18n.ts","../src/ChannelsField.vue","../src/context.ts","../src/api.ts","../src/FindChatsDialog.vue","../src/variables.ts","../src/ChatsField.vue","../src/EmailsField.vue","../src/TemplateField.vue","../src/module.ts","../src/render.ts","../src/telegram.ts","../src/MessagePreview.vue","../src/index.ts"],"sourcesContent":["import type { Messages } from '@webx-ui/module-admin'\n\n/**\n * The English this package speaks on its own, before the server's dictionary arrives, or without\n * one. The server ships the same lines in ten languages under `webx-notifications::` and overrides\n * these; `messages.test.ts` keeps the two sets of keys equal.\n *\n * `panel` is this package's own; the groups after it are the lines of the server's groups the\n * panel says too — a refusal of a template in the preview speaks the words of the save.\n */\nexport const notificationsMessages: Record<string, Messages> = {\n module: {\n title: 'Notifications',\n channel: 'Channel',\n statuses: {\n queued: 'Queued',\n sent: 'Sent',\n failed: 'Failed',\n skipped: 'Skipped',\n },\n reasons: {\n channel_deleted: 'The channel is deleted',\n channel_disabled: 'The channel is switched off',\n wrong_event: 'The channel is for another event',\n provider_missing: 'The provider is not installed',\n no_recipients: 'The channel has no recipients',\n no_address: 'The event brought no address',\n admin_deleted: 'The administrator is deleted',\n admin_inactive: 'The administrator is switched off',\n },\n },\n screen: {\n 'any-event': 'Any event',\n },\n panel: {\n channels: 'Channels',\n log: 'Log',\n bin: 'Bin',\n new: 'New channel',\n untitled: 'Untitled channel',\n 'new-title': 'New channel',\n 'new-help':\n 'The kind is chosen once. An event is optional: with one, the editor knows its variables and only that event offers the channel.',\n 'new-provider': 'Kind',\n 'new-event': 'For the event',\n 'new-create': 'Continue',\n 'any-event': 'Any event',\n 'event-undeclared': 'Event not declared',\n 'event-undeclared-text':\n 'No installed module declares “:event” any more. The channel works as one for any event.',\n 'provider-undeclared': 'Provider not installed',\n 'provider-undeclared-text':\n 'The provider “:provider” is not installed on the site: the channel sends nothing.',\n unreadable:\n \"The channel's secrets cannot be read: the application key has changed. Enter them again.\",\n recipients: 'Recipients: :count',\n 'never-sent': 'Nothing sent yet',\n off: 'Off',\n enable: 'Enabled',\n enabled: 'Switched on.',\n disabled: 'Switched off.',\n edit: 'Edit',\n copy: 'Make a copy',\n copied: 'A copy is made, switched off: “:name”.',\n 'copied-from':\n 'The secrets were copied from channel #:id. Replace them if this channel needs another bot or server.',\n delete: 'Delete',\n 'delete-title': 'Delete “:title”?',\n 'delete-text':\n 'The channel goes to the bin and sends nothing. The modules that chose it keep it, and it comes back to them when it is restored.',\n deleted: 'The channel is in the bin.',\n restore: 'Restore',\n restored: 'The channel is back.',\n purge: 'Delete for good',\n 'purge-title': 'Delete “:title” for good?',\n 'purge-text':\n 'The channel disappears from every module that chose it. Its lines in the log stay, without a link to it.',\n purged: 'The channel is deleted for good.',\n cancel: 'Cancel',\n save: 'Save',\n saved: 'Saved.',\n 'saved-warning': 'Saved, but look: :warning',\n 'save-failed': 'Not saved: look at the fields marked in red.',\n 'leave-title': 'Leave without saving?',\n 'leave-text': 'The changes to this channel will be lost.',\n leave: 'Leave',\n 'empty-channels-text':\n 'A channel is where notifications go and how they read: a Telegram bot and its chats, or e-mail and its addresses.',\n 'empty-bin': 'The bin is empty',\n environment:\n 'The site runs as “:environment”: notifications are sent all the same. Switch channels off on a copy of the site.',\n 'mode-after-response':\n 'The site has no queue worker: notifications are sent right after the page answers, without retries in the background.',\n 'secret-set': 'Set. Type a new one to replace it.',\n forget: 'Forget :field',\n forgotten: ':field will be forgotten on save.',\n check: 'Check the connection',\n 'check-ok': 'Connection works.',\n test: 'Send a test',\n 'test-title': 'Send a test',\n 'test-help':\n 'Sent now, past the queue, with the example values of the event — even through a channel that is switched off. What the form has is used, saved or not.',\n 'test-to': 'To',\n 'test-everybody': 'Everybody on the list',\n 'test-send': 'Send',\n 'test-sent': 'Sent to :recipient.',\n 'test-failed': 'Not sent to :recipient: :error',\n 'test-none': 'The channel has no recipients to send a test to.',\n preview: 'Preview',\n 'preview-help': 'The message as it goes out, on the example values of the event.',\n 'preview-no-event': 'For any event: the variables are empty here.',\n 'preview-subject': 'Subject',\n 'preview-empty': 'The message is empty.',\n 'preview-truncated':\n 'Longer than :limit characters: Telegram gets it as plain text, cut to fit.',\n 'preview-unknown': 'Empty in this message: :names.',\n 'preview-refused': 'The template cannot be drawn:',\n variables: 'Variables',\n 'variables-help': 'A click puts it where the cursor is; type {{ to see them in the editor.',\n 'variables-none':\n 'A channel for any event knows no variables. Choose an event to get its list, or type the names it gives.',\n 'variable-list': 'list of :fields',\n 'problem-unclosed': 'The section {{#:name}} is not closed: end it with {{/:name}}.',\n 'problem-stray': '{{/:name}} closes a section that was never opened.',\n 'problem-unknown': 'Not a variable of this event: :names.',\n 'problem-refused': ':tag is not available in a message template.',\n 'problem-broken': 'A tag is not closed: end it with }}.',\n 'hint-variable': 'variable',\n 'hint-list': 'list',\n 'hint-field': 'field of :list',\n 'hint-section': 'shown when :name has a value',\n 'hint-inverted': 'shown when :name is empty',\n 'hint-close': 'closes :name',\n 'hint-comment': 'a comment, never printed',\n 'hint-example': 'Example: :example',\n 'add-chat': 'Add a chat',\n 'chat-id': 'Chat id',\n 'chat-label': 'Label',\n 'find-chats': 'Find chats',\n 'find-title': 'Chats the bot has seen',\n 'find-help': 'Write to the bot, or add it to a group and write there, then search again.',\n 'find-add': 'Add the chosen',\n 'find-token': 'Type the bot token first.',\n 'find-added': 'Chats added: :count.',\n 'chat-private': 'Private',\n 'chat-group': 'Group',\n 'chat-supergroup': 'Supergroup',\n 'chat-channel': 'Channel',\n addressee: 'From the event: :label',\n 'add-admin': 'Add an administrator',\n 'add-email': 'Add an address',\n 'admin-unknown': 'Administrator #:id',\n remove: 'Remove',\n 'no-recipients': 'No recipients yet.',\n 'column-when': 'When',\n 'column-channel': 'Channel',\n 'column-recipient': 'Recipient',\n 'column-status': 'Status',\n 'column-attempts': 'Attempts',\n 'all-statuses': 'Any status',\n 'all-channels': 'Any channel',\n 'with-tests': 'Tests too',\n 'test-mark': 'Test',\n 'cut-mark': 'Cut',\n 'log-empty': 'Nothing sent yet.',\n retry: 'Send again',\n retried: 'Queued again.',\n 'open-subject': 'Open',\n 'unknown-variables': 'Empty variables: :names',\n 'channel-gone': 'deleted',\n filters: 'Filters',\n 'pick-channels': 'Choose channels',\n 'set-up-channels': 'Set up channels',\n },\n errors: {\n 'template-unclosed': 'The section {{#:section}} is not closed: end it with {{/:section}}.',\n 'template-unexpected': '{{/:section}} closes a section that was never opened.',\n 'template-tag': 'The tag {{:tag is not closed: end it with }}.',\n 'template-name':\n '{{:name}} is not a variable name: lowercase letters, digits and _, one dot at most.',\n 'template-partial': 'Partials ({{>name}}) are not available in a message template.',\n 'template-delimiters':\n 'Changing the delimiters ({{=<% %>=}}) is not available in a message template.',\n 'template-pragma':\n 'Pragmas and blocks ({{%…}}, {{$…}}) are not available in a message template.',\n },\n}\n","import { useAdmin } from '@webx-ui/module-admin'\nimport { notificationsMessages } 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 useNotificationsMessages(): void {\n try {\n const { i18n } = useAdmin()\n\n if (!seeded.has(i18n)) {\n i18n.defaults('webx-notifications', notificationsMessages)\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","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useRouter } from 'vue-router'\nimport { WxLink } from '@webx-ui/core'\nimport { useAdmin, useTranslate, WxRelationsField } from '@webx-ui/module-admin'\nimport { useNotificationsMessages } from './i18n'\n\n/**\n * `wx-notifications-channels`: the channels a module notifies through, for one of its events\n * (§15.2) — «Notify through» of a form of the Inbox, and whatever comes after it.\n *\n * Chosen with search, several at once, in any order: the value is the ids and nothing else, kept\n * in the consumer's own data (decision 9). What there is to choose from is the target of the event\n * (`notify-<event>`): the channels of that event and the ones for any event, never the bin. A\n * channel switched off stays chosen and is marked — it sends nothing until it is on again.\n *\n * Choosing needs no right of this module: the picker shows a name and a kind, never recipients or\n * secrets. \"Set up channels\" is there for whoever may.\n */\ndefineOptions({ name: 'WxNotificationChannelsField' })\n\nconst props = withDefaults(\n defineProps<{\n /** The event the channels are for: `inbox.submission`. */\n event: string\n disabled?: boolean\n /** Where the section is in the panel, for the link to it. */\n base?: string\n addText?: string\n emptyText?: string\n }>(),\n { disabled: false, base: '/notifications', addText: undefined, emptyText: undefined },\n)\n\nconst value = defineModel<number[] | null>({ default: () => [] })\n\nuseNotificationsMessages()\n\nconst admin = useAdmin()\nconst t = useTranslate('webx-notifications')\n\n/** The address of the event's target: `[a-z0-9-]+`, so the dots and underscores become dashes. */\nconst target = computed(() => `notify-${props.event.replace(/[._]/g, '-')}`)\n\nconst canManage = computed(() => admin.can('notifications.manage'))\n\nconst router = useRouter()\n\nconst link = computed(() => `${admin.basePath}${props.base}`.replace(/\\/{2,}/g, '/'))\n\n/* Inside the panel, without loading it again: the address is for a middle click. */\nfunction go(event: MouseEvent): void {\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0) return\n\n event.preventDefault()\n void router.push(props.base)\n}\n</script>\n\n<template>\n <div class=\"wx-notification-channels\">\n <wx-relations-field\n v-model=\"value\"\n :target=\"target\"\n :sortable=\"false\"\n :disabled=\"props.disabled\"\n :add-text=\"props.addText ?? t('panel.pick-channels')\"\n :empty-text=\"props.emptyText\"\n />\n <wx-link v-if=\"canManage\" :href=\"link\" size=\"sm\" @click=\"go\">{{\n t('panel.set-up-channels')\n }}</wx-link>\n </div>\n</template>\n\n<style scoped>\n.wx-notification-channels {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--wx-space-8);\n min-width: 0;\n}\n\n.wx-notification-channels > :first-child {\n align-self: stretch;\n}\n</style>\n","import { computed, inject, provide, ref, type ComputedRef, type InjectionKey, type Ref } from 'vue'\nimport type { ScreenModel } from '@webx-ui/schema'\nimport type { NotificationEvent, NotificationProvider, NotificationsMeta } from './types'\n\n/**\n * What the fields of a channel's form know about the form around them: the kind of channel and\n * the event chosen in it, which decide what the template suggests and which addressees there\n * are, and the record itself, which \"Find chats\" asks the saved token of.\n *\n * Provided by the channel's page; a field drawn anywhere else gets an empty one and works as a\n * plain field — a template with only Mustache's syntax to suggest, chats without a search.\n */\nexport interface ChannelContext {\n meta: Ref<NotificationsMeta | null>\n values: Ref<ScreenModel>\n /** The saved channel, or null for one not written yet. */\n id: Ref<number | null>\n provider: ComputedRef<NotificationProvider | null>\n event: ComputedRef<NotificationEvent | null>\n}\n\nconst key: InjectionKey<ChannelContext> = Symbol('wx-notifications-channel')\n\nexport function provideChannel(\n meta: Ref<NotificationsMeta | null>,\n values: Ref<ScreenModel>,\n id: Ref<number | null>,\n): ChannelContext {\n const context: ChannelContext = {\n meta,\n values,\n id,\n provider: computed(\n () => meta.value?.providers.find((one) => one.key === values.value.provider) ?? null,\n ),\n event: computed(() => meta.value?.events.find((one) => one.key === values.value.event) ?? null),\n }\n\n provide(key, context)\n\n return context\n}\n\nexport function useChannel(): ChannelContext {\n return (\n inject(key, null) ?? {\n meta: ref(null),\n values: ref({}),\n id: ref(null),\n provider: computed(() => null),\n event: computed(() => null),\n }\n )\n}\n","import type { AdminContext } from '@webx-ui/module-admin'\nimport type { ScreenModel } from '@webx-ui/schema'\nimport type {\n Administrator,\n ChannelDetail,\n ChannelsList,\n CheckAnswer,\n DeliveriesPage,\n DeliveriesQuery,\n DeliveryRow,\n FoundChat,\n NotificationsMeta,\n ServerPreview,\n TestResult,\n} from './types'\n\nexport interface NotificationsApi {\n /** The providers and the events the site has. */\n meta(): Promise<NotificationsMeta>\n /** Every channel, the newest first; `event` narrows it (`none` — the ones for any event). */\n channels(filter?: { trashed?: boolean; event?: string }): Promise<ChannelsList>\n get(id: number): Promise<ChannelDetail>\n /** A new channel out of the values of its form; a new channel of an event starts with its sample. */\n create(values: ScreenModel): Promise<ChannelDetail>\n /**\n * Only the fields given are written, so the switch in the list sends `{ enabled }` alone. An\n * empty secret keeps the one saved; `forget` lists the ones to wipe.\n */\n save(id: number, values: ScreenModel): Promise<ChannelDetail>\n remove(id: number): Promise<void>\n restore(id: number): Promise<ChannelDetail>\n purge(id: number): Promise<void>\n /** A copy, switched off, its secrets carried over on the server. */\n copy(id: number, name?: string): Promise<ChannelDetail>\n /** Sends now, past the queue, on the event's examples — through the form's values, not saved. */\n test(id: number | null, values: ScreenModel, recipient?: string | null): Promise<TestResult[]>\n /** The server's render of the form's values: the check of the live preview. */\n preview(id: number | null, values: ScreenModel, locale?: string): Promise<ServerPreview>\n /** The settings tried without sending: Telegram's getMe, an SMTP handshake. */\n check(id: number | null, values: ScreenModel): Promise<CheckAnswer>\n /** The chats the bot has seen; with a token typed into the form or the saved one. */\n findRecipients(input: {\n provider: string\n channel?: number | null\n token?: string\n }): Promise<{ recipients: FoundChat[]; hint: string | null }>\n administrators(): Promise<Administrator[]>\n deliveries(query?: DeliveriesQuery): Promise<DeliveriesPage>\n retry(id: number): Promise<DeliveryRow>\n}\n\n/** The path of the section under the panel's API. */\nexport const NOTIFICATIONS_API = 'notifications'\n\nfunction search(query: DeliveriesQuery): string {\n const params = new URLSearchParams()\n\n for (const [key, value] of Object.entries(query)) {\n if (value === null || value === undefined || value === '') continue\n params.set(key, typeof value === 'boolean' ? (value ? '1' : '0') : String(value))\n }\n\n const text = params.toString()\n\n return text === '' ? '' : `?${text}`\n}\n\nexport function createNotificationsApi(admin: AdminContext): NotificationsApi {\n const base = `${admin.apiPath}/${NOTIFICATIONS_API}`\n const data = <T>(body: { data: T }): T => body.data\n const channel = (id: number | null) => (id === null ? base : `${base}/channels/${id}`)\n\n return {\n meta: () => admin.http.get<{ data: NotificationsMeta }>(`${base}/meta`).then(data),\n channels: (filter = {}) => {\n const params = new URLSearchParams()\n if (filter.trashed) params.set('trashed', '1')\n if (filter.event) params.set('event', filter.event)\n const text = params.toString()\n\n return admin.http.get<ChannelsList>(`${base}/channels${text === '' ? '' : `?${text}`}`)\n },\n get: (id) => admin.http.get<{ data: ChannelDetail }>(`${base}/channels/${id}`).then(data),\n create: (values) =>\n admin.http.post<{ data: ChannelDetail }>(`${base}/channels`, { values }).then(data),\n save: (id, values) =>\n admin.http.put<{ data: ChannelDetail }>(`${base}/channels/${id}`, { values }).then(data),\n remove: (id) => admin.http.delete<void>(`${base}/channels/${id}`).then(() => undefined),\n restore: (id) =>\n admin.http.post<{ data: ChannelDetail }>(`${base}/channels/${id}/restore`, {}).then(data),\n purge: (id) => admin.http.delete<void>(`${base}/channels/${id}/purge`).then(() => undefined),\n copy: (id, name) =>\n admin.http\n .post<{ data: ChannelDetail }>(`${base}/channels/${id}/copy`, name ? { name } : {})\n .then(data),\n test: (id, values, recipient) =>\n admin.http\n .post<{ data: { results: TestResult[] } }>(`${channel(id)}/test`, {\n values,\n ...(recipient ? { recipient } : {}),\n })\n .then((body) => body.data.results),\n preview: (id, values, locale) =>\n admin.http\n .post<{ data: ServerPreview }>(`${channel(id)}/preview`, { values, locale })\n .then(data),\n check: (id, values) =>\n admin.http\n .post<{ data: CheckAnswer }>(`${base}/check`, { values, ...(id ? { channel: id } : {}) })\n .then(data),\n findRecipients: ({ provider, channel: id, token }) =>\n admin.http\n .post<{ data: { recipients: FoundChat[]; hint: string | null } }>(\n `${base}/find-recipients`,\n { provider, ...(id ? { channel: id } : {}), ...(token ? { token } : {}) },\n )\n .then(data),\n administrators: () =>\n admin.http.get<{ data: Administrator[] }>(`${base}/administrators`).then(data),\n deliveries: (query = {}) =>\n admin.http.get<DeliveriesPage>(`${base}/deliveries${search(query)}`),\n retry: (id) =>\n admin.http.post<{ data: DeliveryRow }>(`${base}/deliveries/${id}/retry`, {}).then(data),\n }\n}\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport {\n useModal,\n WxAlert,\n WxBadge,\n WxButton,\n WxCheckbox,\n WxDialog,\n WxEmpty,\n WxSkeleton,\n WxSpace,\n WxText,\n} from '@webx-ui/core'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport { createNotificationsApi } from './api'\nimport { useNotificationsMessages } from './i18n'\nimport type { FoundChat } from './types'\n\n/**\n * \"Find chats\" (§6.3): the chats the bot has seen in the last day, to tick and add. Asked of the\n * saved token, or of one typed into the form and not saved yet — that one goes into this request\n * and nowhere else. Nothing is sent and nothing is written: the bot's updates are read once,\n * without being acknowledged, so a bot that is read elsewhere still gets them.\n */\ndefineOptions({ name: 'WxNotificationsFindChats' })\n\nconst props = withDefaults(\n defineProps<{\n channel?: number | null\n token?: string\n /** Chats already on the list: shown ticked and not added twice. */\n chosen?: string[]\n }>(),\n { channel: null, token: '', chosen: () => [] },\n)\n\nconst { open, resolve, dismiss } = useModal<FoundChat[]>()\n\nconst api = createNotificationsApi(useAdmin())\nuseNotificationsMessages()\n\nconst t = useTranslate('webx-notifications')\nconst message = useErrorText()\n\nconst found = ref<FoundChat[]>([])\nconst hint = ref<string | null>(null)\nconst failure = ref<string | null>(null)\nconst loading = ref(true)\nconst ticked = ref(new Set<string>())\n\nasync function search(): Promise<void> {\n loading.value = true\n failure.value = null\n\n try {\n const answer = await api.findRecipients({\n provider: 'telegram',\n channel: props.channel,\n token: props.token.trim() === '' ? undefined : props.token.trim(),\n })\n\n found.value = answer.recipients\n hint.value = answer.hint\n } catch (error) {\n failure.value = message(error)\n } finally {\n loading.value = false\n }\n}\n\nonMounted(() => void search())\n\nconst fresh = computed(() => found.value.filter((chat) => !props.chosen.includes(chat.id)))\n\nfunction toggle(id: string, on: boolean): void {\n const next = new Set(ticked.value)\n\n if (on) next.add(id)\n else next.delete(id)\n\n ticked.value = next\n}\n\nfunction add(): void {\n resolve(fresh.value.filter((chat) => ticked.value.has(chat.id)))\n}\n</script>\n\n<template>\n <wx-dialog v-model:open=\"open\" :title=\"t('panel.find-title')\" :width=\"480\">\n <wx-skeleton v-if=\"loading\" :rows=\"3\" />\n\n <wx-alert v-else-if=\"failure\" type=\"danger\" variant=\"soft\" :description=\"failure\" />\n\n <wx-empty\n v-else-if=\"found.length === 0\"\n :title=\"t('panel.find-title')\"\n :description=\"hint ?? t('panel.find-help')\"\n />\n\n <ul v-else class=\"wx-notifications-found\">\n <li v-for=\"chat in found\" :key=\"chat.id\" class=\"wx-notifications-found__row\">\n <wx-checkbox\n :model-value=\"props.chosen.includes(chat.id) || ticked.has(chat.id)\"\n :disabled=\"props.chosen.includes(chat.id)\"\n @update:model-value=\"(on: boolean) => toggle(chat.id, on)\"\n >\n <span class=\"wx-notifications-found__text\">\n <wx-text truncate>{{ chat.title }}</wx-text>\n <wx-text size=\"sm\" tone=\"muted\" mono truncate>\n {{ [chat.id, chat.username].filter(Boolean).join(' · ') }}\n </wx-text>\n </span>\n </wx-checkbox>\n <wx-badge>{{ t(`panel.chat-${chat.type}`) }}</wx-badge>\n </li>\n </ul>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" :disabled=\"loading\" @click=\"search\">\n {{ t('panel.find-chats') }}\n </wx-button>\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :disabled=\"ticked.size === 0\" @click=\"add\">\n {{ t('panel.find-add') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-notifications-found {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-8);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.wx-notifications-found__row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--wx-space-8);\n min-width: 0;\n}\n\n.wx-notifications-found__text {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n</style>\n","import type { MustacheVariable } from '@webx-ui/core'\nimport type { NotificationEvent } from './types'\n\n/** The variables of an event as the editor's suggestions take them. */\nexport function variablesOf(event: NotificationEvent | null | undefined): MustacheVariable[] {\n return (event?.variables ?? []).map((variable) => ({\n name: variable.name,\n label: variable.label,\n example: variable.example,\n fields: variable.fields.length > 0 ? variable.fields : undefined,\n }))\n}\n\n/** What a click on a variable puts into the template. */\nexport function snippetOf(\n variable: MustacheVariable,\n kind: 'value' | 'has' | 'empty' = 'value',\n): string {\n const name = variable.name.endsWith('.*') ? `${variable.name.slice(0, -2)}.name` : variable.name\n\n if ((variable.fields?.length ?? 0) > 0) {\n const fields = (variable.fields ?? []).map((field) => `{{${field.name}}}`).join(' ')\n\n return `{{#${name}}}\\n${fields}\\n{{/${name}}}`\n }\n\n if (kind === 'has') return `{{#${name}}}{{${name}}}{{/${name}}}`\n if (kind === 'empty') return `{{^${name}}}{{/${name}}}`\n\n return `{{${name}}}`\n}\n\n/** The addressees of an event a provider can send to: the visitor's e-mail, a chat id. */\nexport function addresseesOf(event: NotificationEvent | null | undefined, address: string) {\n return (event?.variables ?? []).filter((variable) => variable.address === address)\n}\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport {\n createModal,\n toast,\n WxAction,\n WxBadge,\n WxButton,\n WxIcon,\n WxInput,\n WxSpace,\n WxText,\n} from '@webx-ui/core'\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { useChannel } from './context'\nimport FindChatsDialog from './FindChatsDialog.vue'\nimport { useNotificationsMessages } from './i18n'\nimport { addresseesOf } from './variables'\nimport type { ChatRecipient, FoundChat } from './types'\n\n/**\n * `wx-notifications-chats`: who a Telegram channel writes to (§6.1) — chat ids with a label each,\n * and the chat the event brings when it brings one (decision 12).\n *\n * The ids are hard to come by, so \"Find chats\" lists the ones the bot has seen: the saved token's,\n * or the one typed above and not saved yet.\n */\ndefineOptions({ name: 'WxNotificationsChatsField' })\n\nconst props = withDefaults(defineProps<{ disabled?: boolean }>(), { disabled: false })\n\nconst model = defineModel<ChatRecipient[] | null>({ default: () => [] })\n\nuseNotificationsMessages()\n\nconst t = useTranslate('webx-notifications')\nconst channel = useChannel()\nconst find = createModal<\n FoundChat[],\n { channel?: number | null; token?: string; chosen?: string[] }\n>(FindChatsDialog)\n\nconst list = computed<ChatRecipient[]>(() => (Array.isArray(model.value) ? model.value : []))\n\nconst addressees = computed(() => addresseesOf(channel.event.value, 'telegram'))\n\nconst unused = computed(() =>\n addressees.value.filter((variable) => !list.value.some((one) => one.variable === variable.name)),\n)\n\nfunction labelOf(name: string): string {\n return addressees.value.find((variable) => variable.name === name)?.label ?? `{{${name}}}`\n}\n\nfunction set(index: number, patch: Partial<ChatRecipient>): void {\n model.value = list.value.map((one, at) => (at === index ? { ...one, ...patch } : one))\n}\n\nfunction add(recipient: ChatRecipient): void {\n model.value = [...list.value, recipient]\n}\n\nfunction remove(index: number): void {\n model.value = list.value.filter((_, at) => at !== index)\n}\n\nconst token = computed(() => {\n const typed = channel.values.value.token\n\n return typeof typed === 'string' ? typed : ''\n})\n\n/* Without a token there is nobody to ask: the saved channel has one, or the field above does. */\nconst canFind = computed(\n () =>\n token.value.trim() !== '' ||\n (channel.id.value !== null && channel.values.value.provider === 'telegram'),\n)\n\nasync function search(): Promise<void> {\n if (!canFind.value) {\n toast.warning(t('panel.find-token'))\n\n return\n }\n\n const chosen = await find({\n channel: channel.id.value,\n token: token.value,\n chosen: list.value.map((one) => one.chat_id ?? '').filter(Boolean),\n })\n\n if (!chosen || chosen.length === 0) return\n\n model.value = [...list.value, ...chosen.map((chat) => ({ chat_id: chat.id, label: chat.title }))]\n toast.success(t('panel.find-added', { count: String(chosen.length) }))\n}\n</script>\n\n<template>\n <div class=\"wx-notifications-recipients\">\n <wx-text v-if=\"list.length === 0\" size=\"sm\" tone=\"placeholder\">\n {{ t('panel.no-recipients') }}\n </wx-text>\n\n <div v-for=\"(recipient, index) in list\" :key=\"index\" class=\"wx-notifications-recipients__row\">\n <template v-if=\"recipient.variable\">\n <wx-badge type=\"primary\" class=\"wx-notifications-recipients__addressee\">\n {{ t('panel.addressee', { label: labelOf(recipient.variable) }) }}\n </wx-badge>\n </template>\n\n <template v-else>\n <wx-input\n class=\"wx-notifications-recipients__id\"\n :model-value=\"recipient.chat_id ?? ''\"\n :placeholder=\"t('panel.chat-id')\"\n :aria-label=\"t('panel.chat-id')\"\n :disabled=\"props.disabled\"\n inputmode=\"text\"\n @update:model-value=\"(value) => set(index, { chat_id: String(value ?? '') })\"\n />\n <wx-input\n class=\"wx-notifications-recipients__label\"\n :model-value=\"recipient.label ?? ''\"\n :placeholder=\"t('panel.chat-label')\"\n :aria-label=\"t('panel.chat-label')\"\n :disabled=\"props.disabled\"\n @update:model-value=\"(value) => set(index, { label: String(value ?? '') })\"\n />\n </template>\n\n <wx-action\n v-if=\"!props.disabled\"\n icon=\"trash\"\n tone=\"danger\"\n :title=\"t('panel.remove')\"\n @click=\"remove(index)\"\n />\n </div>\n\n <wx-space v-if=\"!props.disabled\" size=\"sm\" wrap>\n <wx-button variant=\"outline\" size=\"sm\" @click=\"add({ chat_id: '', label: '' })\">\n <template #icon><wx-icon name=\"plus\" /></template>\n {{ t('panel.add-chat') }}\n </wx-button>\n <wx-button variant=\"outline\" size=\"sm\" @click=\"search\">\n <template #icon><wx-icon name=\"search\" /></template>\n {{ t('panel.find-chats') }}\n </wx-button>\n <wx-button\n v-for=\"variable in unused\"\n :key=\"variable.name\"\n variant=\"outline\"\n size=\"sm\"\n @click=\"add({ variable: variable.name })\"\n >\n {{ t('panel.addressee', { label: variable.label }) }}\n </wx-button>\n </wx-space>\n </div>\n</template>\n\n<style scoped>\n.wx-notifications-recipients {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-8);\n min-width: 0;\n max-width: var(--wx-field-max-width, 640px);\n}\n\n.wx-notifications-recipients__row {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n min-width: 0;\n}\n\n/* The control of a row takes what the bin leaves: a select draws only as wide as its words. */\n.wx-notifications-recipients__row > :not(:last-child) {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.wx-notifications-recipients__id {\n flex: 1 1 40%;\n min-width: 0;\n}\n\n.wx-notifications-recipients__label {\n flex: 1 1 60%;\n min-width: 0;\n}\n\n.wx-notifications-recipients__addressee {\n flex: 1 1 auto;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport {\n WxAction,\n WxBadge,\n WxButton,\n WxIcon,\n WxInput,\n WxSelect,\n WxSpace,\n WxText,\n} from '@webx-ui/core'\nimport { useAdmin, useTranslate } from '@webx-ui/module-admin'\nimport { createNotificationsApi } from './api'\nimport { useChannel } from './context'\nimport { useNotificationsMessages } from './i18n'\nimport { addresseesOf } from './variables'\nimport type { Administrator, EmailRecipient } from './types'\n\n/**\n * `wx-notifications-emails`: who an e-mail channel writes to (§6.2) — administrators of the panel,\n * whose address follows their account, typed addresses, and the address the event brings: the\n * visitor who filled in a form, for a reply of the site (decision 12). One letter each: nobody\n * sees who else got it.\n */\ndefineOptions({ name: 'WxNotificationsEmailsField' })\n\nconst props = withDefaults(defineProps<{ disabled?: boolean }>(), { disabled: false })\n\nconst model = defineModel<EmailRecipient[] | null>({ default: () => [] })\n\nuseNotificationsMessages()\n\nconst t = useTranslate('webx-notifications')\nconst channel = useChannel()\nconst admin = useAdmin()\n\nconst admins = ref<Administrator[]>([])\n\nonMounted(async () => {\n try {\n admins.value = await createNotificationsApi(admin).administrators()\n } catch {\n // Only the shortcut is gone: an address can still be typed.\n }\n})\n\nconst list = computed<EmailRecipient[]>(() => (Array.isArray(model.value) ? model.value : []))\n\nconst adminOptions = computed(() =>\n admins.value.map((one) => ({ value: one.id, label: `${one.name} · ${one.email}` })),\n)\n\nconst addressees = computed(() => addresseesOf(channel.event.value, 'email'))\n\nconst unused = computed(() =>\n addressees.value.filter((variable) => !list.value.some((one) => one.variable === variable.name)),\n)\n\nfunction labelOf(name: string): string {\n return addressees.value.find((variable) => variable.name === name)?.label ?? `{{${name}}}`\n}\n\nfunction set(index: number, recipient: EmailRecipient): void {\n model.value = list.value.map((one, at) => (at === index ? recipient : one))\n}\n\nfunction add(recipient: EmailRecipient): void {\n model.value = [...list.value, recipient]\n}\n\nfunction remove(index: number): void {\n model.value = list.value.filter((_, at) => at !== index)\n}\n\n/* An administrator the list no longer has — deleted or switched off — is still drawn by number. */\nfunction adminOptionsFor(id: number) {\n return adminOptions.value.some((one) => one.value === id)\n ? adminOptions.value\n : [...adminOptions.value, { value: id, label: t('panel.admin-unknown', { id: String(id) }) }]\n}\n</script>\n\n<template>\n <div class=\"wx-notifications-recipients\">\n <wx-text v-if=\"list.length === 0\" size=\"sm\" tone=\"placeholder\">\n {{ t('panel.no-recipients') }}\n </wx-text>\n\n <div v-for=\"(recipient, index) in list\" :key=\"index\" class=\"wx-notifications-recipients__row\">\n <wx-badge v-if=\"recipient.variable\" type=\"primary\" class=\"wx-notifications-recipients__wide\">\n {{ t('panel.addressee', { label: labelOf(recipient.variable) }) }}\n </wx-badge>\n\n <wx-select\n v-else-if=\"recipient.admin_id !== undefined\"\n class=\"wx-notifications-recipients__wide\"\n :model-value=\"recipient.admin_id\"\n :options=\"adminOptionsFor(recipient.admin_id)\"\n :disabled=\"props.disabled\"\n @update:model-value=\"(id) => set(index, { admin_id: Number(id) })\"\n />\n\n <wx-input\n v-else\n class=\"wx-notifications-recipients__wide\"\n type=\"email\"\n :model-value=\"recipient.email ?? ''\"\n placeholder=\"manager@site.test\"\n :disabled=\"props.disabled\"\n @update:model-value=\"(email) => set(index, { email: String(email ?? '') })\"\n />\n\n <wx-action\n v-if=\"!props.disabled\"\n icon=\"trash\"\n tone=\"danger\"\n :title=\"t('panel.remove')\"\n @click=\"remove(index)\"\n />\n </div>\n\n <wx-space v-if=\"!props.disabled\" size=\"sm\" wrap>\n <wx-button\n variant=\"outline\"\n size=\"sm\"\n :disabled=\"adminOptions.length === 0\"\n @click=\"add({ admin_id: Number(adminOptions[0]?.value) })\"\n >\n <template #icon><wx-icon name=\"user\" /></template>\n {{ t('panel.add-admin') }}\n </wx-button>\n <wx-button variant=\"outline\" size=\"sm\" @click=\"add({ email: '' })\">\n <template #icon><wx-icon name=\"mail\" /></template>\n {{ t('panel.add-email') }}\n </wx-button>\n <wx-button\n v-for=\"variable in unused\"\n :key=\"variable.name\"\n variant=\"outline\"\n size=\"sm\"\n @click=\"add({ variable: variable.name })\"\n >\n {{ t('panel.addressee', { label: variable.label }) }}\n </wx-button>\n </wx-space>\n </div>\n</template>\n\n<style scoped>\n.wx-notifications-recipients {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-8);\n min-width: 0;\n max-width: var(--wx-field-max-width, 640px);\n}\n\n.wx-notifications-recipients__row {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n min-width: 0;\n}\n\n/* The control of a row takes what the bin leaves: a select draws only as wide as its words. */\n.wx-notifications-recipients__row > :not(:last-child) {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.wx-notifications-recipients__wide {\n flex: 1 1 auto;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport {\n mustacheCompletions,\n mustacheProblems,\n useLocales,\n WxAlert,\n WxButton,\n WxCodeEditor,\n WxText,\n WxTooltip,\n type CodeEditorExposed,\n type LocalizedValue,\n type MustacheVariable,\n} from '@webx-ui/core'\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { useChannel } from './context'\nimport { useNotificationsMessages } from './i18n'\nimport { snippetOf, variablesOf } from './variables'\n\n/**\n * `wx-notifications-template`: the body of a channel's message (§7) in every language of the site.\n *\n * `WxCodeEditor` with Mustache painted over HTML for Telegram and over text for a letter; `{{`\n * opens the event's variables, the fields of the list being looped over and the end of the section\n * that is open. Under it the same variables as buttons — the editor is the fast way, the buttons\n * are the way to find out what there is — and what is wrong with the template as it stands, by the\n * same rules the save refuses it with.\n *\n * The event and the kind of channel come from the form around it (`provideChannel`); without one\n * the field still edits a template and offers Mustache's syntax alone.\n */\ndefineOptions({ name: 'WxNotificationsTemplateField' })\n\nconst props = withDefaults(\n defineProps<{\n localized?: boolean\n disabled?: boolean\n minHeight?: string\n }>(),\n { localized: false, disabled: undefined, minHeight: '200px' },\n)\n\nconst model = defineModel<string | LocalizedValue | null>({ default: '' })\n\nuseNotificationsMessages()\n\nconst t = useTranslate('webx-notifications')\nconst channel = useChannel()\nconst locales = useLocales()\nconst editor = ref<CodeEditorExposed | null>(null)\n\nconst variables = computed<MustacheVariable[]>(() => variablesOf(channel.event.value))\n\nconst language = computed(() =>\n channel.provider.value?.key === 'telegram' ? 'mustache-html' : 'mustache',\n)\n\nconst completions = computed(() =>\n mustacheCompletions(variables.value, {\n variable: t('panel.hint-variable'),\n list: t('panel.hint-list'),\n field: t('panel.hint-field'),\n section: t('panel.hint-section'),\n inverted: t('panel.hint-inverted'),\n close: t('panel.hint-close'),\n comment: t('panel.hint-comment'),\n example: t('panel.hint-example'),\n }),\n)\n\n/** The language on screen: what the problems below are about. */\nconst text = computed(() => {\n const value = model.value\n\n if (value === null || value === undefined) return ''\n if (typeof value === 'string') return value\n\n const active = locales.active.value || locales.list.value[0]?.code || ''\n\n return value[active] ?? ''\n})\n\n/*\n * Names are judged only on a channel of an event: one for any event may say anything, and the\n * server only warns about it on save.\n */\nconst problems = computed(() =>\n mustacheProblems(text.value, channel.event.value === null ? undefined : variables.value),\n)\n\nconst said = computed(() => {\n const found = problems.value\n\n return [\n ...found.unclosed.map((name) => t('panel.problem-unclosed', { name })),\n ...found.stray.map((name) => t('panel.problem-stray', { name })),\n ...found.refused.map((tag) => t('panel.problem-refused', { tag })),\n ...(found.broken ? [t('panel.problem-broken')] : []),\n ...(found.unknown.length > 0\n ? [\n t('panel.problem-unknown', {\n names: found.unknown.map((name) => `{{${name}}}`).join(', '),\n }),\n ]\n : []),\n ]\n})\n\nfunction example(variable: MustacheVariable): string {\n if ((variable.fields?.length ?? 0) > 0) {\n return t('panel.variable-list', {\n fields: (variable.fields ?? []).map((field) => field.name).join(', '),\n })\n }\n\n const value = variable.example\n\n return typeof value === 'string' || typeof value === 'number' ? String(value) : ''\n}\n\n/** Into the editor where the caret is, and the caret after it. */\nfunction insert(snippet: string): void {\n const view = editor.value?.view\n\n if (!view) return\n\n const range = view.state.selection.main\n\n view.dispatch({\n changes: { from: range.from, to: range.to, insert: snippet },\n selection: { anchor: range.from + snippet.length },\n scrollIntoView: true,\n })\n view.focus()\n}\n</script>\n\n<template>\n <div class=\"wx-notifications-template\">\n <wx-code-editor\n ref=\"editor\"\n v-model=\"model\"\n :language=\"language\"\n :completions=\"completions\"\n :localized=\"props.localized\"\n :disabled=\"props.disabled\"\n :line-numbers=\"false\"\n line-wrapping\n :min-height=\"props.minHeight\"\n />\n\n <wx-alert v-for=\"line in said\" :key=\"line\" type=\"warning\" variant=\"soft\" :description=\"line\" />\n\n <div class=\"wx-notifications-template__variables\">\n <wx-text size=\"sm\" weight=\"medium\">{{ t('panel.variables') }}</wx-text>\n\n <wx-text v-if=\"variables.length === 0\" size=\"sm\" tone=\"muted\">\n {{ t('panel.variables-none') }}\n </wx-text>\n\n <template v-else>\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.variables-help') }}</wx-text>\n\n <div class=\"wx-notifications-template__chips\">\n <wx-tooltip\n v-for=\"variable in variables\"\n :key=\"variable.name\"\n :content=\"[variable.label, example(variable)].filter(Boolean).join(' — ')\"\n >\n <wx-button\n size=\"sm\"\n variant=\"outline\"\n class=\"wx-notifications-template__chip\"\n :disabled=\"props.disabled\"\n @click=\"insert(snippetOf(variable))\"\n >\n <span class=\"wx-notifications-template__name\">\n {{ (variable.fields?.length ?? 0) > 0 ? `#${variable.name}` : variable.name }}\n </span>\n </wx-button>\n </wx-tooltip>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.wx-notifications-template {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-8);\n min-width: 0;\n}\n\n.wx-notifications-template__variables {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-4);\n}\n\n.wx-notifications-template__chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-6);\n margin-top: var(--wx-space-4);\n}\n\n.wx-notifications-template__name {\n font-family: var(--wx-font-family-mono);\n}\n</style>\n","import type { AdminModule } from '@webx-ui/module-admin'\nimport ChannelsField from './ChannelsField.vue'\nimport ChatsField from './ChatsField.vue'\nimport EmailsField from './EmailsField.vue'\nimport TemplateField from './TemplateField.vue'\n\nexport interface NotificationsOptions {\n /** Where the section lives inside the panel. */\n path?: string\n}\n\n/**\n * Notification channels as a section of the panel (§10): the channels, the log, the bin, and a\n * page per channel.\n *\n * The fields of a channel's form are node types the server's screen names — the chats of a bot,\n * the addresses of a letter, the template — and so is the picker a consumer chooses channels with\n * (`wx-notifications-channels`), which any screen or block may use. They come with this package\n * because what they list is this section's.\n *\n * A section whose server half is not installed, or that the person may not open — everybody but a\n * super administrator until a role is given `notifications.view` — never appears: the entry is\n * built from the manifest.\n */\nexport function notifications(options: NotificationsOptions = {}): AdminModule {\n const path = options.path ?? '/notifications'\n\n return {\n id: 'notifications',\n path,\n routes: [\n {\n path,\n name: 'webx.notifications',\n component: () => import('./NotificationsPage.vue'),\n props: { base: path },\n },\n {\n path: `${path}/channels/new`,\n name: 'webx.notifications.new',\n component: () => import('./ChannelPage.vue'),\n props: { base: path },\n },\n {\n path: `${path}/channels/:id(\\\\d+)`,\n name: 'webx.notifications.channel',\n component: () => import('./ChannelPage.vue'),\n props: { base: path },\n },\n ],\n types: {\n 'wx-notifications-template': { component: TemplateField, kind: 'field', wide: true },\n 'wx-notifications-chats': { component: ChatsField, kind: 'field' },\n 'wx-notifications-emails': { component: EmailsField, kind: 'field' },\n 'wx-notifications-channels': {\n component: ChannelsField,\n kind: 'field',\n bind: (node) => ({ event: node.props?.event, base: path }),\n },\n },\n }\n}\n","import Mustache from 'mustache'\nimport type { NotificationEvent } from './types'\n\n/**\n * The live preview of a channel's message (§7): the template Mustache reads — `mustache.js`, the\n * same syntax the server renders with `mustache/mustache` — and the values of the event's examples\n * through the provider's escaping. `render.test.ts` and the server's `PreviewParityTest` read the\n * same cases out of `tests/fixtures/render.json`, so a difference between the two shows as a red\n * test rather than as a message that looks one way here and another in the chat.\n *\n * `mustache.js` only parses: its rendering differs from PHP's where it matters to a notification —\n * `'0'` is a value to JavaScript and empty to PHP, an escaping function is global to it — so the\n * tree it parses is walked here by the rules of `Mustache\\Template` on the server.\n */\n\n/** Values as the consumer gives them: flat, `field.phone` with a dot. */\nexport type TemplateValues = Record<string, unknown>\n\n/** How a value goes into a message: the provider's escaping (`Provider::escape`). */\nexport type Escape = (value: string) => string\n\n/** A template the server would refuse, with the key of `errors.*` that says why. */\nexport class TemplateRefusal extends Error {\n constructor(\n public readonly key: string,\n public readonly replace: Record<string, string> = {},\n ) {\n super(key)\n this.name = 'TemplateRefusal'\n }\n}\n\ntype Token = [string, string, number, number, Token[]?, number?]\n\nconst NAME = /^[a-z0-9_]+(\\.[a-z0-9_]+)?$/\n\n/** Telegram's: `htmlspecialchars(…, ENT_QUOTES | ENT_HTML401)`. */\nexport function escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\n/** A subject is one line: a value with line breaks would break the header. */\nexport function oneLine(value: string): string {\n return value.replace(/[\\r\\n]+/g, ' ')\n}\n\n/** Each provider's escaping, by key; a provider nobody knows here prints values as they are. */\nexport function escapeFor(provider: string): Escape {\n return provider === 'telegram' ? escapeHtml : (value) => value\n}\n\nfunction parse(template: string): Token[] {\n try {\n return Mustache.parse(template, ['{{', '}}']) as unknown as Token[]\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n const section = /section \"([^\"]*)\"/.exec(message)?.[1] ?? ''\n\n if (message.startsWith('Unopened section')) {\n throw new TemplateRefusal('template-unexpected', { section })\n }\n\n if (message.startsWith('Unclosed section')) {\n throw new TemplateRefusal('template-unclosed', { section })\n }\n\n const at = Number(/at (\\d+)/.exec(message)?.[1] ?? template.lastIndexOf('{{'))\n const tag = template\n .slice(at)\n .replace(/^\\{\\{\\{?[#^/!&>=]?/, '')\n .trim()\n\n throw new TemplateRefusal('template-tag', { tag })\n }\n}\n\n/** The checks of `Template::tokens()`: what Mustache has and a message template may not use. */\nfunction check(tokens: Token[]): void {\n for (const token of tokens) {\n const [type, value] = token\n\n if (type === '>') throw new TemplateRefusal('template-partial')\n if (type === '=') throw new TemplateRefusal('template-delimiters')\n if (type === 'text' || type === '!') continue\n\n const name = value.trim()\n\n if (name.startsWith('<')) throw new TemplateRefusal('template-partial')\n if (name.startsWith('%') || name.startsWith('$')) throw new TemplateRefusal('template-pragma')\n if (!NAME.test(name)) throw new TemplateRefusal('template-name', { name })\n\n if (token[4]) check(token[4])\n }\n}\n\n/** Flat values nested the way Mustache reads a dot: `field.phone` is `field` → `phone`. */\nfunction nest(values: TemplateValues): Record<string, unknown> {\n const context: Record<string, unknown> = {}\n\n for (const [name, value] of Object.entries(values)) {\n if (!name.includes('.')) {\n context[name] = value\n continue\n }\n\n const [head, ...tail] = name.split('.')\n const key = head as string\n const current = context[key]\n\n if (current === undefined || isMap(current)) {\n context[key] = { ...(isMap(current) ? current : {}), [tail.join('.')]: value }\n }\n }\n\n return context\n}\n\nfunction isMap(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** PHP's `empty()`, which is what decides a section there. */\nfunction empty(value: unknown): boolean {\n if (value === null || value === undefined || value === false) return true\n if (value === '' || value === '0' || value === 0) return true\n if (Array.isArray(value)) return value.length === 0\n if (isMap(value)) return Object.keys(value).length === 0\n\n return false\n}\n\n/** `Context::findDot()`: the first part up the stack, the rest inside it. */\nfunction find(stack: unknown[], name: string): unknown {\n const [first, ...rest] = name.split('.')\n let value: unknown = undefined\n\n for (let at = stack.length - 1; at >= 0; at--) {\n const frame = stack[at]\n\n if (isMap(frame) && Object.prototype.hasOwnProperty.call(frame, first as string)) {\n value = frame[first as string]\n break\n }\n }\n\n for (const chunk of rest) {\n if (value === '' || value === undefined) return value\n value = isMap(value) && Object.prototype.hasOwnProperty.call(value, chunk) ? value[chunk] : ''\n }\n\n return value\n}\n\nfunction scalar(value: unknown): string {\n if (typeof value === 'string') return value\n if (typeof value === 'number') return String(value)\n if (value === true) return '1'\n\n return ''\n}\n\nfunction walk(tokens: Token[], stack: unknown[], escape: Escape): string {\n let out = ''\n\n for (const token of tokens) {\n const [type, value] = token\n\n if (type === 'text') {\n out += value\n continue\n }\n\n if (type === '!') continue\n\n const found = find(stack, value.trim())\n\n if (type === 'name' || type === '&') {\n out += isMap(found) || Array.isArray(found) ? '' : escape(scalar(found))\n continue\n }\n\n const inside = token[4] ?? []\n\n if (type === '#' && !empty(found)) {\n for (const item of Array.isArray(found) ? found : [found]) {\n out += walk(inside, [...stack, item], escape)\n }\n }\n\n if (type === '^' && empty(found)) out += walk(inside, stack, escape)\n }\n\n return out\n}\n\ninterface Usage {\n name: string\n sections: string[]\n}\n\nfunction usages(tokens: Token[], sections: string[] = [], into: Usage[] = []): Usage[] {\n for (const token of tokens) {\n const [type, value] = token\n\n if (type === 'text' || type === '!') continue\n\n const name = value.trim()\n\n into.push({ name, sections })\n\n if (type === '#') usages(token[4] ?? [], [...sections, name], into)\n if (type === '^') usages(token[4] ?? [], sections, into)\n }\n\n return into\n}\n\n/** `Template::find()`: a name in the nearest scope that has its first part; null for none. */\nfunction lookup(scopes: unknown[], name: string): unknown {\n const [first, ...rest] = name.split('.') as [string, ...string[]]\n\n for (const scope of [...scopes].reverse()) {\n if (!isMap(scope) || !Object.prototype.hasOwnProperty.call(scope, first)) continue\n\n let value: unknown = scope[first]\n\n for (const chunk of rest) {\n if (!isMap(value) || !Object.prototype.hasOwnProperty.call(value, chunk)) return null\n value = value[chunk]\n }\n\n return value ?? null\n }\n\n return null\n}\n\n/** `Template::present()`: whether a name has a value where it is used. */\nfunction present(context: Record<string, unknown>, name: string, sections: string[]): boolean {\n const scopes: unknown[] = [context]\n\n for (const section of sections) {\n const value = lookup(scopes, section)\n\n // The fields of any element: a list of rows with gaps is not a mistake.\n if (Array.isArray(value)) scopes.push(Object.assign({}, ...value.filter(isMap)))\n else if (isMap(value)) scopes.push(value)\n }\n\n return lookup(scopes, name) !== null\n}\n\n/** `EventDefinition::knows()`: a field of an enclosing list, or a variable of the event. */\nexport function knows(event: NotificationEvent, name: string, sections: string[]): boolean {\n for (const section of [...sections].reverse()) {\n const list = event.variables.find((variable) => variable.name === section)\n\n if (list && list.fields.length > 0 && list.fields.some((field) => field.name === name)) {\n return true\n }\n }\n\n return event.variables.some(\n (variable) =>\n variable.name === name ||\n (variable.name.endsWith('.*') && name.startsWith(variable.name.slice(0, -1))),\n )\n}\n\n/**\n * The template with the values in, each through `escape` — `Template::render()`. A name with no\n * value is empty, and reported unless `known` says the event declares it.\n *\n * @throws TemplateRefusal for a template the server would refuse\n */\nexport function renderTemplate(\n template: string,\n values: TemplateValues,\n escape: Escape,\n known?: (name: string, sections: string[]) => boolean,\n): { text: string; unknown: string[] } {\n const tokens = parse(template)\n\n check(tokens)\n\n const context = nest(values)\n const unknown = new Set<string>()\n\n for (const usage of usages(tokens)) {\n if (!present(context, usage.name, usage.sections) && !known?.(usage.name, usage.sections)) {\n unknown.add(usage.name)\n }\n }\n\n return { text: walk(tokens, [context], escape), unknown: [...unknown] }\n}\n\n/** The examples of an event as values: what a test and the preview fill a template with. */\nexport function examplesOf(event: NotificationEvent | null | undefined): TemplateValues {\n const values: TemplateValues = {}\n\n for (const variable of event?.variables ?? []) {\n if (!variable.name.endsWith('.*')) values[variable.name] = variable.example\n }\n\n return values\n}\n\n/** Telegram's plain text: the tags dropped, the entities read. */\nexport function plainOf(html: string): string {\n const document = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html')\n\n return document.body.textContent ?? ''\n}\n\nexport interface RenderedMessage {\n subject: string | null\n body: string\n plain: string\n /** Longer than the provider takes: sent as plain text, cut. */\n truncated: boolean\n unknown: string[]\n}\n\nexport interface MessageInput {\n provider: string\n template: string\n subject?: string | null\n /** Whether the provider's messages have a subject. */\n hasSubject?: boolean\n /** The longest message the provider takes, in characters. */\n limit?: number | null\n values: TemplateValues\n event?: NotificationEvent | null\n}\n\n/** `Renderer::render()`: the message a channel would send on these values. */\nexport function renderMessage(input: MessageInput): RenderedMessage {\n const escape = escapeFor(input.provider)\n const event = input.event ?? null\n const known =\n event === null ? undefined : (name: string, sections: string[]) => knows(event, name, sections)\n const body = renderTemplate(input.template, input.values, escape, known)\n let subject: string | null = null\n let unknown = body.unknown\n\n if (input.hasSubject) {\n const rendered = renderTemplate(input.subject ?? '', input.values, oneLine, known)\n\n subject = oneLine(rendered.text).trim()\n unknown = [...new Set([...unknown, ...rendered.unknown])]\n }\n\n const plain = input.provider === 'telegram' ? plainOf(body.text) : body.text\n const limit = input.limit ?? null\n\n if (limit !== null && [...plain].length > limit) {\n const cut = `${[...plain].slice(0, limit - 1).join('')}…`\n\n return { subject, body: escape(cut), plain: cut, truncated: true, unknown }\n }\n\n return { subject, body: body.text, plain, truncated: false, unknown }\n}\n","/**\n * A Telegram message as the chat draws it, for the preview: only the tags Telegram takes\n * (`TelegramMarkup::TAGS`), links only to the web and to Telegram, and everything else as text.\n *\n * The template is the administrator's and the values are the event's examples, but the preview\n * still never hands HTML to the page as it is: what is not on the list is not drawn.\n */\nconst TAGS = new Set([\n 'b',\n 'strong',\n 'i',\n 'em',\n 'u',\n 'ins',\n 's',\n 'strike',\n 'del',\n 'a',\n 'code',\n 'pre',\n 'blockquote',\n 'tg-spoiler',\n 'span',\n])\n\nfunction copy(from: Node, into: Node, document: Document): void {\n for (const child of Array.from(from.childNodes)) {\n if (child.nodeType === Node.TEXT_NODE) {\n into.appendChild(document.createTextNode(child.textContent ?? ''))\n continue\n }\n\n if (!(child instanceof Element)) continue\n\n const tag = child.tagName.toLowerCase()\n\n if (!TAGS.has(tag) || (tag === 'span' && !child.classList.contains('tg-spoiler'))) {\n copy(child, into, document)\n continue\n }\n\n const made = document.createElement(tag === 'tg-spoiler' ? 'span' : tag)\n\n if (tag === 'tg-spoiler' || tag === 'span') made.className = 'tg-spoiler'\n\n if (tag === 'a') {\n const href = child.getAttribute('href') ?? ''\n\n if (/^(https?:|tg:)/i.test(href)) {\n made.setAttribute('href', href)\n made.setAttribute('target', '_blank')\n made.setAttribute('rel', 'noopener noreferrer')\n }\n }\n\n copy(child, made, document)\n into.appendChild(made)\n }\n}\n\nexport function telegramHtml(body: string): string {\n const parsed = new DOMParser().parseFromString(`<body>${body}</body>`, 'text/html')\n const out = document.implementation.createHTMLDocument('')\n const root = out.createElement('div')\n\n copy(parsed.body, root, out)\n\n return root.innerHTML\n}\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport {\n localizedValue,\n useLocales,\n WxAlert,\n WxCard,\n WxText,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport { useTranslate } from '@webx-ui/module-admin'\nimport { useChannel } from './context'\nimport { useNotificationsMessages } from './i18n'\nimport { examplesOf, renderMessage, TemplateRefusal, type RenderedMessage } from './render'\nimport { telegramHtml } from './telegram'\n\n/**\n * The message as it goes out, drawn while the template is typed (§7.5): the event's examples\n * through the provider's escaping, by the renderer that `PreviewParityTest` holds to the server's.\n * Telegram as a bubble of the chat, with only the tags Telegram takes; a letter as its subject and\n * its text.\n *\n * The language is the one the editor is on, so switching it switches the preview with it.\n */\ndefineOptions({ name: 'WxNotificationsPreview' })\n\nuseNotificationsMessages()\n\nconst t = useTranslate('webx-notifications')\nconst channel = useChannel()\nconst locales = useLocales()\n\nconst locale = computed(() => locales.active.value || locales.list.value[0]?.code || '')\n\ntype Outcome = { message: RenderedMessage } | { refusal: string }\n\nconst outcome = computed<Outcome | null>(() => {\n const provider = channel.provider.value\n\n if (provider === null) return null\n\n const values = channel.values.value\n\n try {\n return {\n message: renderMessage({\n provider: provider.key,\n template: localizedValue(values.template as LocalizedValue | string | null, locale.value),\n subject: localizedValue(values.subject as LocalizedValue | string | null, locale.value),\n hasSubject: provider.subject,\n limit: provider.limit,\n values: examplesOf(channel.event.value),\n event: channel.event.value,\n }),\n }\n } catch (error) {\n if (error instanceof TemplateRefusal) {\n return { refusal: t(`errors.${error.key}`, error.replace) }\n }\n\n throw error\n }\n})\n\nconst message = computed(() =>\n outcome.value !== null && 'message' in outcome.value ? outcome.value.message : null,\n)\n\nconst refusal = computed(() =>\n outcome.value !== null && 'refusal' in outcome.value ? outcome.value.refusal : null,\n)\n\n/* Built here: a `}}` of Mustache inside an interpolation of the template would end it. */\nconst unknownLine = computed(() =>\n t('panel.preview-unknown', {\n names: (message.value?.unknown ?? []).map((name) => '{{' + name + '}}').join(', '),\n }),\n)\n\nconst telegram = computed(() => channel.provider.value?.key === 'telegram')\n\nconst bubble = computed(() =>\n message.value === null || message.value.truncated ? '' : telegramHtml(message.value.body),\n)\n</script>\n\n<template>\n <wx-card :title=\"t('panel.preview')\" class=\"wx-notifications-preview\">\n <wx-text size=\"sm\" tone=\"muted\">\n {{ channel.event.value ? t('panel.preview-help') : t('panel.preview-no-event') }}\n </wx-text>\n\n <wx-alert\n v-if=\"refusal\"\n type=\"danger\"\n variant=\"soft\"\n :title=\"t('panel.preview-refused')\"\n :description=\"refusal\"\n />\n\n <template v-else-if=\"message\">\n <div v-if=\"telegram\" class=\"wx-notifications-preview__chat\">\n <!-- eslint-disable-next-line vue/no-v-html -- only Telegram's tags, see telegram.ts -->\n <div v-if=\"!message.truncated\" class=\"wx-notifications-preview__bubble\" v-html=\"bubble\" />\n <div v-else class=\"wx-notifications-preview__bubble\">{{ message.plain }}</div>\n </div>\n\n <div v-else class=\"wx-notifications-preview__letter\">\n <div class=\"wx-notifications-preview__subject\">\n <wx-text size=\"sm\" tone=\"muted\">{{ t('panel.preview-subject') }}</wx-text>\n <wx-text weight=\"medium\">{{ message.subject || '—' }}</wx-text>\n </div>\n <div class=\"wx-notifications-preview__body\">{{ message.body }}</div>\n </div>\n\n <wx-text v-if=\"message.plain.trim() === ''\" size=\"sm\" tone=\"muted\">\n {{ t('panel.preview-empty') }}\n </wx-text>\n\n <wx-alert\n v-if=\"message.truncated\"\n type=\"warning\"\n variant=\"soft\"\n :description=\"\n t('panel.preview-truncated', { limit: String(channel.provider.value?.limit ?? '') })\n \"\n />\n\n <wx-text v-if=\"message.unknown.length > 0 && channel.event.value\" size=\"sm\" tone=\"muted\">\n {{ unknownLine }}\n </wx-text>\n </template>\n </wx-card>\n</template>\n\n<style scoped>\n.wx-notifications-preview__chat {\n display: flex;\n margin-top: var(--wx-space-8);\n padding: var(--wx-space-12);\n border-radius: var(--wx-radius-md);\n background: var(--wx-bg-subtle);\n}\n\n/*\n * A bubble of the chat: as wide as its text and no wider than most of the column, the way\n * Telegram draws a message from a bot.\n */\n.wx-notifications-preview__bubble {\n max-width: min(100%, 520px);\n padding: var(--wx-space-8) var(--wx-space-12);\n border-radius: var(--wx-radius-md);\n background: var(--wx-bg-surface);\n box-shadow: var(--wx-shadow-sm);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-size: var(--wx-font-size-sm);\n line-height: var(--wx-font-line-height-normal);\n}\n\n.wx-notifications-preview__bubble :deep(a) {\n color: var(--wx-text-link);\n}\n\n.wx-notifications-preview__bubble :deep(code),\n.wx-notifications-preview__bubble :deep(pre) {\n font-family: var(--wx-font-family-mono);\n}\n\n.wx-notifications-preview__bubble :deep(blockquote) {\n margin: 0;\n padding-left: var(--wx-space-8);\n border-left: 3px solid var(--wx-color-primary);\n}\n\n.wx-notifications-preview__bubble :deep(.tg-spoiler) {\n border-radius: var(--wx-radius-xs);\n background: var(--wx-bg-fill);\n}\n\n.wx-notifications-preview__letter {\n display: flex;\n flex-direction: column;\n margin-top: var(--wx-space-8);\n border: 1px solid var(--wx-border-muted);\n border-radius: var(--wx-radius-md);\n overflow: hidden;\n}\n\n.wx-notifications-preview__subject {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-2);\n padding: var(--wx-space-8) var(--wx-space-12);\n border-bottom: 1px solid var(--wx-border-muted);\n background: var(--wx-bg-subtle);\n overflow-wrap: anywhere;\n}\n\n.wx-notifications-preview__body {\n padding: var(--wx-space-12);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-size: var(--wx-font-size-sm);\n line-height: var(--wx-font-line-height-normal);\n}\n</style>\n","import { defineAsyncComponent } from 'vue'\nexport { notifications, type NotificationsOptions } from './module'\nexport { createNotificationsApi, NOTIFICATIONS_API, type NotificationsApi } from './api'\nexport { notificationsMessages } from './messages'\nexport {\n escapeFor,\n escapeHtml,\n examplesOf,\n renderMessage,\n renderTemplate,\n TemplateRefusal,\n type MessageInput,\n type RenderedMessage,\n type TemplateValues,\n} from './render'\nexport { telegramHtml } from './telegram'\nexport { addresseesOf, snippetOf, variablesOf } from './variables'\nexport { provideChannel, useChannel, type ChannelContext } from './context'\nexport const WxNotificationsPage = defineAsyncComponent(() => import('./NotificationsPage.vue'))\nexport const WxNotificationsChannelPage = defineAsyncComponent(() => import('./ChannelPage.vue'))\nexport { default as WxNotificationsPreview } from './MessagePreview.vue'\nexport { default as WxNotificationsTemplateField } from './TemplateField.vue'\nexport { default as WxNotificationsChatsField } from './ChatsField.vue'\nexport { default as WxNotificationsEmailsField } from './EmailsField.vue'\nexport { default as WxNotificationChannelsField } from './ChannelsField.vue'\nexport type * from './types'\n"],"names":["notificationsMessages","seeded","useNotificationsMessages","i18n","useAdmin","props","__props","value","_useModel","admin","t","useTranslate","target","computed","canManage","router","useRouter","link","go","event","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","WxRelationsField","$event","_createBlock","WxLink","key","provideChannel","meta","values","id","context","one","provide","useChannel","inject","ref","NOTIFICATIONS_API","search","query","params","text","createNotificationsApi","base","data","body","channel","filter","name","recipient","locale","provider","token","open","resolve","dismiss","useModal","api","message","useErrorText","found","hint","failure","loading","ticked","answer","error","onMounted","fresh","chat","toggle","on","next","add","WxDialog","WxSpace","WxButton","WxSkeleton","WxAlert","WxEmpty","_Fragment","_renderList","WxCheckbox","_createElementVNode","_hoisted_2","WxText","_createTextVNode","_toDisplayString","WxBadge","variablesOf","variable","snippetOf","kind","fields","field","addresseesOf","address","model","find","createModal","FindChatsDialog","list","addressees","unused","labelOf","set","index","patch","at","remove","_","typed","canFind","toast","chosen","WxInput","WxAction","WxIcon","admins","adminOptions","adminOptionsFor","WxSelect","email","locales","useLocales","editor","variables","language","completions","mustacheCompletions","active","problems","mustacheProblems","said","tag","example","insert","snippet","view","range","WxCodeEditor","line","_hoisted_3","WxTooltip","_hoisted_4","notifications","options","path","TemplateField","ChatsField","EmailsField","ChannelsField","node","TemplateRefusal","replace","NAME","escapeHtml","oneLine","escapeFor","parse","template","Mustache","section","check","tokens","type","nest","head","tail","current","isMap","empty","stack","first","rest","frame","chunk","scalar","walk","escape","out","inside","item","usages","sections","into","lookup","scopes","scope","present","knows","renderTemplate","known","unknown","usage","examplesOf","plainOf","html","renderMessage","input","subject","rendered","plain","limit","cut","TAGS","copy","from","document","child","made","href","telegramHtml","parsed","root","outcome","localizedValue","refusal","unknownLine","telegram","bubble","WxCard","_hoisted_5","_hoisted_6","WxNotificationsPage","defineAsyncComponent","WxNotificationsChannelPage"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,20 @@ export { escapeFor, escapeHtml, examplesOf, renderMessage, renderTemplate, Templ
|
|
|
5
5
|
export { telegramHtml } from './telegram';
|
|
6
6
|
export { addresseesOf, snippetOf, variablesOf } from './variables';
|
|
7
7
|
export { provideChannel, useChannel, type ChannelContext } from './context';
|
|
8
|
-
export
|
|
9
|
-
|
|
8
|
+
export declare const WxNotificationsPage: import('vue').DefineComponent<{
|
|
9
|
+
base?: string;
|
|
10
|
+
}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{
|
|
11
|
+
base?: string;
|
|
12
|
+
}> & Readonly<{}>, {
|
|
13
|
+
base: string;
|
|
14
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
15
|
+
export declare const WxNotificationsChannelPage: import('vue').DefineComponent<{
|
|
16
|
+
base?: string;
|
|
17
|
+
}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{
|
|
18
|
+
base?: string;
|
|
19
|
+
}> & Readonly<{}>, {
|
|
20
|
+
base: string;
|
|
21
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
10
22
|
export { default as WxNotificationsPreview } from './MessagePreview';
|
|
11
23
|
export { default as WxNotificationsTemplateField } from './TemplateField';
|
|
12
24
|
export { default as WxNotificationsChatsField } from './ChatsField';
|