Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/1486-workflow-composer.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Workflow stage no longer shows the shell's message composer. Tasks are handed to the graph; the stage provides only pause/resume/progress controls. ([#1486](https://github.com/ThinkFlowLab/FlyBot/issues/1486))
1 change: 1 addition & 0 deletions changelog.d/1487-workflow-header.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Workflow stage header titles no longer duplicate the issue number, and task titles are shown without mid-text truncation. ([#1487](https://github.com/ThinkFlowLab/FlyBot/issues/1487))
1 change: 1 addition & 0 deletions changelog.d/1488-workflow-sidebar-locale.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Workflow sidebar rows show schedule previews in English when the UI locale is English. ([#1488](https://github.com/ThinkFlowLab/FlyBot/issues/1488))
1 change: 1 addition & 0 deletions changelog.d/1489-workflow-timeline-locale.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Workflow stage timeline shows step badges and event text in English when the UI locale is English. ([#1489](https://github.com/ThinkFlowLab/FlyBot/issues/1489))
1 change: 1 addition & 0 deletions changelog.d/1491-workflow-progress-button.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Workflow stage Progress button now ensures the drawer opens and switches to the Runs tab. ([#1491](https://github.com/ThinkFlowLab/FlyBot/issues/1491))
1 change: 1 addition & 0 deletions changelog.d/1492-notifications-title.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Settings → General → Notifications: the first toggle row now shows the title "In other chats" alongside its description. ([#1492](https://github.com/ThinkFlowLab/FlyBot/issues/1492))
1 change: 1 addition & 0 deletions changelog.d/1493-workflow-failed-runs.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Workflow stage now shows failed sibling runs in the header and timeline, not only in the Runs tab. ([#1493](https://github.com/ThinkFlowLab/FlyBot/issues/1493))
5 changes: 3 additions & 2 deletions core/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,7 @@ var ZH = {
"{count} updates": "{count} 条更新",
"Once more if it still waits after 15 min.": "等了 15 分钟还没批准时再提醒一次。",
Notifications: "通知",
"In other chats": "在其他对话时",
"When your Bots finish, fail, or wait for your approval while you are in another chat or app.": "你的 Bot 完成、失败或等你批准时提醒你(你在别的对话或应用里时)。",
"{first} and {second} are waiting for your approval": "{first}、{second} 等你批准",
"{first}, {second} and {count} more are waiting for your approval": "{first}、{second} 等 {total} 个等你批准",
Expand Down Expand Up @@ -4745,6 +4746,7 @@ body[data-bt-friend-chat] [data-composer-stats]{display:none!important}
body[data-bt-room] .bt-voice{display:none!important}
body[data-bt-room] [data-composer-card] [class*="_activity"]{display:none!important}
body[data-bt-room] [data-composer-card]:has(button[class*="_primary"]:disabled) .bt-mic:not([aria-pressed=true]){background:var(--bt-accent);color:var(--bt-accent-ink,#fff)}
body[data-bt-workflow] [data-composer-card]{display:none!important}
.bt-mic-note{position:absolute;right:12px;bottom:calc(100% + 8px);padding:5px 10px;border-radius:8px;background:var(--bt-user);color:var(--bt-user-ink);font-size:12px;line-height:16px;white-space:nowrap;pointer-events:none;animation:bt-rise .16s ease-out}
[data-chain-overlay-fallback="conversation.composer"]:has(~ .bt-q){display:block!important;order:2}
.bt-q{order:1}
Expand Down Expand Up @@ -16698,8 +16700,7 @@ function GeneralPage({ roster, actions, run }) {
SetSection,
{ key: "notify", title: t("Notifications") },
(0, import_react39.createElement)(SwitchRow, {
label: t("Notifications"),
showLabel: false,
label: t("In other chats"),
hint: t("When your Bots finish, fail, or wait for your approval while you are in another chat or app."),
on: prefs.notifications !== false,
onChange: (on) => run(actions.setPrefs({ notifications: on }))
Expand Down
1 change: 1 addition & 0 deletions core/src/client/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,7 @@ const ZH = {
'{count} updates': '{count} 条更新',
'Once more if it still waits after 15 min.': '等了 15 分钟还没批准时再提醒一次。',
Notifications: '通知',
'In other chats': '在其他对话时',
'When your Bots finish, fail, or wait for your approval while you are in another chat or app.': '你的 Bot 完成、失败或等你批准时提醒你(你在别的对话或应用里时)。',
'{first} and {second} are waiting for your approval': '{first}、{second} 等你批准',
'{first}, {second} and {count} more are waiting for your approval': '{first}、{second} 等 {total} 个等你批准',
Expand Down
2 changes: 1 addition & 1 deletion core/src/client/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function GeneralPage({ roster, actions, run }) {
// One switch for every system notification (#353), then one per kind (#469).
h(SetSection, { key: 'notify', title: t('Notifications') },
h(SwitchRow, {
label: t('Notifications'), showLabel: false,
label: t('In other chats'),
hint: t('When your Bots finish, fail, or wait for your approval while you are in another chat or app.'),
on: prefs.notifications !== false, onChange: on => run(actions.setPrefs({ notifications: on })),
}),
Expand Down
1 change: 1 addition & 0 deletions core/src/client/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,7 @@ body[data-bt-friend-chat] [data-composer-stats]{display:none!important}
body[data-bt-room] .bt-voice{display:none!important}
body[data-bt-room] [data-composer-card] [class*="_activity"]{display:none!important}
body[data-bt-room] [data-composer-card]:has(button[class*="_primary"]:disabled) .bt-mic:not([aria-pressed=true]){background:var(--bt-accent);color:var(--bt-accent-ink,#fff)}
body[data-bt-workflow] [data-composer-card]{display:none!important}
.bt-mic-note{position:absolute;right:12px;bottom:calc(100% + 8px);padding:5px 10px;border-radius:8px;background:var(--bt-user);color:var(--bt-user-ink);font-size:12px;line-height:16px;white-space:nowrap;pointer-events:none;animation:bt-rise .16s ease-out}
[data-chain-overlay-fallback="conversation.composer"]:has(~ .bt-q){display:block!important;order:2}
.bt-q{order:1}
Expand Down
3 changes: 2 additions & 1 deletion patches/ds-bot/0001-core-fixes.patch
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ diff --git a/src/client/i18n.js b/src/client/i18n.js
"{name} didn't answer in time": '{name} 没有及时回应',
'{name} paused for your approval': '{name} 停下来等你批准',
'{name} started on it': '{name} 开始做了',
@@ -450,12 +450,30 @@ const ZH = {
@@ -450,12 +450,31 @@ const ZH = {
'Asked to make the tool call it wrote as text': '工具调用被写成了文字,已让它重新调用',
'A Bot': '一个 Bot',
'{name} is waiting for your approval': '{name} 等你批准',
Expand All @@ -1197,6 +1197,7 @@ diff --git a/src/client/i18n.js b/src/client/i18n.js
+ '{count} updates': '{count} 条更新',
+ 'Once more if it still waits after 15 min.': '等了 15 分钟还没批准时再提醒一次。',
+ Notifications: '通知',
+ 'In other chats': '在其他对话时',
+ 'When your Bots finish, fail, or wait for your approval while you are in another chat or app.': '你的 Bot 完成、失败或等你批准时提醒你(你在别的对话或应用里时)。',
'{first} and {second} are waiting for your approval': '{first}、{second} 等你批准',
'{first}, {second} and {count} more are waiting for your approval': '{first}、{second} 等 {total} 个等你批准',
Expand Down
4 changes: 3 additions & 1 deletion patches/ds-bot/0003-flybot-api-client.patch
Original file line number Diff line number Diff line change
Expand Up @@ -2988,14 +2988,16 @@ diff --git a/src/client/styles.js b/src/client/styles.js
[data-composer-placeholder]::after{content:var(--bt-placeholder,"Message");display:block;font-size:14px;line-height:24px;color:color-mix(in srgb,var(--bt-ink) 36%,transparent)}
/* The team's "+" (ComposerPlus) takes the seat of the shell's command-menu button. */
[data-composer-card] button[class*="_add"]{display:none!important}
@@ -905,6 +905,7 @@ header[class*="_header"] .bt-head{flex:1 1 auto;width:100%}
@@ -905,7 +905,9 @@ header[class*="_header"] .bt-head{flex:1 1 auto;width:100%}
.bt-mic:active,.bt-voice:active{scale:.9}
[data-composer-card]:has(button[class*="_primary"]:disabled) .bt-voice{display:inline-grid}
body[data-bt-room] .bt-voice{display:none!important}
+body[data-bt-room] [data-composer-card] [class*="_activity"]{display:none!important}
body[data-bt-room] [data-composer-card]:has(button[class*="_primary"]:disabled) .bt-mic:not([aria-pressed=true]){background:var(--bt-accent);color:var(--bt-accent-ink,#fff)}
+body[data-bt-workflow] [data-composer-card]{display:none!important}
.bt-mic-note{position:absolute;right:12px;bottom:calc(100% + 8px);padding:5px 10px;border-radius:8px;background:var(--bt-user);color:var(--bt-user-ink);font-size:12px;line-height:16px;white-space:nowrap;pointer-events:none;animation:bt-rise .16s ease-out}
[data-chain-overlay-fallback="conversation.composer"]:has(~ .bt-q){display:block!important;order:2}
.bt-q{order:1}
@@ -959,6 +959,7 @@ div:has(> nav [class*="_marks"]){display:none!important}
.bt-earlier-top{display:flex;justify-content:center;align-items:center;height:34px;flex:none}
.bt-earlier-top .bt-soft{height:28px;font-size:12px;padding:0 12px}
Expand Down
11 changes: 6 additions & 5 deletions patches/ds-bot/0008-client-bundle.patch
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ diff --git a/client.js b/client.js
"{name} didn't answer in time": "{name} 没有及时回应",
"{name} paused for your approval": "{name} 停下来等你批准",
"{name} started on it": "{name} 开始做了",
@@ -506,12 +506,30 @@ var ZH = {
@@ -506,12 +506,31 @@ var ZH = {
"Asked to make the tool call it wrote as text": "工具调用被写成了文字,已让它重新调用",
"A Bot": "一个 Bot",
"{name} is waiting for your approval": "{name} 等你批准",
Expand All @@ -617,6 +617,7 @@ diff --git a/client.js b/client.js
+ "{count} updates": "{count} 条更新",
+ "Once more if it still waits after 15 min.": "等了 15 分钟还没批准时再提醒一次。",
+ Notifications: "通知",
+ "In other chats": "在其他对话时",
+ "When your Bots finish, fail, or wait for your approval while you are in another chat or app.": "你的 Bot 完成、失败或等你批准时提醒你(你在别的对话或应用里时)。",
"{first} and {second} are waiting for your approval": "{first}、{second} 等你批准",
"{first}, {second} and {count} more are waiting for your approval": "{first}、{second} 等 {total} 个等你批准",
Expand Down Expand Up @@ -4363,7 +4364,7 @@ diff --git a/client.js b/client.js
.bt-account{flex:none;width:36px;height:36px;border:0;padding:0;background:none;border-radius:50%;cursor:pointer;display:inline-flex}
.bt-account:hover .bt-you,.bt-account[aria-expanded=true] .bt-you{background:color-mix(in srgb,var(--bt-ink) 9%,var(--bt-sidebar))}
/* Popover keyframes move translate and scale, which compose with a transform the popover
@@ -2488,2292 +2488,4418 @@ body[data-ds-dark-theme] .bt-theme-chip i{background:var(--da)}
@@ -2488,2292 +2488,4419 @@ body[data-ds-dark-theme] .bt-theme-chip i{background:var(--da)}
@keyframes bt-rise{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.bt-member,.bt-addlist{animation:none}}

Expand Down Expand Up @@ -4728,6 +4729,7 @@ diff --git a/client.js b/client.js
+body[data-bt-room] .bt-voice{display:none!important}
+body[data-bt-room] [data-composer-card] [class*="_activity"]{display:none!important}
+body[data-bt-room] [data-composer-card]:has(button[class*="_primary"]:disabled) .bt-mic:not([aria-pressed=true]){background:var(--bt-accent);color:var(--bt-accent-ink,#fff)}
+body[data-bt-workflow] [data-composer-card]{display:none!important}
+.bt-mic-note{position:absolute;right:12px;bottom:calc(100% + 8px);padding:5px 10px;border-radius:8px;background:var(--bt-user);color:var(--bt-user-ink);font-size:12px;line-height:16px;white-space:nowrap;pointer-events:none;animation:bt-rise .16s ease-out}
+[data-chain-overlay-fallback="conversation.composer"]:has(~ .bt-q){display:block!important;order:2}
+.bt-q{order:1}
Expand Down Expand Up @@ -18636,7 +18638,7 @@ diff --git a/client.js b/client.js
key: ink,
type: "button",
className: "bt-swatch",
@@ -10626,75 +10626,87 @@ function GeneralPage({ roster, actions, run }) {
@@ -10626,75 +10626,86 @@ function GeneralPage({ roster, actions, run }) {
style: { background: INKS[ink][0] },
onClick: () => run(actions.setPrefs({ accent: INKS[ink][0] }))
})),
Expand All @@ -18662,8 +18664,7 @@ diff --git a/client.js b/client.js
- )
+ { key: "notify", title: t("Notifications") },
+ (0, import_react39.createElement)(SwitchRow, {
+ label: t("Notifications"),
+ showLabel: false,
+ label: t("In other chats"),
+ hint: t("When your Bots finish, fail, or wait for your approval while you are in another chat or app."),
+ on: prefs.notifications !== false,
+ onChange: (on) => run(actions.setPrefs({ notifications: on }))
Expand Down
2 changes: 1 addition & 1 deletion patches/ds-bot/0014-flybot-branding.patch
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ diff --git a/src/client/settings.js b/src/client/settings.js
+ // One switch for every system notification (#353), then one per kind (#469).
+ h(SetSection, { key: 'notify', title: t('Notifications') },
+ h(SwitchRow, {
+ label: t('Notifications'), showLabel: false,
+ label: t('In other chats'),
+ hint: t('When your Bots finish, fail, or wait for your approval while you are in another chat or app.'),
+ on: prefs.notifications !== false, onChange: on => run(actions.setPrefs({ notifications: on })),
+ }),
Expand Down
33 changes: 24 additions & 9 deletions plugins/workflow/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ window.__ModuleLoader__.load({
'Could not delete this workflow': '无法删除该 Workflow',
'Reading workflows…': '正在读取 Workflow…',
'Changes are saved automatically': '更改会自动保存',
'Next run: {time}': '下次运行:{time}',
'Step {step}': '步骤 {step}',
'Parallel branches · Merge after all pass': '并行分支 · 全部通过后汇合',
}

function zhUi() {
Expand Down Expand Up @@ -194,8 +197,12 @@ window.__ModuleLoader__.load({
if (!id && !title) return ''
if (!title) return id
if (!id) return title.length > 72 ? `${title.slice(0, 69)}…` : title
// Remove issue number prefix from title if it duplicates the id
let cleanTitle = title
const issueMatch = title.match(/^issue\s+#?\d+\s*[:\-–—]\s*/i)
if (issueMatch && id) cleanTitle = title.slice(issueMatch[0].length)
const room = Math.max(24, 72 - id.length - 3)
const short = title.length > room ? `${title.slice(0, room - 1)}…` : title
const short = cleanTitle.length > room ? `${cleanTitle.slice(0, room - 1)}…` : cleanTitle
return `${id} · ${short}`
}
function chatPreview(text) {
Expand All @@ -206,7 +213,7 @@ window.__ModuleLoader__.load({
function sidebarPreview(item) {
const busy = (item.activeCount ?? 0) > 0 && item.run?.live === true
if (busy) return item.preview || tr('Waiting for a task')
if (item.trigger === 'schedule' && item.scheduleLabel) return `下次运行:${item.scheduleLabel}`
if (item.trigger === 'schedule' && item.scheduleLabel) return tr('Next run: {time}', { time: item.scheduleLabel })
return tr('Waiting for a task')
}
function glyph() {
Expand Down Expand Up @@ -375,8 +382,8 @@ window.__ModuleLoader__.load({
? h('button', { type: 'button', className: 'wf-btn wf-sm wf-pri', onClick: (event) => { stopBubble(event); onResume?.(run.id) } }, tr('Resume'))
: h('button', { type: 'button', className: 'wf-btn wf-sm', onClick: (event) => { stopBubble(event); onPause?.(run.id) } }, tr('Pause'))) : null,
run.status === 'running' ? h('button', { type: 'button', className: 'wf-btn wf-sm wf-danger-outline', onClick: (event) => { stopBubble(event); onStop?.(run.id) } }, tr('Stop')) : null,
h('button', { type: 'button', className: 'wf-btn wf-sm', onClick: (event) => { stopBubble(event); focus(); onTab('runs'); onOpenDrawer?.() } }, tr('Progress')),
h('button', { type: 'button', className: 'wf-btn wf-sm', onClick: (event) => { stopBubble(event); focus(); onTab('flow'); onOpenDrawer?.() } }, tr('Flow'))))
h('button', { type: 'button', className: 'wf-btn wf-sm', onClick: (event) => { stopBubble(event); focus(); onOpenDrawer?.(); onTab('runs') } }, tr('Progress')),
h('button', { type: 'button', className: 'wf-btn wf-sm', onClick: (event) => { stopBubble(event); focus(); onOpenDrawer?.(); onTab('flow') } }, tr('Flow'))))
}

// Stage: view/control only — progress and flowchart; no message composer (#1459).
Expand Down Expand Up @@ -423,7 +430,7 @@ window.__ModuleLoader__.load({
return h('div', { className: 'wf-msg' },
h(Mark, { node, roster, size: 28 }),
h('div', null,
h('div', { className: 'wf-who' }, node.name, message.step ? h('span', { className: 'wf-step' }, `步骤 ${message.step}`) : null),
h('div', { className: 'wf-who' }, node.name, message.step ? h('span', { className: 'wf-step' }, tr('Step {step}', { step: message.step })) : null),
h('div', { className: 'wf-bub', title: message.text }, chatPreview(message.text),
message.attachments?.length ? h('div', { className: 'wf-att' }, message.attachments.map(name => h('span', { key: name }, name))) : null)))
}
Expand Down Expand Up @@ -488,8 +495,8 @@ window.__ModuleLoader__.load({
}

function liveStageRuns(workflow) {
let liveRuns = (workflow.runs ?? []).filter(run => run?.live === true && run.status === 'running')
if (liveRuns.length === 0 && workflow.run?.live === true && workflow.run.status === 'running') {
let liveRuns = (workflow.runs ?? []).filter(run => run?.live === true && (run.status === 'running' || run.status === 'failed'))
if (liveRuns.length === 0 && workflow.run?.live === true && (workflow.run.status === 'running' || workflow.run.status === 'failed')) {
liveRuns = [workflow.run]
}
return liveRuns
Expand All @@ -501,7 +508,7 @@ window.__ModuleLoader__.load({
const picked = live.find(run => run.id === focusedRunId)
if (picked) return picked
}
if (workflow.run?.live === true && workflow.run.status === 'running') return workflow.run
if (workflow.run?.live === true && (workflow.run.status === 'running' || workflow.run.status === 'failed')) return workflow.run
return live[0] ?? null
}

Expand Down Expand Up @@ -614,7 +621,7 @@ window.__ModuleLoader__.load({
return h('div', {
key: layer.join('+'), className: 'wf-par wf-abs',
style: parallelFrameStyle(members),
}, h('div', { className: 'wf-plabel' }, '并行分支 · 全部通过后汇合'))
}, h('div', { className: 'wf-plabel' }, tr('Parallel branches · Merge after all pass')))
}),
nodes.map(node => h('div', {
key: node.id,
Expand Down Expand Up @@ -1140,6 +1147,14 @@ window.__ModuleLoader__.load({
if (!live.some(run => run.id === focusedRunId)) setFocusedRunId(live[0].id)
}, [open?.id, open?.activeCount, open?.runs?.length, focusedRunId])

// Hide the shell's composer when a Workflow stage is open (#1486)
useEffect(() => {
if (typeof document === 'undefined' || !document.body || !document.body.dataset) return undefined
if (!open) return undefined
document.body.dataset.btWorkflow = ''
return () => { delete document.body.dataset.btWorkflow }
}, [open?.id])

const loadTasks = async () => {
const host = globalThis.__flybot__?.host
if (typeof host !== 'function') { setTasks([]); return }
Expand Down
2 changes: 1 addition & 1 deletion plugins/workflow/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ test('the sidebar opens the flowchart, and a drag, a wire and a dropped Bot are
findAll(view.tree, node => node.type === 'button' && textOf(node).includes('发布交付流水线'))[0].props.onClick()
findAll(view.tree, node => node.type === 'button' && textOf(node) === 'Flow')[0].props.onClick()
const opened = textOf(view.tree)
assert.ok(opened.includes('并行分支 · 全部通过后汇合'))
assert.ok(opened.includes('Parallel branches · Merge after all pass'))
assert.ok(opened.includes('Reviewer'))
assert.ok(opened.includes('Tester'))
const html = htmlOf(view.tree)
Expand Down
Loading