Accept pasted images in inbox Other and Reply answers
This commit is contained in:
Vendored
+32
-20
@@ -3,6 +3,7 @@ import { mountChanges } from "./changes.js";
|
||||
import { ago, errorText, h, replace, showAlert } from "./dom.js";
|
||||
import { image, inlineMarkdown, markdown } from "./markdown.js";
|
||||
import { checkedAnswer, clearAnswer, dropTextAnswer, flushDrafts, hasTextAnswer, setCheckedAnswer, setTextAnswer, textAnswer } from "./drafts.js";
|
||||
import { imageDrafts, imageTray, releaseImages, uploadImages } from "./images.js";
|
||||
import { diagram } from "./mermaid.js";
|
||||
import { focusTab, onEach, state } from "./state.js";
|
||||
import { taskStyle } from "./taskcolor.js";
|
||||
@@ -90,13 +91,17 @@ function card(item) {
|
||||
c.disabled = on;
|
||||
}
|
||||
};
|
||||
const submit = async (response) => {
|
||||
const imageKey = `inbox:${item.id}`;
|
||||
const submit = async (response, tray) => {
|
||||
if (busy()) {
|
||||
return;
|
||||
}
|
||||
lock(true);
|
||||
const imgs = tray?.take() ?? [];
|
||||
try {
|
||||
await post("/api/inbox/responses", { body: { responses: [response] } });
|
||||
const images = await uploadImages(imgs);
|
||||
await post("/api/inbox/responses", { body: { responses: [{ ...response, images }] } });
|
||||
releaseImages(imgs);
|
||||
clearAnswer(item.id);
|
||||
const others = state.inbox.some((i) => i.task_id === item.task_id && i.id !== item.id);
|
||||
if (!others && state.focus.tab === "inbox" && state.selectedTaskId === item.task_id) {
|
||||
@@ -104,6 +109,7 @@ function card(item) {
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
tray?.restore(imgs);
|
||||
void showAlert(errorText(err));
|
||||
lock(false);
|
||||
renderActions();
|
||||
@@ -139,10 +145,16 @@ function card(item) {
|
||||
return h("label", { class: rec ? "option choice-box rec" : "option choice-box" }, h("div", { class: "choice-head" }, input, name, tag));
|
||||
};
|
||||
const textEntry = (label, placeholder, shared) => {
|
||||
const open = hasTextAnswer(item.id);
|
||||
const open = hasTextAnswer(item.id) || imageDrafts.has(imageKey);
|
||||
const text = h("textarea", { rows: 3, placeholder, value: textAnswer(item.id) ?? "" });
|
||||
const send = h("button", { type: "button", class: "primary", disabled: !text.value.trim() }, "Submit");
|
||||
const editor = h("div", { class: "text-editor", hidden: !open }, text, !shared && h("div", { class: "submit-row" }, send));
|
||||
const send = h("button", { type: "button", class: "primary" }, "Submit");
|
||||
const editor = h("div", { class: "text-editor", hidden: !open });
|
||||
const empty = () => !text.value.trim() && !imageDrafts.has(imageKey);
|
||||
const tray = imageTray(editor, text, imageKey, () => {
|
||||
send.disabled = empty();
|
||||
shared?.onInput();
|
||||
});
|
||||
editor.append(tray.el, text, shared ? "" : h("div", { class: "submit-row" }, send));
|
||||
const block = clickable(h("div", { class: "pick other", role: "button", tabIndex: 0, hidden: open }, label), () => {
|
||||
setTextAnswer(item.id, "");
|
||||
block.hidden = true;
|
||||
@@ -151,21 +163,21 @@ function card(item) {
|
||||
});
|
||||
const go = () => {
|
||||
if (shared) {
|
||||
shared.onSubmit();
|
||||
shared.onSubmit(tray);
|
||||
return;
|
||||
}
|
||||
if (text.value.trim()) {
|
||||
void submit({ item_id: item.id, type: "other", text: text.value });
|
||||
if (!empty()) {
|
||||
void submit({ item_id: item.id, type: "other", text: text.value }, tray);
|
||||
}
|
||||
};
|
||||
send.onclick = go;
|
||||
text.oninput = () => {
|
||||
setTextAnswer(item.id, text.value);
|
||||
send.disabled = !text.value.trim();
|
||||
send.disabled = empty();
|
||||
shared?.onInput();
|
||||
};
|
||||
text.onblur = () => {
|
||||
if (!text.value.trim() && !busy()) {
|
||||
if (empty() && !busy()) {
|
||||
dropTextAnswer(item.id);
|
||||
editor.hidden = true;
|
||||
block.hidden = false;
|
||||
@@ -179,7 +191,7 @@ function card(item) {
|
||||
go();
|
||||
}
|
||||
};
|
||||
return h("div", { class: "text-entry" }, block, editor);
|
||||
return { el: h("div", { class: "text-entry" }, block, editor), tray };
|
||||
};
|
||||
const delegate = () => {
|
||||
const button = h("button", { type: "button", class: "delegate" }, "Let the agent decide");
|
||||
@@ -193,28 +205,28 @@ function card(item) {
|
||||
const send = h("button", { type: "button", class: "primary" }, "Submit");
|
||||
const typed = () => (textAnswer(item.id) ?? "").trim();
|
||||
const refresh = () => {
|
||||
send.disabled = !typed() && (!multiple || checkedAnswer(item.id).length === 0);
|
||||
send.disabled = !typed() && !imageDrafts.has(imageKey) && (!multiple || checkedAnswer(item.id).length === 0);
|
||||
};
|
||||
const go = () => {
|
||||
const go = (tray) => {
|
||||
const options = multiple ? checkedAnswer(item.id) : [];
|
||||
if (options.length > 0) {
|
||||
void submit({ item_id: item.id, type: "option", options, text: typed() ? textAnswer(item.id) : undefined });
|
||||
void submit({ item_id: item.id, type: "option", options, text: typed() ? textAnswer(item.id) : undefined }, tray);
|
||||
return;
|
||||
}
|
||||
if (typed()) {
|
||||
void submit({ item_id: item.id, type: "other", text: textAnswer(item.id) });
|
||||
if (typed() || imageDrafts.has(imageKey)) {
|
||||
void submit({ item_id: item.id, type: "other", text: textAnswer(item.id) ?? "" }, tray);
|
||||
}
|
||||
};
|
||||
const other = textEntry("Other…", placeholder, { onInput: refresh, onSubmit: go });
|
||||
send.onclick = go;
|
||||
send.onclick = () => go(other.tray);
|
||||
refresh();
|
||||
replace(actions, other, h("div", { class: "submit-row" }, delegate(), send));
|
||||
replace(actions, other.el, h("div", { class: "submit-row" }, delegate(), send));
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
const dismiss = h("button", { type: "button" }, "Dismiss");
|
||||
dismiss.onclick = () => void submit({ item_id: item.id, type: "dismiss" });
|
||||
replace(actions, h("div", { class: "reply-row" }, textEntry("Reply…", "Reply to the agent"), dismiss));
|
||||
replace(actions, h("div", { class: "reply-row" }, textEntry("Reply…", "Reply to the agent").el, dismiss));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -251,7 +263,7 @@ function thread(item) {
|
||||
if (item.responses.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return h("ul", { class: "thread" }, ...item.responses.map((r) => h("li", {}, h("strong", {}, r.user), ` ${r.type.replace("_", " ")}`, r.options ? `: ${r.options.join("; ")}` : "", r.text ? ` — ${r.text}` : "")));
|
||||
return h("ul", { class: "thread" }, ...item.responses.map((r) => h("li", {}, h("strong", {}, r.user), ` ${r.type.replace("_", " ")}`, r.options ? `: ${r.options.join("; ")}` : "", r.text ? ` — ${r.text}` : "", r.images.length > 0 ? ` (${r.images.length === 1 ? "1 image" : `${r.images.length} images`})` : "")));
|
||||
}
|
||||
function attachments(list, taskId) {
|
||||
if (list.length === 0) {
|
||||
|
||||
Reference in New Issue
Block a user