@sparkelf/dsh-plus 0.2.2-alpha.2.9 → 0.2.4-alpha.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -7
- package/README.zh.md +5 -7
- package/package.json +480 -405
- package/patches/dsh-resource-ref-chip.patch +40 -0
- package/patches/session-controller-image-downgrade-and-tool-visibility.patch +83 -0
- package/patches/ui-schedule-plaza-tab.patch +217 -0
- package/patches/ui-sidebar-right-global-panel.patch +36 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
diff --git a/packages/client/ui-conversation/src/client/contract/draft-editor.ts b/packages/client/ui-conversation/src/client/contract/draft-editor.ts
|
|
2
|
+
index b305bb3a3c..0aee9f6be2 100644
|
|
3
|
+
--- a/packages/client/ui-conversation/src/client/contract/draft-editor.ts
|
|
4
|
+
+++ b/packages/client/ui-conversation/src/client/contract/draft-editor.ts
|
|
5
|
+
@@ -15,7 +15,7 @@ export interface ReferenceInsert {
|
|
6
|
+
readonly source: string
|
|
7
|
+
readonly ref: string
|
|
8
|
+
readonly label: string
|
|
9
|
+
- readonly appearance?: 'session' | 'file' | 'folder'
|
|
10
|
+
+ readonly appearance?: 'session' | 'file' | 'folder' | 'resource'
|
|
11
|
+
readonly clipboardText: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
diff --git a/packages/client/ui-primitives/src/ReferenceIcon.tsx b/packages/client/ui-primitives/src/ReferenceIcon.tsx
|
|
15
|
+
index ca566c40f6..198e6bbb1d 100644
|
|
16
|
+
--- a/packages/client/ui-primitives/src/ReferenceIcon.tsx
|
|
17
|
+
+++ b/packages/client/ui-primitives/src/ReferenceIcon.tsx
|
|
18
|
+
@@ -6,7 +6,7 @@ import {
|
|
19
|
+
} from './icons/shared-artwork.tsx'
|
|
20
|
+
|
|
21
|
+
/** Reference domains with distinct composer and transcript glyphs. */
|
|
22
|
+
-export type ReferenceIconKind = 'session' | 'file' | 'folder'
|
|
23
|
+
+export type ReferenceIconKind = 'session' | 'file' | 'folder' | 'resource'
|
|
24
|
+
|
|
25
|
+
/** Props shared by inline reference glyphs. */
|
|
26
|
+
export interface ReferenceIconProps extends IconProps {
|
|
27
|
+
@@ -27,6 +27,13 @@ function ReferenceIconArtwork({ kind, size = 16, className, strokeWidth }: Weigh
|
|
28
|
+
case 'session': return <ChatLinesOutlineArtwork size={size} className={className} strokeWidth={strokeWidth} />
|
|
29
|
+
case 'file': return <BrowseOutlineArtwork size={size} className={className} strokeWidth={strokeWidth} />
|
|
30
|
+
case 'folder': return <FolderCloseArtwork size={size} className={className} strokeWidth={strokeWidth} />
|
|
31
|
+
+ case 'resource': return (
|
|
32
|
+
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round" className={className} aria-hidden>
|
|
33
|
+
+ <path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" />
|
|
34
|
+
+ <path d="m3.3 7 8.7 5 8.7-5" />
|
|
35
|
+
+ <path d="M12 22V12" />
|
|
36
|
+
+ </svg>
|
|
37
|
+
+ )
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
--- a/packages/api/session-controller/src/commands.ts 2026-11-03 00:40:46.207711920 +0800
|
|
2
|
+
+++ b/packages/api/session-controller/src/commands.ts 2026-11-03 00:40:46.209868821 +0800
|
|
3
|
+
@@ -83,6 +83,9 @@
|
|
4
|
+
|
|
5
|
+
/** Implements Session business commands delegated by the Session Controller Remote service. */
|
|
6
|
+
export class SessionCommandController {
|
|
7
|
+
+ /** 每个 agent 当前生效的工具可见性限制的撤销函数(按模型能力同步)。 */
|
|
8
|
+
+ private readonly toolVisibility = new WeakMap<Agent, () => void>()
|
|
9
|
+
+
|
|
10
|
+
/**
|
|
11
|
+
* @param ctx - Host context carrying Agent, model, attachment, title, and Workspace services.
|
|
12
|
+
* @param agents - sole owner of create, resume, and Agent composition.
|
|
13
|
+
@@ -142,6 +145,31 @@
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
+ * 按当前模型的输入能力裁剪工具面。
|
|
18
|
+
+ *
|
|
19
|
+
+ * `read_image` 会把像素作为图像内容送进对话;纯文本模型即使被允许调用也消费不了,
|
|
20
|
+
+ * 而它只要出现在工具清单里,模型就会去试、试了必然失败。这里用
|
|
21
|
+
+ * `ctx.tools.restrict({ deny })` 把它从**可见集合**里摘掉——不是调用时报错。
|
|
22
|
+
+ *
|
|
23
|
+
+ * 只在 agent 作用域调用(全局 ctx 会屏蔽所有 agent);切换模型时先撤销旧限制。
|
|
24
|
+
+ *
|
|
25
|
+
+ * @param agent - 目标 agent(其 ctx 是作用域键)。
|
|
26
|
+
+ * @param selection - 已提交的模型选择。
|
|
27
|
+
+ */
|
|
28
|
+
+ private async syncToolVisibility(agent: Agent, selection: AgentModelSelection): Promise<void> {
|
|
29
|
+
+ const disposers = this.toolVisibility
|
|
30
|
+
+ disposers.get(agent)?.()
|
|
31
|
+
+ disposers.delete(agent)
|
|
32
|
+
+ try {
|
|
33
|
+
+ const info = await this.ctx.llm.resolveModelInfo(selection.provider, selection.model)
|
|
34
|
+
+ if (info.inputModalities?.includes('image') === true) return
|
|
35
|
+
+ disposers.set(agent, agent.ctx.tools.restrict({ deny: ['read_image'] }))
|
|
36
|
+
+ } catch {
|
|
37
|
+
+ // 模型信息取不到时保持默认(全部可见),不影响主流程。
|
|
38
|
+
+ }
|
|
39
|
+
+ }
|
|
40
|
+
+
|
|
41
|
+
+ /**
|
|
42
|
+
* Validate and record one Session model selection; save the default in the background.
|
|
43
|
+
* @param request - Session identity and requested model selection.
|
|
44
|
+
* @returns the normalized selection recorded for the Session, without waiting for default persistence.
|
|
45
|
+
@@ -160,6 +188,7 @@
|
|
46
|
+
}
|
|
47
|
+
await this.ctx.llm.resolveCallConfig(selected)
|
|
48
|
+
agent.model.select(selected)
|
|
49
|
+
+ void this.syncToolVisibility(agent, selected)
|
|
50
|
+
void this.ctx.agentDefaultModel.saveSelection(selected).catch((error: unknown) => {
|
|
51
|
+
this.ctx.logger.warn(
|
|
52
|
+
`session-controller: model selection changed for the Session but the default was not saved: ${String(error)}`,
|
|
53
|
+
@@ -312,20 +341,24 @@
|
|
54
|
+
const hasImage = admission.content.some(part => part.type === 'image')
|
|
55
|
+
const admit = async (): Promise<SessionPromptValue> => {
|
|
56
|
+
try {
|
|
57
|
+
+ let promptContent = admission.content
|
|
58
|
+
if (hasImage) {
|
|
59
|
+
const current = agent.model.current()
|
|
60
|
+
if (current !== undefined) {
|
|
61
|
+
const model = await this.ctx.llm.resolveModelInfo(current.provider, current.model)
|
|
62
|
+
if (model.inputModalities !== undefined && !model.inputModalities.includes('image')) {
|
|
63
|
+
- throw new RemoteError(
|
|
64
|
+
- 'session/attachment-invalid',
|
|
65
|
+
- `Model "${current.model}" does not support image input.`,
|
|
66
|
+
- { reason: 'MODEL_DOES_NOT_SUPPORT_IMAGES' },
|
|
67
|
+
- )
|
|
68
|
+
+ // 纯文本模型:不要把整条消息拒掉。图片块降级成一行文字占位,消息照常入队;
|
|
69
|
+
+ // 模型看不到像素,但至少用户能发出去,不会卡在输入框。
|
|
70
|
+
+ promptContent = admission.content.map(part => part.type === 'image'
|
|
71
|
+
+ ? {
|
|
72
|
+
+ type: 'text' as const,
|
|
73
|
+
+ text: '[图片附件已附加。当前模型不支持图像输入,无法查看图片内容;如需处理请改用文件/工具链路。]',
|
|
74
|
+
+ }
|
|
75
|
+
+ : part)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
- const content = await this.ctx.attachments.admitPromptContent(admission.content)
|
|
80
|
+
+ const content = await this.ctx.attachments.admitPromptContent(promptContent)
|
|
81
|
+
const message: UserMessage = createUserMessage({ content, source })
|
|
82
|
+
if (this.ctx.agents.get(agent.id) !== agent) {
|
|
83
|
+
throw new RemoteError(
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
diff --git a/packages/client/ui-schedule/src/client/TaskManagerPage.module.css b/packages/client/ui-schedule/src/client/TaskManagerPage.module.css
|
|
2
|
+
index 7c4acf5a3d..ea9d29e2e3 100644
|
|
3
|
+
--- a/packages/client/ui-schedule/src/client/TaskManagerPage.module.css
|
|
4
|
+
+++ b/packages/client/ui-schedule/src/client/TaskManagerPage.module.css
|
|
5
|
+
@@ -149,6 +149,12 @@
|
|
6
|
+
neutral hairline, the 10px radius, and the mock's `--muted` leading icon. The
|
|
7
|
+
mock brightens the border on hover and takes the brand stroke on focus
|
|
8
|
+
rather than drawing a ring around the control. */
|
|
9
|
+
+/* The runtime extension tab keeps the page's centered column, so a contributor
|
|
10
|
+
+ body lines up with the search field and the task rows. */
|
|
11
|
+
+.plazaBody {
|
|
12
|
+
+ min-width: 0;
|
|
13
|
+
+}
|
|
14
|
+
+
|
|
15
|
+
.searchTools {
|
|
16
|
+
--task-search-height: 36px;
|
|
17
|
+
display: flex;
|
|
18
|
+
diff --git a/packages/client/ui-schedule/src/client/TaskManagerPage.tsx b/packages/client/ui-schedule/src/client/TaskManagerPage.tsx
|
|
19
|
+
index 3c330c9f26..f7e7b78312 100644
|
|
20
|
+
--- a/packages/client/ui-schedule/src/client/TaskManagerPage.tsx
|
|
21
|
+
+++ b/packages/client/ui-schedule/src/client/TaskManagerPage.tsx
|
|
22
|
+
@@ -5,7 +5,7 @@ import {
|
|
23
|
+
Button, IconClockOutlineRegular, IconCloseOutlineRegular, IconEllipsisOutlineRegular, IconPlusOutlineRegular,
|
|
24
|
+
IconSearchOutlineRegular, IconTrashOutlineRegular, Input, Menu, Modal, Tooltip,
|
|
25
|
+
} from '@deepseek-ai/dsh-client-ui-primitives'
|
|
26
|
+
-import type { HostObservable, InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
|
|
27
|
+
+import type { HostObservable, InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
|
|
28
|
+
import type {} from '@deepseek-ai/dsh-client-ui-layout/client'
|
|
29
|
+
import type { ScheduleCatalogEntry, ScheduleId } from '@deepseek-ai/dsh-schedule/client'
|
|
30
|
+
import type { CatalogSnapshot } from './catalog-source.ts'
|
|
31
|
+
@@ -36,14 +36,26 @@ export interface TaskManagerInjected extends TaskDetailInjected {
|
|
32
|
+
* @returns resolution after the outcome is reported.
|
|
33
|
+
*/
|
|
34
|
+
readonly onClearEnded: () => Promise<void>
|
|
35
|
+
+ /**
|
|
36
|
+
+ * Whether a plugin currently contributes the page's runtime extension tab.
|
|
37
|
+
+ *
|
|
38
|
+
+ * The page reads this while rendering, so a contributor that registers after
|
|
39
|
+
+ * the page mounted still makes its tab appear on the next render; with no
|
|
40
|
+
+ * contributor the page keeps exactly its three status tabs.
|
|
41
|
+
+ * @returns true when the `schedule.manager.tabs` seat has an occupant.
|
|
42
|
+
+ */
|
|
43
|
+
+ readonly plazaAvailable?: () => boolean
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Root-scoped task catalog props derived from the framework and injected actions. */
|
|
47
|
+
export type TaskManagerPageProps = PropsRuntime<'main'>
|
|
48
|
+
& InjectFace<TaskManagerInjected>
|
|
49
|
+
& PropsLocale<'schedule.manager'>
|
|
50
|
+
+ // Narrowed to the one seat this page declares; optional so a unit test can
|
|
51
|
+
+ // render the page without a slot host, as every other page-level test does.
|
|
52
|
+
+ & Partial<PropsRenderSlots<'schedule.manager.tabs'>>
|
|
53
|
+
|
|
54
|
+
-type StatusFilter = 'all' | ScheduleCatalogEntry['status']
|
|
55
|
+
+type StatusFilter = 'all' | ScheduleCatalogEntry['status'] | 'plaza'
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Render retained tasks with authoritative deletion and timing-only edits.
|
|
59
|
+
@@ -51,7 +63,7 @@ type StatusFilter = 'all' | ScheduleCatalogEntry['status']
|
|
60
|
+
* @returns the searchable task list beside the selected task's detail.
|
|
61
|
+
*/
|
|
62
|
+
export function TaskManagerPage(props: TaskManagerPageProps) {
|
|
63
|
+
- const { useCatalog, onNewTask, onClearEnded, onRetry, t } = props
|
|
64
|
+
+ const { useCatalog, onNewTask, onClearEnded, onRetry, plazaAvailable, renderSlot, t } = props
|
|
65
|
+
const catalog = useCatalog(snapshot => snapshot)
|
|
66
|
+
const { records, status } = catalog
|
|
67
|
+
const [search, setSearch] = useState('')
|
|
68
|
+
@@ -85,7 +97,7 @@ export function TaskManagerPage(props: TaskManagerPageProps) {
|
|
69
|
+
const rows = useMemo(() => {
|
|
70
|
+
const query = search.trim().toLowerCase()
|
|
71
|
+
return records.filter(record => (
|
|
72
|
+
- (statusFilter === 'all' || record.status === statusFilter)
|
|
73
|
+
+ (statusFilter === 'all' || (statusFilter !== 'plaza' && record.status === statusFilter))
|
|
74
|
+
&& (record.prompt.toLowerCase().includes(query)
|
|
75
|
+
|| record.sessionId.toLowerCase().includes(query)
|
|
76
|
+
|| taskName(record).toLowerCase().includes(query))
|
|
77
|
+
@@ -202,8 +214,24 @@ export function TaskManagerPage(props: TaskManagerPageProps) {
|
|
78
|
+
{t(value === 'all' ? 'statusFilter.all' : `status.${value}`)}
|
|
79
|
+
</button>
|
|
80
|
+
))}
|
|
81
|
+
+ {plazaAvailable?.() === true && (
|
|
82
|
+
+ <button
|
|
83
|
+
+ type="button"
|
|
84
|
+
+ className={clsx(css.filterTab, statusFilter === 'plaza' && css.filterTabActive)}
|
|
85
|
+
+ aria-pressed={statusFilter === 'plaza'}
|
|
86
|
+
+ data-testid="task-manager-plaza-tab"
|
|
87
|
+
+ onClick={() => { setStatusFilter('plaza') }}
|
|
88
|
+
+ >
|
|
89
|
+
+ {t('statusFilter.plaza')}
|
|
90
|
+
+ </button>
|
|
91
|
+
+ )}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
+ {statusFilter === 'plaza' ? (
|
|
95
|
+
+ <div className={css.plazaBody} data-testid="task-manager-plaza-body">
|
|
96
|
+
+ {renderSlot?.('schedule.manager.tabs', {})}
|
|
97
|
+
+ </div>
|
|
98
|
+
+ ) : (<>
|
|
99
|
+
<div className={css.searchTools}>
|
|
100
|
+
<div className={css.searchField}>
|
|
101
|
+
<Input
|
|
102
|
+
@@ -299,6 +327,7 @@ export function TaskManagerPage(props: TaskManagerPageProps) {
|
|
103
|
+
})}
|
|
104
|
+
</ul>
|
|
105
|
+
</div>
|
|
106
|
+
+ </>)}
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
diff --git a/packages/client/ui-schedule/src/client/index.ts b/packages/client/ui-schedule/src/client/index.ts
|
|
111
|
+
index 7dcbc32ee3..cd072150e7 100644
|
|
112
|
+
--- a/packages/client/ui-schedule/src/client/index.ts
|
|
113
|
+
+++ b/packages/client/ui-schedule/src/client/index.ts
|
|
114
|
+
@@ -73,6 +73,21 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
115
|
+
/** Host task management page and task tab copy. */
|
|
116
|
+
'schedule.manager': TaskManagerKey
|
|
117
|
+
}
|
|
118
|
+
+ interface SlotMap {
|
|
119
|
+
+ /**
|
|
120
|
+
+ * One extension body contributed at runtime to the automation-task page.
|
|
121
|
+
+ *
|
|
122
|
+
+ * The page renders the single occupant as an additional status tab and
|
|
123
|
+
+ * supplies no owner props: a contributor owns its own data and needs no
|
|
124
|
+
+ * identity from the page. The seat belongs to no Session, so opening the
|
|
125
|
+
+ * page never mounts a contributor against an arbitrary conversation.
|
|
126
|
+
+ */
|
|
127
|
+
+ 'schedule.manager.tabs': {
|
|
128
|
+
+ kind: 'single'
|
|
129
|
+
+ scope: 'root'
|
|
130
|
+
+ owner: Record<string, never>
|
|
131
|
+
+ }
|
|
132
|
+
+ }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Required services for catalogs, ambient Session marks, the right Sidebar, Remote queries, original-Session navigation, and access. */
|
|
136
|
+
@@ -197,8 +212,13 @@ export function apply(ctx: ClientContext): void {
|
|
137
|
+
name: 'main',
|
|
138
|
+
key: PANEL_ID,
|
|
139
|
+
locale: MANAGER_NS,
|
|
140
|
+
+ // The automation page is the one first-level page that accepts a runtime
|
|
141
|
+
+ // extension tab. Declaring the seat here is what lets a plugin contribute
|
|
142
|
+
+ // a tab body without this package importing that plugin.
|
|
143
|
+
+ children: { 'schedule.manager.tabs': { kind: 'single', scope: 'root' } },
|
|
144
|
+
inject: (): TaskManagerInjected => ({
|
|
145
|
+
...detail,
|
|
146
|
+
+ plazaAvailable: () => ctx.slots.entriesOfSlot('schedule.manager.tabs').length > 0,
|
|
147
|
+
// The page has no creation form: a new reminder starts in a Session.
|
|
148
|
+
onNewTask: () => { ctx.uiWorkspace.startSession() },
|
|
149
|
+
onClearEnded: async () => {
|
|
150
|
+
diff --git a/packages/client/ui-schedule/src/client/task-manager-locales.ts b/packages/client/ui-schedule/src/client/task-manager-locales.ts
|
|
151
|
+
index fffde14568..145b05a825 100644
|
|
152
|
+
--- a/packages/client/ui-schedule/src/client/task-manager-locales.ts
|
|
153
|
+
+++ b/packages/client/ui-schedule/src/client/task-manager-locales.ts
|
|
154
|
+
@@ -20,6 +20,7 @@ export const en = {
|
|
155
|
+
'empty.action': 'New automation task',
|
|
156
|
+
'statusFilter.label': 'Task status',
|
|
157
|
+
'statusFilter.all': 'All',
|
|
158
|
+
+ 'statusFilter.plaza': 'Workflow plaza',
|
|
159
|
+
'status.active': 'Enabled',
|
|
160
|
+
'status.inactive': 'Inactive',
|
|
161
|
+
'detail.label': 'Task details',
|
|
162
|
+
@@ -176,6 +177,7 @@ export const zh: Record<TaskManagerKey, string> = {
|
|
163
|
+
'empty.action': '新建自动化任务',
|
|
164
|
+
'statusFilter.label': '任务状态',
|
|
165
|
+
'statusFilter.all': '全部',
|
|
166
|
+
+ 'statusFilter.plaza': '工作流广场',
|
|
167
|
+
'status.active': '已开启',
|
|
168
|
+
'status.inactive': '已结束',
|
|
169
|
+
'detail.label': '任务详情',
|
|
170
|
+
@@ -327,6 +329,7 @@ export const ja = {
|
|
171
|
+
'empty.action': '新規自動化タスク',
|
|
172
|
+
'statusFilter.label': 'タスクの状態',
|
|
173
|
+
'statusFilter.all': 'すべて',
|
|
174
|
+
+ 'statusFilter.plaza': 'ワークフロープラザ',
|
|
175
|
+
'status.active': '有効',
|
|
176
|
+
'status.inactive': '無効',
|
|
177
|
+
'detail.label': 'タスクの詳細',
|
|
178
|
+
@@ -476,6 +479,7 @@ export const es = {
|
|
179
|
+
'empty.action': 'Nueva tarea de automatización',
|
|
180
|
+
'statusFilter.label': 'Estado de la tarea',
|
|
181
|
+
'statusFilter.all': 'Todos',
|
|
182
|
+
+ 'statusFilter.plaza': 'Plaza de flujos',
|
|
183
|
+
'status.active': 'Habilitado',
|
|
184
|
+
'status.inactive': 'Inactivo',
|
|
185
|
+
'detail.label': 'Detalles de la tarea',
|
|
186
|
+
@@ -628,6 +632,7 @@ export const fr = {
|
|
187
|
+
'empty.action': "Nouvelle tâche d'automatisation",
|
|
188
|
+
'statusFilter.label': 'Statut de la tâche',
|
|
189
|
+
'statusFilter.all': 'Tout',
|
|
190
|
+
+ 'statusFilter.plaza': 'Place des workflows',
|
|
191
|
+
'status.active': 'Activé',
|
|
192
|
+
'status.inactive': 'Inactif',
|
|
193
|
+
'detail.label': 'Détails de la tâche',
|
|
194
|
+
@@ -780,6 +785,7 @@ export const de = {
|
|
195
|
+
'empty.action': 'Neue Automatisierungsaufgabe',
|
|
196
|
+
'statusFilter.label': 'Aufgabenstatus',
|
|
197
|
+
'statusFilter.all': 'Alle',
|
|
198
|
+
+ 'statusFilter.plaza': 'Workflow-Plaza',
|
|
199
|
+
'status.active': 'Aktiviert',
|
|
200
|
+
'status.inactive': 'Inaktiv',
|
|
201
|
+
'detail.label': 'Aufgabendetails',
|
|
202
|
+
@@ -932,6 +938,7 @@ export const ru = {
|
|
203
|
+
'empty.action': 'Новая задача автоматизации',
|
|
204
|
+
'statusFilter.label': 'Статус задачи',
|
|
205
|
+
'statusFilter.all': 'Все',
|
|
206
|
+
+ 'statusFilter.plaza': 'Витрина сценариев',
|
|
207
|
+
'status.active': 'Включено',
|
|
208
|
+
'status.inactive': 'Неактивный',
|
|
209
|
+
'detail.label': 'Подробности задачи',
|
|
210
|
+
@@ -1084,6 +1091,7 @@ export const pt = {
|
|
211
|
+
'empty.action': 'Nova tarefa de automação',
|
|
212
|
+
'statusFilter.label': 'Status da tarefa',
|
|
213
|
+
'statusFilter.all': 'Todos',
|
|
214
|
+
+ 'statusFilter.plaza': 'Praça de fluxos',
|
|
215
|
+
'status.active': 'Habilitado',
|
|
216
|
+
'status.inactive': 'Inativo',
|
|
217
|
+
'detail.label': 'Detalhes da tarefa',
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
diff --git a/packages/client/ui-sidebar-right/src/client/index.ts b/packages/client/ui-sidebar-right/src/client/index.ts
|
|
2
|
+
index 99b800b6c8..9b317464e1 100644
|
|
3
|
+
--- a/packages/client/ui-sidebar-right/src/client/index.ts
|
|
4
|
+
+++ b/packages/client/ui-sidebar-right/src/client/index.ts
|
|
5
|
+
@@ -138,7 +138,10 @@ export function apply(ctx: ClientContext): void {
|
|
6
|
+
ctx.effect(() => {
|
|
7
|
+
const sync = (): void => {
|
|
8
|
+
const selected = views.source.getSnapshot().find(view => view.selected)
|
|
9
|
+
- show(layout.panelInfo.getSnapshot().activePanelId === null ? selected?.sessionId : undefined)
|
|
10
|
+
+ // The right column stays addressable from a global main panel; the layout
|
|
11
|
+
+ // still decides the track's width, so a session tab is named whenever a
|
|
12
|
+
+ // Session is selected rather than only while the Conversation is focused.
|
|
13
|
+
+ show(selected?.sessionId)
|
|
14
|
+
}
|
|
15
|
+
const unsubscribeViews = views.source.subscribe(sync)
|
|
16
|
+
const unsubscribePanel = layout.panelInfo.subscribe(sync)
|
|
17
|
+
diff --git a/packages/client/ui-sidebar-right/src/client/shell/RightbarRoot.tsx b/packages/client/ui-sidebar-right/src/client/shell/RightbarRoot.tsx
|
|
18
|
+
index 26bedb1d18..bebc73706d 100644
|
|
19
|
+
--- a/packages/client/ui-sidebar-right/src/client/shell/RightbarRoot.tsx
|
|
20
|
+
+++ b/packages/client/ui-sidebar-right/src/client/shell/RightbarRoot.tsx
|
|
21
|
+
@@ -31,8 +31,12 @@ function SessionView({ view, visible, SessionProvider, renderSlot, mountView, wi
|
|
22
|
+
* @param props - frame geometry, view targets and the authorized Session renderer.
|
|
23
|
+
* @returns the foreground and retained background Sidebars.
|
|
24
|
+
*/
|
|
25
|
+
-export function RightbarRoot({ usePanelInfo, useViews, ...props }: RootProps) {
|
|
26
|
+
- const visible = usePanelInfo(info => info.activePanelId === null)
|
|
27
|
+
+export function RightbarRoot({ useViews, ...props }: RootProps) {
|
|
28
|
+
+ // A global main panel (the knowledge base) keeps the right column usable: the
|
|
29
|
+
+ // layout already owns whether the track takes width, so gating the Session
|
|
30
|
+
+ // content on `activePanelId === null` only made the column render empty there.
|
|
31
|
+
+ // Retained views still hide themselves through `view.selected`, so conversation
|
|
32
|
+
+ // behaviour is unchanged.
|
|
33
|
+
const views = useViews(value => value)
|
|
34
|
+
- return <>{views.map(view => <SessionView key={view.sessionId} {...props} view={view} visible={visible} />)}</>
|
|
35
|
+
+ return <>{views.map(view => <SessionView key={view.sessionId} {...props} view={view} visible />)}</>
|
|
36
|
+
}
|