diff --git a/addons/internal/connector-ui/src/FilesFields.jsx b/addons/internal/connector-ui/src/FilesFields.jsx index 30d8cb0499..d90c08d036 100644 --- a/addons/internal/connector-ui/src/FilesFields.jsx +++ b/addons/internal/connector-ui/src/FilesFields.jsx @@ -3,8 +3,8 @@ // limit of the connector kind. The page shows the limit in effect with the // layer that sets it. The numbers come from the server; the words live here as // defaults, like the rest of the shared fields. -import { Field, TextInput } from './controls' -import { fileLimitProblem, formatBytes, previewLimit } from './connector' +import { Field, Hint, TextInput } from './controls' +import { fileDirection, fileLimitProblem, formatBytes, previewLimit } from './connector' export const FILES_TEXT = { 'files.title': 'Files', @@ -14,6 +14,12 @@ export const FILES_TEXT = { 'files.invalid': 'Use a number greater than 0.', 'files.tooHigh': 'The add-on allows at most {{max}} here.', 'files.now': 'Now: {{limit}} ({{layer}}).', + 'files.receiveHelp': 'Files that people send to the bot. A bigger file is refused, and the bot says which limit it hit.', + 'files.sendHelp': 'Files that the agent makes and the bot sends back. A bigger file is not sent, and the bot says which limit it hit.', + 'files.addon.off': 'This add-on does not move files in this direction, so there is nothing to set.', + 'files.addon.declared': 'The add-on declares up to {{max}}.', + 'files.addon.open': 'The add-on declares no limit, so the limit of the platform applies.', + 'files.host': 'No bot can move a file above {{max}}. An administrator sets this in the settings.', 'files.layer.owner': 'limit set for this bot', 'files.layer.addon': 'limit of the add-on', 'files.layer.host': 'limit of the platform', @@ -25,16 +31,19 @@ function shown(base, saved, mib) { return previewLimit(base, mib) || (saved ? { bytes: saved.effective_bytes, layer: saved.layer } : null) } -function Limit({ label, mib, onChange, base, saved, s, testId }) { - const problem = fileLimitProblem(mib, base?.allowed_bytes) - const limit = shown(base, saved, mib) +function Limit({ label, help, mib, onChange, base, saved, s, testId }) { + const dir = fileDirection(base) + const problem = dir === 'off' ? '' : fileLimitProblem(mib, base?.allowed_bytes) + const limit = dir === 'off' ? null : shown(base, saved, mib) const error = problem === 'invalid' ? s('files.invalid') : problem === 'tooHigh' ? s('files.tooHigh', { max: formatBytes(base.allowed_bytes) }) : undefined + const declared = dir === 'declared' ? s('files.addon.declared', { max: formatBytes(base.declared_bytes) }) + : dir === 'open' ? s('files.addon.open') : dir === 'off' ? s('files.addon.off') : '' + const now = limit ? s('files.now', { limit: formatBytes(limit.bytes), layer: s(`files.layer.${limit.layer}`) }) : '' return ( - + {(p) => ( - onChange(e.target.value)} /> + onChange(e.target.value)} /> )} ) @@ -49,13 +58,15 @@ function Limit({ label, mib, onChange, base, saved, s, testId }) { * @param {Function} props.s the translation function with the defaults */ export default function FilesFields({ form, setForm, kind, saved, s }) { + const hostCeiling = kind?.host_ceiling_bytes || 0 return (
{s('files.title')}

{s('files.help')}

- 0 && {s('files.host', { max: formatBytes(hostCeiling) })}} + setForm({ ...form, file_receive_mib: v })} /> - setForm({ ...form, file_send_mib: v })} />
) diff --git a/addons/internal/connector-ui/src/connector.js b/addons/internal/connector-ui/src/connector.js index 623c11898b..3fe6fe5aaa 100644 --- a/addons/internal/connector-ui/src/connector.js +++ b/addons/internal/connector-ui/src/connector.js @@ -172,6 +172,16 @@ export function previewLimit(base, mib) { return { bytes: base.effective_bytes, layer: base.layer } } +// What the add-on declares for one direction, from the limits of the kind: +// 'off' (it moves no file that way), 'declared' (it names a largest file), +// 'open' (it names none, so the platform limit applies) or 'unknown' (the page +// has no numbers yet). +export function fileDirection(base) { + if (!base) return 'unknown' + if (!(base.effective_bytes > 0) && !(base.allowed_bytes > 0)) return 'off' + return base.declared_bytes > 0 ? 'declared' : 'open' +} + // A size as a person reads it: bytes, KiB, MiB, GiB or TiB, one decimal at most. export function formatBytes(n) { if (n === 1) return '1 byte' diff --git a/addons/telegram/ui/test/connector.test.mjs b/addons/telegram/ui/test/connector.test.mjs index b732195248..a92c97cce0 100644 --- a/addons/telegram/ui/test/connector.test.mjs +++ b/addons/telegram/ui/test/connector.test.mjs @@ -1,6 +1,6 @@ import test from 'node:test' import assert from 'node:assert/strict' -import { approvalForm, approvalPayload, approvalProblem, bytesToMib, canSave, connectorForm, connectorPayload, emptyConnector, fileLimitProblem, formatBytes, mibToBytes, modeText, previewLimit, senderLine } from '../../../internal/connector-ui/src/connector.js' +import { approvalForm, approvalPayload, approvalProblem, bytesToMib, canSave, connectorForm, connectorPayload, emptyConnector, fileDirection, fileLimitProblem, formatBytes, mibToBytes, modeText, previewLimit, senderLine } from '../../../internal/connector-ui/src/connector.js' test('chat connectors: the token goes only when it was typed', () => { const create = connectorPayload({ ...emptyConnector(), name: ' Bot ', token: ' 1:abc ', agent_id: 'a1', allow: ['11', ' 11', '@ada_l', ''] }, 'telegram') @@ -121,6 +121,13 @@ test('chat connectors: a typed limit can only lower the limit in effect, and nam assert.equal(previewLimit(null, '1'), null) }) +test('chat connectors: the page tells what the add-on declares for a direction', () => { + assert.equal(fileDirection(null), 'unknown') + assert.equal(fileDirection({ effective_bytes: 0, allowed_bytes: 0, declared_bytes: 0, layer: 'addon' }), 'off') + assert.equal(fileDirection({ effective_bytes: 100, allowed_bytes: 100, declared_bytes: 0, layer: 'host' }), 'open') + assert.equal(fileDirection({ effective_bytes: 50, allowed_bytes: 50, declared_bytes: 50, layer: 'addon' }), 'declared') +}) + test('chat connectors: sizes are written in KiB and MiB', () => { assert.equal(formatBytes(900), '900 bytes') assert.equal(formatBytes(1), '1 byte')