Give a private task its own skill only, in the Ways panel too
ai_skills.get refuses a private-only skill in a task that is not private and every other skill in a private one, so a private task's AI gets the privacy skill alone; get_toolbox tells it by the task. The Ways panel lists the skills of the task's kind and is drawn again when the task's lock is turned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
eceb51b6a1
commit
4e5faad768
+2
-1
@@ -410,7 +410,8 @@ covered by the `styles.css` manifest.
|
||||
blocks by job (GET /anomalous/ai_blocks, `reference_blocks.status`), each block's words from its
|
||||
data file, greyed with the pack (a way into ComfyUI-Manager) or model it lacks, and a switch that
|
||||
keeps it from the AI (POST, `user/anomalous/ai_blocks.json`); under them the skills
|
||||
(`ai_skills.status`), each with the same switch (`user/anomalous/ai_skills.json`). For a run the AI did not wait
|
||||
(`ai_skills.status`), each with the same switch (`user/anomalous/ai_skills.json`), those of the
|
||||
task's kind only (a private task's, else the others), as the AI gets. For a run the AI did not wait
|
||||
for (`ai_gates.run_wait` "call") the server marks the ended run `call_ai` until the AI is told,
|
||||
and the lines over the message box are about it meanwhile. `ui_ai_side.js` is the
|
||||
stage, the column on the right where the AI's panels are shown (the timeline keeps a card per
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
## v1.63.0 — unreleased
|
||||
|
||||
- 新增 **隐私模式**:任务标题栏的 **🔒** 一点,这个任务的**图和提示词原文**都不会发给 AI。图一张都不给(放大看图、图片信息、跑完的预览、你递给它的图、AI 软件里任务卡片上的图都一样),它只知道出了几张、成没成功;提示词和图片文件名换成 **[P1]**、**[img1]** 这样的代号:画布上、图片信息里、提示词库、搭配、模型的触发词和介绍、你自己改画布的记录里都一样(只有节点的“文字输入”被换掉,模型名、数字、选项照常给,第三方节点也一样)。AI 拿代号去跑图、写提示词、放挑图面板,AMB 再换回原文,所以它照样能干活,你那边看到的也都是原样。要新的提示词时,AI 会放一个 **提示词框**:你在里面写几条提示词、反向提示词,可以从图库选或拖进参考图,原文只存在 AMB 里;框上方还会按画布主模型的大小提醒你(小模型手容易画坏,可以选简单动作或藏手,只是可选)。新增 skill“隐私模式·怎么干活”,隐私任务里的 AI 开工时会被指过去。**关卡** 窗口里设新任务默认开不开;打开、关掉都记在时间线上并告诉 AI。所有工具的结果出门前都过同一道关,测试会在每个工具的结果里埋“暗号”提示词和图片名,确认一个都漏不出去。
|
||||
- New: **privacy mode**. The **🔒** in a task's header keeps that task's **pictures and prompt text** from the AI. No picture goes (a closer look, picture info, a run's previews, pictures you hand over, the task card in the AI app alike): it hears how many came out and whether they did. Prompts and picture file names become tokens like **[P1]** and **[img1]**: on the canvas, in picture info, saved prompts, combos, models' trigger words and descriptions, and your own canvas changes (only the nodes' text inputs are swapped; model names, numbers and choices stay, third-party nodes too). The AI runs, writes prompts and shows pick panels with the tokens and Anomalous puts the texts back, so it still works and you see everything as it is. For new prompts the AI shows a **prompt box**: you write prompts and a negative one and add reference pictures from the gallery or by dropping them; the texts stay in Anomalous, and above the box a word on what suits the canvas's model (a smaller model often gets hands wrong: a simple pose, or hands hidden, as an option). A new skill, "Privacy mode: how to work", is where a private task's AI is pointed. The **Gates** window sets it for new tasks; turning it on or off is on the timeline and told to the AI. Every tool's result passes one check on its way out, and a test plants canary prompts and picture names in every tool's result to make sure none gets through.
|
||||
- 新增 **隐私模式**:任务标题栏的 **🔒** 一点,这个任务的**图和提示词原文**都不会发给 AI。图一张都不给(放大看图、图片信息、跑完的预览、你递给它的图、AI 软件里任务卡片上的图都一样),它只知道出了几张、成没成功;提示词和图片文件名换成 **[P1]**、**[img1]** 这样的代号:画布上、图片信息里、提示词库、搭配、模型的触发词和介绍、你自己改画布的记录里都一样(只有节点的“文字输入”被换掉,模型名、数字、选项照常给,第三方节点也一样)。AI 拿代号去跑图、写提示词、放挑图面板,AMB 再换回原文,所以它照样能干活,你那边看到的也都是原样。要新的提示词时,AI 会放一个 **提示词框**:你在里面写几条提示词、反向提示词,可以从图库选或拖进参考图,原文只存在 AMB 里;框上方还会按画布主模型的大小提醒你(小模型手容易画坏,可以选简单动作或藏手,只是可选)。新增 skill“隐私模式·怎么干活”,隐私任务里的 AI 开工时会被指过去;隐私任务里 AI 只拿得到这一个 skill,**做法** 面板的 skill 一栏也只显示它,关掉隐私后才换回普通的 skill。**关卡** 窗口里设新任务默认开不开;打开、关掉都记在时间线上并告诉 AI。所有工具的结果出门前都过同一道关,测试会在每个工具的结果里埋“暗号”提示词和图片名,确认一个都漏不出去。
|
||||
- New: **privacy mode**. The **🔒** in a task's header keeps that task's **pictures and prompt text** from the AI. No picture goes (a closer look, picture info, a run's previews, pictures you hand over, the task card in the AI app alike): it hears how many came out and whether they did. Prompts and picture file names become tokens like **[P1]** and **[img1]**: on the canvas, in picture info, saved prompts, combos, models' trigger words and descriptions, and your own canvas changes (only the nodes' text inputs are swapped; model names, numbers and choices stay, third-party nodes too). The AI runs, writes prompts and shows pick panels with the tokens and Anomalous puts the texts back, so it still works and you see everything as it is. For new prompts the AI shows a **prompt box**: you write prompts and a negative one and add reference pictures from the gallery or by dropping them; the texts stay in Anomalous, and above the box a word on what suits the canvas's model (a smaller model often gets hands wrong: a simple pose, or hands hidden, as an option). A new skill, "Privacy mode: how to work", is where a private task's AI is pointed; it is the only skill a private task's AI gets, and the only one the **Ways** panel lists for it, the usual skills coming back once privacy mode is off. The **Gates** window sets it for new tasks; turning it on or off is on the timeline and told to the AI. Every tool's result passes one check on its way out, and a test plants canary prompts and picture names in every tool's result to make sure none gets through.
|
||||
- AI 可以一次排一串提示词:跑图时给几条提示词(最多 8 条),AMB 按顺序一条条填进去排队,其余设置(比如同一个种子)每条都一样,算同一次跑图,图都在时间线的同一步里。以前要一条条跑、每次一个来回。哪一条排不上就停在那里,前面排上的照常跑完。
|
||||
- An AI can queue a list of prompts: a run given several prompts (up to 8) fills them in and queues them in order, the other settings (the same seed, say) the same for each, as one run whose pictures share one step of the timeline, instead of a round trip per prompt. One that cannot be queued stops the rest; those queued before it run as usual.
|
||||
- 同一个模型的几个版本放在一起:扫描认出来自同一个 Civitai 模型页的文件,在模型列表里收成一张卡片,卡片右边有一条带数字的箭头,点一下其余版本就从它右边滑出来、并排挨着,同一个模型的卡片顶上是同一道橙色边;最后一张右边的箭头点一下又收回去。展开后每张卡片的版本名旁边有个图钉,点哪个,收起时就显示哪个版本(封面、名字、插入节点都跟着换)。展开过的模型下次打开还是展开的;版本多的话,类型下面那排最右边的 **展开全部版本** 一下全展开,再点一下全收起。只认 Civitai 的模型编号,文件名再像也不会合在一起;没扫描、Civitai 上找不到的模型照旧各自一张。模型详情里名字下面一排列出这里有的几个版本,点一下就过去;再下面的 **Civitai 上的全部版本** 点了才联网,列出这个模型页的每个版本(底模、日期、大小),这里有的可以直接打开,没有的点 **下载** 放到这个模型旁边,下载完按 SHA-256 核对;名字和已有文件重了,就在名字后面加上版本名,不覆盖。
|
||||
|
||||
+8
-3
@@ -10,7 +10,8 @@ begin_task lists the skills on (name and short); get_toolbox(skill=…)
|
||||
gives one. The tools' own descriptions only point at a skill, so the list every app holds stays
|
||||
small. The user turns a skill off in the panel (user/anomalous/ai_skills.json): the AI is not
|
||||
offered it and get_toolbox refuses it. A skill marked private_only is for private tasks
|
||||
(ai_privacy.py): begin_task points at it there instead of listing the others. A by_model skill's
|
||||
(ai_privacy.py) and is all a private task gets: begin_task points at it there instead of listing
|
||||
the others, and get refuses each kind in the other kind of task. A by_model skill's
|
||||
for_user words say the same to the user, on the prompt box of a private task. Each skill fetched is a step of the AI's task (note_use), with
|
||||
the form its advice came in, so the user sees what the AI went by; the run after it says so too.
|
||||
"""
|
||||
@@ -98,13 +99,17 @@ def _model_name(model):
|
||||
return os.path.splitext(os.path.basename(str((model or {}).get("name") or "").replace("\\", "/")))[0]
|
||||
|
||||
|
||||
def get(name, model=None):
|
||||
def get(name, model=None, private=False):
|
||||
"""The advice of skill `name`, for get_toolbox; `model`: the canvas's main model {name, params},
|
||||
for a skill whose advice depends on it."""
|
||||
for a skill whose advice depends on it; `private`: the task is private (only its skills)."""
|
||||
if name not in SKILLS:
|
||||
raise SkillError(f"No skill {name!r}; begin_task lists them: {', '.join(SKILLS)}.")
|
||||
if name in turned_off():
|
||||
raise SkillError(f"The user turned the skill {name!r} off: do the job your own way.")
|
||||
if private and not SKILLS[name].get("private_only"):
|
||||
raise SkillError("This task is private: the user writes the prompts. Its skill is get_toolbox(skill=\"privacy\").")
|
||||
if not private and SKILLS[name].get("private_only"):
|
||||
raise SkillError(f"The skill {name!r} is for private tasks; this one is not.")
|
||||
skill = SKILLS[name]
|
||||
lines = list(skill["text"])
|
||||
answer = {"skill": name, "advice": lines}
|
||||
|
||||
@@ -234,14 +234,15 @@ def stop_run(ctx, task=None):
|
||||
def get_toolbox(ctx, task=None, skill=None):
|
||||
from .mcp_canvas_edit import find_nodes
|
||||
|
||||
task_id = task or ctx.get("task") or ai_tasks.active_task_id(ctx.get("client") or "AI", ctx.get("session") or "")
|
||||
if skill:
|
||||
private = ai_privacy.applies(task_id)
|
||||
try:
|
||||
answer = ai_skills.get(str(skill), _canvas_model() if ai_skills.by_model(str(skill)) else None)
|
||||
answer = ai_skills.get(str(skill), _canvas_model() if ai_skills.by_model(str(skill)) else None, private)
|
||||
except ai_skills.SkillError as error:
|
||||
raise ToolError(str(error))
|
||||
ai_skills.note_use(ctx.get("client") or "AI", answer, session=ctx.get("session") or "", task_id=task or ctx.get("task"))
|
||||
return answer
|
||||
task_id = task or ctx.get("task") or ai_tasks.active_task_id(ctx.get("client") or "AI", ctx.get("session") or "")
|
||||
box = ai_toolbox.effective(ai_tasks.get_task(task_id)) if task_id else None
|
||||
if not box:
|
||||
return {"picked": False, "note": "The user picked nothing for this task; use what fits."}
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ claude mcp add --transport http anomalous http://127.0.0.1:8188/anomalous/mcp
|
||||
|
||||
**AI 改副本**(默认):AI 第一次改画布前,AMB 先把你正开着的工作流复制到一个以任务命名的新标签页(副本),之后 AI 的修改、读画布和运行都只在那一页;你切去别的标签页也没关系,它下次动手前 AMB 会先切回去。你原来的工作流一笔不动。AI 用 `new_workflow` / `open_workflow` 打开的标签页就直接算这个任务的。任务标题栏有 **AI 改副本 ▾**(点开可以换成 **改当前画布**,每种都写着是什么意思)和 **切到副本**(点一下切过去);**关卡** 窗口里的“AI 改画布时”设定新任务的默认做法。
|
||||
|
||||
**隐私模式**:有些图和提示词不方便给 AI 看时,点任务标题栏的 **🔒**,这个任务就成了隐私任务。AMB 一张图都不发给 AI(放大看图、图片信息里的图、跑完附带的预览、你递给它的图、AI 软件里任务卡片上的图都一样),它只知道出了几张、成没成功。提示词原文和图片文件名换成 **[P1]**、**[img1]** 这样的代号:画布上节点的文字输入(按 ComfyUI 自己的节点定义认,第三方节点也一样;模型名、数字、选项照常给)、图片信息、提示词库、搭配、工作流的设置、模型的触发词和介绍、你自己改画布的记录都一样,同一段文字永远是同一个代号。AI 用代号去写提示词、跑图、填加载图片、放挑图面板,AMB 在工具执行前换回原文,所以画布和出图都是原样,你看到的也都是原样;时间线上记的是代号。要新提示词时,AI 会放一个 **提示词框**:写几条提示词(可以再加)、反向提示词,可以从图库选或把图拖进来当参考图,点 **交给 AI(只给代号)**;原文只存在 AMB 里,交出后框里显示代号和你写的原文。框上方按画布主模型的大小提醒你(来自 skill“写提示词·动作适合模型”)。AI 怎么在隐私任务里干活写在 skill“隐私模式·怎么干活”里,开工时会被指过去;这个 skill 不在普通任务里列出。**关卡** 窗口里的“隐私模式”设新任务默认开不开;默认改成关时,原来按默认开着的任务仍然保持隐私。AI 的某次调用认不出属于哪个任务时,只要默认开着或者还有没做完的隐私任务,就按隐私处理。注意:任务做到一半才打开时,之前已经给过 AI 的收不回来;你自己在留言或 AI 聊天框里写的文字和贴的图,AMB 不拦(那是你主动给的);模型名字 AI 是看得到的。
|
||||
**隐私模式**:有些图和提示词不方便给 AI 看时,点任务标题栏的 **🔒**,这个任务就成了隐私任务。AMB 一张图都不发给 AI(放大看图、图片信息里的图、跑完附带的预览、你递给它的图、AI 软件里任务卡片上的图都一样),它只知道出了几张、成没成功。提示词原文和图片文件名换成 **[P1]**、**[img1]** 这样的代号:画布上节点的文字输入(按 ComfyUI 自己的节点定义认,第三方节点也一样;模型名、数字、选项照常给)、图片信息、提示词库、搭配、工作流的设置、模型的触发词和介绍、你自己改画布的记录都一样,同一段文字永远是同一个代号。AI 用代号去写提示词、跑图、填加载图片、放挑图面板,AMB 在工具执行前换回原文,所以画布和出图都是原样,你看到的也都是原样;时间线上记的是代号。要新提示词时,AI 会放一个 **提示词框**:写几条提示词(可以再加)、反向提示词,可以从图库选或把图拖进来当参考图,点 **交给 AI(只给代号)**;原文只存在 AMB 里,交出后框里显示代号和你写的原文。框上方按画布主模型的大小提醒你(来自 skill“写提示词·动作适合模型”)。AI 怎么在隐私任务里干活写在 skill“隐私模式·怎么干活”里,开工时会被指过去。隐私任务里 AI 只拿得到这一个 skill,做法面板的 skill 一栏也只显示它;普通任务正好反过来,只显示、只给普通的 skill。**关卡** 窗口里的“隐私模式”设新任务默认开不开;默认改成关时,原来按默认开着的任务仍然保持隐私。AI 的某次调用认不出属于哪个任务时,只要默认开着或者还有没做完的隐私任务,就按隐私处理。注意:任务做到一半才打开时,之前已经给过 AI 的收不回来;你自己在留言或 AI 聊天框里写的文字和贴的图,AMB 不拦(那是你主动给的);模型名字 AI 是看得到的。
|
||||
|
||||
**这次跑的节点结构**:每次运行那一步下面写着一行“底模 · 几个 LoRA · 尺寸 · 步数 · 几个节点”,点开有 **简单** 和 **完整** 两种看法(AMB 记得你上次选的)。简单:按每一段采样列出“用哪个模型加哪些 LoRA、提示词是什么、从空白画布还是从上一段的结果(放大多少)开始”,最后保存在哪;后一段和前一段一样的就写“和第 1 段一样”。完整:方块图,哪个底模、LoRA 和权重、正负提示词开头、尺寸、采样器设置、保存,方块之间的线标着类型。两种看法里点任意一项都能定位到画布上的节点。这张图是 AMB 按 ComfyUI 实际收到的工作流画的,不靠 AI 描述。上面的黄色小块是 **比上次改了什么**(比如“K采样器·步数:20 → 30”“新增「加载LoRA」”)。AI 讲解时可以用 `show_run_map` 一次把同一张图放上展台,不用自己拼。
|
||||
|
||||
|
||||
+10
-2
@@ -124,10 +124,18 @@ class SealedTests(unittest.TestCase):
|
||||
self.assertNotIn("canarypos", step["text"])
|
||||
self.assertIn("a.safetensors -> b.safetensors", step["text"], "the models it may know")
|
||||
|
||||
def test_the_skill_for_private_tasks_is_not_listed_elsewhere(self):
|
||||
def test_a_private_task_gets_its_own_skill_only(self):
|
||||
from api import ai_skills
|
||||
self.assertNotIn("privacy", ai_skills.directory())
|
||||
self.assertIn("prompts", " ".join(ai_skills.get("privacy")["advice"]))
|
||||
ctx = {"client": "test", "task": self.task}
|
||||
self.assertIn("prompts", " ".join(mcp_task_tools.get_toolbox(ctx, skill="privacy")["advice"]))
|
||||
with self.assertRaisesRegex(mcp_task_tools.ToolError, "privacy"):
|
||||
mcp_task_tools.get_toolbox(ctx, skill="prompt_pose")
|
||||
ai_privacy.set_private(self.task, False)
|
||||
with self.assertRaises(mcp_task_tools.ToolError):
|
||||
mcp_task_tools.get_toolbox(ctx, skill="privacy")
|
||||
self.assertIn("advice", mcp_task_tools.get_toolbox(ctx, skill="prompt_pose"))
|
||||
ai_privacy.set_private(self.task, True)
|
||||
self.assertEqual(mcp_task_tools.begin_task({"client": "test", "task": self.task}, "private")["privacy"], ai_privacy.NOTE)
|
||||
|
||||
|
||||
|
||||
@@ -1441,6 +1441,7 @@ export const i18n = {
|
||||
aiBlocksJob_process: "图片处理",
|
||||
aiSkillsHeading: "Skill(给 AI 的建议)",
|
||||
aiSkillsNote: "做法是 AMB 替 AI 搭节点;skill 是 AI 遇到这类活时自己去取的建议,不搭任何节点,你的原话优先。关掉的 AI 就拿不到。",
|
||||
aiSkillsNotePrivate: "这个任务开着隐私模式:AI 只拿得到下面这个 skill,照它用提示词框和代号干活;普通的 skill 在隐私模式关掉后才会出现。",
|
||||
modelVersionsOpen: "展开这个模型的 {count} 个版本(来自同一个 Civitai 模型页)",
|
||||
modelVersionsFold: "收起,只留图钉那个版本",
|
||||
modelVersionsPin: "收起时显示这个版本",
|
||||
@@ -4949,6 +4950,7 @@ export const i18n = {
|
||||
aiBlocksJob_process: "Picture work",
|
||||
aiSkillsHeading: "Skills (advice for the AI)",
|
||||
aiSkillsNote: "A way is nodes AMB builds for the AI; a skill is advice the AI fetches when that kind of job comes up. It builds nothing, and your own words come first. The AI can't fetch the ones turned off.",
|
||||
aiSkillsNotePrivate: "This task is in privacy mode: the AI gets only the skill below and works with the prompt box and tokens as it says. The other skills show again once privacy mode is off.",
|
||||
modelVersionsOpen: "Show this model's {count} versions (from one Civitai model page)",
|
||||
modelVersionsFold: "Fold, keeping the pinned version",
|
||||
modelVersionsPin: "Show this version when folded",
|
||||
|
||||
+14
-10
@@ -6,7 +6,7 @@
|
||||
* with, so the AI is not offered it; how it was tried (the card, a run's time) and the models it recommends
|
||||
* (api/block_models.json), each here or a button downloading it, link and SHA256 from the list.
|
||||
* Under them the skills (api/ai_skills.py): advice the AI fetches for a kind of job, each with its
|
||||
* switch too. GET /anomalous/ai_blocks, POST {name, on} or {skill, on}. Drawn when shown,
|
||||
* switch too; for a private task only the private task's skill, as that is all its AI gets. GET /anomalous/ai_blocks, POST {name, on} or {skill, on}. Drawn when shown,
|
||||
* the list read again each time the view is opened.
|
||||
*/
|
||||
|
||||
@@ -131,11 +131,12 @@ function blockRow(block, owner, redraw) {
|
||||
return row;
|
||||
}
|
||||
|
||||
/** The skills: a title, what it advises, its switch. */
|
||||
function skillsGroup(skills, redraw) {
|
||||
/** The skills of the task's kind (`private`): a title, what it advises, its switch. */
|
||||
function skillsGroup(skills, redraw, isPrivate) {
|
||||
const group = el('div', 'anomalous-ai-blocks-group');
|
||||
group.append(el('div', 'anomalous-ai-blocks-job', t('aiSkillsHeading')), el('div', 'anomalous-ai-blocks-note', t('aiSkillsNote')));
|
||||
for (const skill of skills) {
|
||||
group.append(el('div', 'anomalous-ai-blocks-job', t('aiSkillsHeading')),
|
||||
el('div', 'anomalous-ai-blocks-note', t(isPrivate ? 'aiSkillsNotePrivate' : 'aiSkillsNote')));
|
||||
for (const skill of skills.filter(item => Boolean(item.private_only) === isPrivate)) {
|
||||
const row = el('div', `anomalous-ai-block${skill.on ? '' : ' is-off'}`);
|
||||
const body = el('div', 'anomalous-ai-block-body');
|
||||
const head = el('div', 'anomalous-ai-block-head');
|
||||
@@ -147,7 +148,7 @@ function skillsGroup(skills, redraw) {
|
||||
return group;
|
||||
}
|
||||
|
||||
function listBox(owner, redraw) {
|
||||
function listBox(owner, redraw, isPrivate) {
|
||||
const body = el('div', 'anomalous-ai-stage-body anomalous-ai-blocks');
|
||||
if (!shown) {
|
||||
body.append(el('div', 'anomalous-ai-stage-empty', t('aiBlocksReading')));
|
||||
@@ -168,13 +169,16 @@ function listBox(owner, redraw) {
|
||||
group.append(el('div', 'anomalous-ai-blocks-job', t(`aiBlocksJob_${job}`)), ...blocks.map(block => blockRow(block, owner, redraw)));
|
||||
body.append(group);
|
||||
}
|
||||
if (shown.skills?.length) body.append(skillsGroup(shown.skills, redraw));
|
||||
if (shown.skills?.length) body.append(skillsGroup(shown.skills, redraw, isPrivate));
|
||||
return body;
|
||||
}
|
||||
|
||||
/** The view into `pane`; `ctx`: {close, owner}. `fresh`: the view was just opened, so the list is read again. */
|
||||
export function renderBlocksView(pane, ctx, fresh = false) {
|
||||
const redraw = () => pane.replaceChildren(sideHead(t('aiSideBlocks'), ctx.close), listBox(ctx.owner, redraw));
|
||||
/**
|
||||
* The view into `pane`; `ctx`: {close, owner}; `isPrivate`: the task shown is private (its skills only).
|
||||
* `fresh`: the view was just opened, so the list is read again.
|
||||
*/
|
||||
export function renderBlocksView(pane, ctx, fresh = false, isPrivate = false) {
|
||||
const redraw = () => pane.replaceChildren(sideHead(t('aiSideBlocks'), ctx.close), listBox(ctx.owner, redraw, isPrivate));
|
||||
if ((fresh || !shown) && !reading) {
|
||||
reading = ask().then(data => { shown = data; }, error => { shown = { error: error.message }; })
|
||||
.finally(() => { reading = null; redraw(); });
|
||||
|
||||
@@ -224,7 +224,12 @@ export function drawSide(box, task, side, ctx, pickTab, arrived = null) {
|
||||
if (side.view === 'map') renderMapView(panes.map, task, side, ctx);
|
||||
if (side.view === 'decisions') renderDecisionsView(panes.decisions, task, ctx);
|
||||
if (side.view === 'outputs') renderOutputsView(panes.outputs, task, ctx);
|
||||
if (side.view === 'blocks' && (opened || !panes.blocks.childElementCount)) renderBlocksView(panes.blocks, ctx, opened);
|
||||
// The ways and skills, drawn again when the view comes up or the task's privacy mode changed (its skills differ).
|
||||
const privacy = String(task.private === true);
|
||||
if (side.view === 'blocks' && (opened || !panes.blocks.childElementCount || panes.blocks.dataset.private !== privacy)) {
|
||||
panes.blocks.dataset.private = privacy;
|
||||
renderBlocksView(panes.blocks, ctx, opened, task.private === true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user