A task the AI never names (mostly one asked for in the AI app's own chat, with no begin_task) took the summary of its first step that did something as its title, so the list read "run_workflow" or "new_workflow: anima test". ai_task_title.js shows such a title (title_from "auto", now in the list's summaries and the task links) with the tool in the page's words, "新建了工作流:anima test"; a title the user or the AI gave stays as written, and every page naming a task uses it. Renaming starts from that name. The short set's note said "drawing in the AI app's own chat", which the user read as the picture being drawn in the AI app. It now says it is for telling the AI to draw right in the app's chat, the picture still drawn by ComfyUI, and that a task started with New task cannot use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
60 lines
3.1 KiB
JavaScript
60 lines
3.1 KiB
JavaScript
/**
|
|
* The ⋯ of a task, in its head and on its row in the list: what is done to a task now and then (rename
|
|
* it, say what it goes on from, keep its pictures from the AI, remove it), out of the way of the tools
|
|
* used while it runs.
|
|
*/
|
|
|
|
import { translate as t } from './locales.js';
|
|
import { forgetTask } from './ai_task_cache.js';
|
|
import { anomalousAlert, anomalousConfirm, anomalousPrompt } from './ui_dialog.js';
|
|
import { modelTokens, setPrivacy } from './ui_ai_privacy.js';
|
|
import { openSent } from './ui_ai_sent.js';
|
|
import { pickTaskLink } from './ui_ai_task_links.js';
|
|
import { openPopupMenu } from './ui_popup_menu.js';
|
|
import { taskTitle } from './ai_task_title.js';
|
|
|
|
/**
|
|
* What the menu of `task` does. `tasks`: the list's summaries; `post(id, body)` writes to the task,
|
|
* `refresh()` draws the page again, `removed()` lets go of a removed task, before that.
|
|
*/
|
|
export function menuActions(task, { tasks, post, refresh, removed }) {
|
|
return { tasks, changed: () => void refresh(), rename: async () => {
|
|
const named = await anomalousPrompt(t('aiRenamePrompt'), task.title ? taskTitle(task) : '', t('aiRename'));
|
|
if (named === null || named === undefined) return;
|
|
await post(task.id, { title: named }).catch(error => anomalousAlert(error.message));
|
|
await refresh();
|
|
}, remove: async () => {
|
|
if (!await anomalousConfirm(t('aiRemoveConfirm'), t('aiRemove'))) return;
|
|
await post(task.id, { remove: true }).catch(error => anomalousAlert(error.message));
|
|
forgetTask(task.id);
|
|
removed();
|
|
await refresh();
|
|
} };
|
|
}
|
|
|
|
/** The menu of `task` (its full record) under `anchor`; the rest from menuActions. */
|
|
export function openTaskMenu(anchor, task, { tasks, rename, remove, changed }) {
|
|
const place = anchor.getBoundingClientRect(); // the head is drawn anew every few seconds: the button may be another by the time a row is chosen
|
|
openPopupMenu(anchor, [
|
|
{ label: t('aiRename'), run: rename },
|
|
...(task.links?.from ? [] : [{ label: t('aiTaskLink'), title: t('aiTaskLinkHint'), run: () => pickTaskLink(place, task, tasks, changed) }]),
|
|
{ label: t(task.private ? 'aiPrivacyTurnOff' : 'aiPrivacyTurnOn'), title: t(task.private ? 'aiPrivacyHint_on' : 'aiPrivacyHint_off'),
|
|
run: () => void setPrivacy(task, !task.private, changed) },
|
|
...(task.private || Object.keys(task.sealed || {}).length ? [{ label: t('aiSent'), title: t('aiSentHint'), run: () => void openSent(task) }] : []),
|
|
...(modelTokens(task) ? [{ label: t('aiModelTokens'), title: t('aiModelTokensHint'),
|
|
run: () => void anomalousAlert(modelTokens(task), t('aiModelTokens')) }] : []),
|
|
{ label: t('aiRemove'), danger: true, run: remove },
|
|
]);
|
|
}
|
|
|
|
/** The button in the head of `task`. */
|
|
export function taskMenu(task, actions) {
|
|
const more = document.createElement('button');
|
|
more.type = 'button';
|
|
more.className = 'anomalous-ai-tool is-icon';
|
|
more.textContent = '⋯';
|
|
more.title = t('notebookMore');
|
|
more.onclick = () => openTaskMenu(more, task, actions);
|
|
return more;
|
|
}
|