@gehennawu/dsh-service 0.31.0 → 0.31.1
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/client.js +161 -10
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -226,6 +226,7 @@ window.__ModuleLoader__.load({
|
|
|
226
226
|
'tabs.restart': '重启',
|
|
227
227
|
'tabs.alert.title': '服务控制提醒',
|
|
228
228
|
'tabs.alert.body': '以下功能需要处理:{tabs}',
|
|
229
|
+
'tabs.alert.dot': '此标签存在故障提醒',
|
|
229
230
|
'permissions.title': '文件权限',
|
|
230
231
|
'permissions.description': '检查 Agent 是否能读取、写入并进入 DSH_HOME 和工作区。深检跳过 .git 内部文件;修复只补充当前用户所需权限并保留执行位,DSH 凭据文件固定为 600。',
|
|
231
232
|
'permissions.target': '目标属主:{owner}',
|
|
@@ -727,6 +728,7 @@ window.__ModuleLoader__.load({
|
|
|
727
728
|
'tabs.restart': 'Restart',
|
|
728
729
|
'tabs.alert.title': 'Service control alert',
|
|
729
730
|
'tabs.alert.body': 'These areas need attention: {tabs}',
|
|
731
|
+
'tabs.alert.dot': 'Alert on this tab',
|
|
730
732
|
'permissions.title': 'File permissions',
|
|
731
733
|
'permissions.description': 'Checks whether the Agent can read, write, and enter DSH_HOME and workspaces. Deep scans skip internal .git files; repair only adds permissions needed by the current user while preserving execute bits, and keeps the DSH credential file at 600.',
|
|
732
734
|
'permissions.target': 'Target owner: {owner}',
|
|
@@ -1020,14 +1022,57 @@ window.__ModuleLoader__.load({
|
|
|
1020
1022
|
const NAV_ICON_SVG_OPEN = '%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2724%27 height=%2724%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27black%27 stroke-width=%272%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E'
|
|
1021
1023
|
const NAV_ICON_SVG_CLOSE = '%3C/svg%3E'
|
|
1022
1024
|
const navIconMask = (body) => '-webkit-mask:url("data:image/svg+xml,' + NAV_ICON_SVG_OPEN + body + NAV_ICON_SVG_CLOSE + '") center/contain no-repeat;mask:url("data:image/svg+xml,' + NAV_ICON_SVG_OPEN + body + NAV_ICON_SVG_CLOSE + '") center/contain no-repeat'
|
|
1023
|
-
//
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
const
|
|
1025
|
+
// 线性图标单一事实源(v0.31 用户点名:顶部标签胶囊复用既有 SVG):每枚 = [tag, attrs]
|
|
1026
|
+
// 元素清单,两处消费——① 顶栏胶囊内联 React SVG;② 左列导航 mask 的 data URI 序列化。
|
|
1027
|
+
// 换图标只改这一处,两处永远同步。风格统一 lucide:24 viewBox、stroke 2、圆角线帽。
|
|
1028
|
+
const SVG_ICONS = {
|
|
1029
|
+
// 服务控制(左列 mask 专用)= 滑杆组
|
|
1030
|
+
service: [['path', { d: 'M4 8h16' }], ['path', { d: 'M4 16h16' }], ['circle', { cx: '9', cy: '8', r: '2.5', fill: 'black' }], ['circle', { cx: '15', cy: '16', r: '2.5', fill: 'black' }]],
|
|
1031
|
+
// 概览 = 仪表盘四宫格
|
|
1032
|
+
overview: [['rect', { x: '3', y: '3', width: '7', height: '9', rx: '1' }], ['rect', { x: '14', y: '3', width: '7', height: '5', rx: '1' }], ['rect', { x: '14', y: '12', width: '7', height: '9', rx: '1' }], ['rect', { x: '3', y: '16', width: '7', height: '5', rx: '1' }]],
|
|
1033
|
+
// 通知 = 铃铛(取 BellIcon 铃体三笔,不带对钩/斜线变体)
|
|
1034
|
+
notify: [['path', { d: 'M10.268 21a2 2 0 0 0 3.464 0' }], ['path', { d: 'M16.8607 4.4824A6 6 0 0 0 6 8C6 12.499 4.589 13.956 3.262 15.326' }], ['path', { d: 'M3.262 15.326A1 1 0 0 0 4 17H20A1 1 0 0 0 20.74 15.327C20.209 14.779 19.665 14.218 19.203 13.454' }]],
|
|
1035
|
+
// 健康诊断 = 盾牌 + 对钩
|
|
1036
|
+
health: [['path', { d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z' }], ['path', { d: 'm9 12 2 2 4-4' }]],
|
|
1037
|
+
// 模型统计 = 坐标轴 + 三根柱
|
|
1038
|
+
usage: [['path', { d: 'M3 3v16a2 2 0 0 0 2 2h16' }], ['path', { d: 'M18 17V9' }], ['path', { d: 'M13 17V5' }], ['path', { d: 'M8 17v-3' }]],
|
|
1039
|
+
// 额度查询 = 仪表弧 + 指针
|
|
1040
|
+
quota: [['path', { d: 'm12 14 4-4' }], ['path', { d: 'M3.34 19a10 10 0 1 1 17.32 0' }]],
|
|
1041
|
+
// 备份维护 = 归档箱
|
|
1042
|
+
backup: [['rect', { x: '2', y: '3', width: '20', height: '5', rx: '1' }], ['path', { d: 'M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8' }], ['path', { d: 'M10 12h4' }]],
|
|
1043
|
+
// 技能 = 书本轮廓
|
|
1044
|
+
skills: [['path', { d: 'M4 19.5A2.5 2.5 0 0 1 6.5 17H20' }], ['path', { d: 'M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z' }]],
|
|
1045
|
+
// 子代理 = 机器人头
|
|
1046
|
+
subagent: [['path', { d: 'M12 8V4H8' }], ['rect', { width: '16', height: '12', x: '4', y: '8', rx: '2' }], ['path', { d: 'M2 14h2' }], ['path', { d: 'M20 14h2' }], ['path', { d: 'M15 13v2' }], ['path', { d: 'M9 13v2' }]],
|
|
1047
|
+
// 重启 = 电源符号
|
|
1048
|
+
restart: [['path', { d: 'M12 2v10' }], ['path', { d: 'M18.4 6.6a9 9 0 1 1-12.77.04' }]],
|
|
1049
|
+
}
|
|
1050
|
+
// 左列 mask 的 data URI 体序列化:`<tag attr='val'/>` → %3Ctag%20attr=%27val%27/%3E。
|
|
1051
|
+
// 输出 byte 级等于历史上手写的常量(属性分隔用原始空格),外观零漂移。
|
|
1052
|
+
const iconMaskBody = (icon) => icon.map(([tag, attrs]) =>
|
|
1053
|
+
'%3C' + tag + Object.entries(attrs).map(([k, v]) => ` ${k}=%27${v}%27`).join('') + '/%3E').join('')
|
|
1054
|
+
const NAV_ICON_BODY_SERVICE = iconMaskBody(SVG_ICONS.service)
|
|
1055
|
+
const NAV_ICON_BODY_QUOTA = iconMaskBody(SVG_ICONS.quota)
|
|
1056
|
+
const NAV_ICON_BODY_RESTART = iconMaskBody(SVG_ICONS.restart)
|
|
1027
1057
|
// 技能 = 书本轮廓(lucide book 风格,16px 下可读)
|
|
1028
|
-
const NAV_ICON_BODY_SKILLS =
|
|
1058
|
+
const NAV_ICON_BODY_SKILLS = iconMaskBody(SVG_ICONS.skills)
|
|
1029
1059
|
// 子代理 = 机器人头(lucide bot 风格,16px 下可读)
|
|
1030
|
-
const NAV_ICON_BODY_SUBAGENT =
|
|
1060
|
+
const NAV_ICON_BODY_SUBAGENT = iconMaskBody(SVG_ICONS.subagent)
|
|
1061
|
+
/** 顶栏胶囊的内联 SVG 图标:跟随 currentColor,尺寸 13px,随文字基线居中。 */
|
|
1062
|
+
function TabIcon({ name }) {
|
|
1063
|
+
const elements = SVG_ICONS[name]
|
|
1064
|
+
if (elements === undefined) return null
|
|
1065
|
+
return React.createElement('svg', {
|
|
1066
|
+
viewBox: '0 0 24 24', width: 13, height: 13, fill: 'none', stroke: 'currentColor',
|
|
1067
|
+
strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': 'true',
|
|
1068
|
+
style: { flexShrink: 0, display: 'block' },
|
|
1069
|
+
}, elements.map(([tag, attrs], index) => React.createElement(tag, Object.assign({ key: index }, attrs))))
|
|
1070
|
+
}
|
|
1071
|
+
// v0.34 顶栏分段条激活段实底色。v0.34.2 用户复核定稿——**按主题分流**:
|
|
1072
|
+
// 浅色主题 = 品牌原色实底 + 白字(黑/深底白字,用户点名);暗色主题 = 提亮品牌色块
|
|
1073
|
+
// 激活块底色与文字色均由插件样式表的双主题变量决定(写死中性固定色,见 v0.34.2 注释):
|
|
1074
|
+
// 组件只引用变量,React 内联样式无需感知当前主题。不支持变量的极老内核回退到浅色深块白字。
|
|
1075
|
+
const CHIP_ACTIVE_TEXT = 'var(--dsh-svc-tab-active-text)'
|
|
1031
1076
|
|
|
1032
1077
|
function markSettingsNavRows(rows) {
|
|
1033
1078
|
if (typeof document === 'undefined' || !document.body) return () => {}
|
|
@@ -1083,6 +1128,10 @@ window.__ModuleLoader__.load({
|
|
|
1083
1128
|
svcStyle = document.createElement('style')
|
|
1084
1129
|
svcStyle.textContent = [
|
|
1085
1130
|
':root{--dsh-svc-surface-bg:#f3f4f6}body[data-ds-dark-theme]{--dsh-svc-surface-bg:#1e1e20}',
|
|
1131
|
+
// 顶栏分段条激活块双主题配色:浅色=深色实底块#16181d+白字,暗色=近白实底块#eef0f4+黑字。
|
|
1132
|
+
// 不用 --dsw-alias-* 令牌(实测其明暗方向与本预期相反,浅色呈白块、深色呈黑块),写死中性固定色。
|
|
1133
|
+
':root{--dsh-svc-tab-active-bg:#16181d;--dsh-svc-tab-active-danger:#16181d;--dsh-svc-tab-active-text:#ffffff}',
|
|
1134
|
+
'body[data-ds-dark-theme]{--dsh-svc-tab-active-bg:#eef0f4;--dsh-svc-tab-active-danger:#eef0f4;--dsh-svc-tab-active-text:#111318}',
|
|
1086
1135
|
// 设置页导航行图标:外壳按 id 硬编码(第三方一律兜底齿轮)且协议无 icon 字段,
|
|
1087
1136
|
// 由 markSettingsNavRows 打的 data 标记接住——藏齿轮 SVG、mask SVG 画各自图标,
|
|
1088
1137
|
// currentColor 跟随主题文字色(hover/active 高亮自动继承)。
|
|
@@ -1093,6 +1142,26 @@ window.__ModuleLoader__.load({
|
|
|
1093
1142
|
'[data-dsh-service-skills-nav]::before{' + navIconMask(NAV_ICON_BODY_SKILLS) + '}',
|
|
1094
1143
|
'[data-dsh-service-subagent-nav]::before{' + navIconMask(NAV_ICON_BODY_SUBAGENT) + '}',
|
|
1095
1144
|
'[data-dsh-service-restart-nav]::before{' + navIconMask(NAV_ICON_BODY_RESTART) + '}',
|
|
1145
|
+
// ── 窄面板下的顶栏标签(用户反馈:移动端「太乱、容易误触」)──────────
|
|
1146
|
+
// 作用域是纯媒体查询 ≤640px,**不**挂在 data-dshsvc-mobile 下——这是本插件
|
|
1147
|
+
// 自己的面板 UI,360px 手机上无论移动适配功能开没开都挤成数行碎胶囊。
|
|
1148
|
+
// 方案:每个分组托盘整行横滑(不换行、藏滚动条),触达目标放大到 ≥36px;
|
|
1149
|
+
// 重启胶囊独占第二行整宽居中——危险动作与普通标签物理分离,杜绝误触。
|
|
1150
|
+
// 胶囊 padding/fontSize 是内联样式,覆盖必须 !important。
|
|
1151
|
+
'@media (max-width:640px){',
|
|
1152
|
+
/* 保持桌面语义:重启始终钉在首行右缘(marginLeft:auto 内联样式生效的前提
|
|
1153
|
+
是它和托盘同行)。窄屏不再让托盘抢整行把重启挤去换行居中(用户复核:
|
|
1154
|
+
悬在两行中间很离谱),而是托盘收缩可横滑、重启贴右不换行。 */
|
|
1155
|
+
'[data-testid="tab-list"]{gap:10px}',
|
|
1156
|
+
'[data-testid="tab-list"]>div{flex-wrap:nowrap !important;align-items:center}',
|
|
1157
|
+
'[data-testid="tab-list"] [data-testid$="-tray"]{flex:0 1 auto;min-width:0;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding:3px}',
|
|
1158
|
+
'[data-testid="tab-list"] [data-testid$="-tray"]::-webkit-scrollbar{display:none}',
|
|
1159
|
+
'[data-testid="tab-list"] [data-testid^="top-tab-"]{padding:9px 13px !important;min-height:36px;box-sizing:border-box;font-size:13px !important;white-space:nowrap;flex:none}',
|
|
1160
|
+
'[data-testid="tab-list"] [data-testid^="top-tab-"] svg{flex:none}',
|
|
1161
|
+
/* 重启胶囊:刚性尺寸——窄屏挤压下 flex 子项会被压宽拉高成瘦椭圆
|
|
1162
|
+
(真机复核),钉死高度/圆角/内边距/不缩不放。 */
|
|
1163
|
+
'[data-testid="top-tab-restart"]{flex:none !important;width:max-content;height:40px;min-height:40px;max-height:40px;padding:0 16px !important;border-radius:999px !important}',
|
|
1164
|
+
'}',
|
|
1096
1165
|
].join('')
|
|
1097
1166
|
document.head.appendChild(svcStyle)
|
|
1098
1167
|
}
|
|
@@ -4359,9 +4428,8 @@ window.__ModuleLoader__.load({
|
|
|
4359
4428
|
const maintenanceBlock = React.createElement('div', { key: 'maintenance-card', 'data-testid': 'maintenance-card', style: card }, backupBlock)
|
|
4360
4429
|
// advisory 警告(如手动启动环境的黄色提示)只做行内呈现,不点亮标签 ⚠ 与顶部服务控制提醒。
|
|
4361
4430
|
const diagnosticFailure = diagnostics?.checks?.some((check) => check.status === 'error' || (check.status === 'warning' && check.advisory !== true)) === true
|
|
4362
|
-
//
|
|
4431
|
+
// 批量进行中在「技能」标签胶囊右上角显示进度计数角标(done/total)。
|
|
4363
4432
|
const { batch: skillsBadgeBatch } = useSkillsBatch()
|
|
4364
|
-
const skillsBadge = skillsBadgeBatch !== null && skillsBadgeBatch.phase === 'running' ? ' ⟳' + skillsBadgeBatch.done + '/' + skillsBadgeBatch.total : ''
|
|
4365
4433
|
const tabWarnings = {
|
|
4366
4434
|
overview: false,
|
|
4367
4435
|
notify: false,
|
|
@@ -4404,8 +4472,91 @@ window.__ModuleLoader__.load({
|
|
|
4404
4472
|
warningTabs.length > 0 ? React.createElement('div', { style: { marginBottom: '12px', padding: '11px 13px', borderRadius: '8px', background: 'rgba(198,128,0,0.16)', border: '1px solid rgba(198,128,0,0.48)', boxShadow: '0 2px 8px rgba(0,0,0,0.08)' } },
|
|
4405
4473
|
React.createElement('div', { style: { fontSize: '13px', fontWeight: 700 } }, translate('tabs.alert.title')),
|
|
4406
4474
|
React.createElement('div', { style: Object.assign({}, hint, { marginTop: '3px' }) }, translate('tabs.alert.body', { tabs: warningTabs.join('、') }))) : null,
|
|
4407
|
-
React.createElement('div', { 'data-testid': 'tab-list', style: { display: 'flex',
|
|
4408
|
-
|
|
4475
|
+
React.createElement('div', { 'data-testid': 'tab-list', style: { display: 'flex', flexDirection: 'column', gap: '6px', alignItems: 'flex-start' } },
|
|
4476
|
+
(() => {
|
|
4477
|
+
// v0.31 用户点名(终版):顶栏标签 = 两行分组的紧凑胶囊条。胶囊「图标+文字」,
|
|
4478
|
+
// 激活态用品牌色淡染底 + 品牌色文字(不用实底白字——品牌色在深色主题里偏亮,
|
|
4479
|
+
// 白底白字会直接不可读),重启激活态同理用危险色淡染;未激活重启保持危险色
|
|
4480
|
+
// 描边呼应安全教义。组序(用户点名):「状态与数据」概览→健康诊断→模型统计→
|
|
4481
|
+
// 额度查询→通知;「技能与维护」子代理→技能管理→备份维护→红描边重启殿后。
|
|
4482
|
+
// 组内功能开关全关时该标签消失,整行全空才不渲染该行。
|
|
4483
|
+
// 故障 ⚠ 从文字前缀改为角落橙点,技能批量计数是右上小徽标。
|
|
4484
|
+
// v0.33 用户参考图终版:每行是**一条连续圆角分段条**——段无各自边框、段间细竖线。
|
|
4485
|
+
// v0.34:激活段区分度加强——品牌色实底 + 白字(实底取「深色上也够暗」的品牌原色,
|
|
4486
|
+
// 不再受主题明度翻转影响;v0.32 的白底白字 BUG 是错把亮色主题交互底当背景所致,
|
|
4487
|
+
// 与本处的区别见 TODO);重启移出托盘、独立红胶囊钉在标签区最右(margin-left:auto)。
|
|
4488
|
+
const buildTabChip = ([id, label]) => {
|
|
4489
|
+
const isActive = visibleActiveTab === id
|
|
4490
|
+
const isRestart = id === 'restart'
|
|
4491
|
+
let chipStyle = Object.assign(
|
|
4492
|
+
{
|
|
4493
|
+
position: 'relative', display: 'inline-flex', alignItems: 'center', gap: '5px',
|
|
4494
|
+
padding: '4px 9px', margin: 0, border: 0, borderRadius: 0,
|
|
4495
|
+
background: 'transparent',
|
|
4496
|
+
color: tabWarnings[id] && !isActive ? 'var(--dsw-alias-state-warn-primary)' : 'var(--dsw-alias-label-secondary)',
|
|
4497
|
+
fontSize: '12.5px', fontWeight: 550, lineHeight: '16px', cursor: 'pointer',
|
|
4498
|
+
transition: 'color 120ms, background 120ms',
|
|
4499
|
+
},
|
|
4500
|
+
)
|
|
4501
|
+
if (isActive) {
|
|
4502
|
+
chipStyle.background = isRestart ? 'var(--dsh-svc-tab-active-danger)' : 'var(--dsh-svc-tab-active-bg)'
|
|
4503
|
+
chipStyle.color = CHIP_ACTIVE_TEXT
|
|
4504
|
+
chipStyle.fontWeight = 650
|
|
4505
|
+
chipStyle.borderRadius = '8px'
|
|
4506
|
+
}
|
|
4507
|
+
return React.createElement('button', { key: id, 'data-testid': 'top-tab-' + id, style: chipStyle, onClick: () => { setActiveTab(id); if (id === 'health') runDiagnostics(false) } },
|
|
4508
|
+
React.createElement(TabIcon, { name: id }),
|
|
4509
|
+
translate(label),
|
|
4510
|
+
tabWarnings[id] ? React.createElement('span', { 'data-testid': 'tab-dot-' + id, 'aria-label': translate('tabs.alert.dot'), style: { position: 'absolute', top: '-3px', right: '-3px', width: '8px', height: '8px', borderRadius: '50%', background: 'var(--dsw-alias-state-warn-primary)', boxShadow: '0 0 0 2px var(--dsw-alias-bg-layer-1)' } }) : null,
|
|
4511
|
+
id === 'skills' && skillsBadgeBatch !== null && skillsBadgeBatch.phase === 'running' ? React.createElement('span', { 'data-testid': 'skills-tab-badge', style: { position: 'absolute', top: '-7px', right: '-10px', fontSize: '9px', lineHeight: '14px', padding: '0 4px', borderRadius: '999px', background: 'var(--dsw-alias-state-warn-primary)', color: '#fff', fontWeight: 700 } }, skillsBadgeBatch.done + '/' + skillsBadgeBatch.total) : null)
|
|
4512
|
+
}
|
|
4513
|
+
const groupDefs = [
|
|
4514
|
+
['tabs.group.data', ['overview', 'health', 'usage', 'quota', 'notify']],
|
|
4515
|
+
['tabs.group.maint', ['subagent', 'skills', 'backup']],
|
|
4516
|
+
]
|
|
4517
|
+
const rows = []
|
|
4518
|
+
let restartEntry = null
|
|
4519
|
+
for (const [groupKey, ids] of groupDefs) {
|
|
4520
|
+
// 行内顺序跟随 groupDefs 里点名的 id 序(用户点名组序),不是 tabs 源序——
|
|
4521
|
+
// filter 保源序会把「通知」排回第一行第二位,这里按 ids 顺序映射重排。
|
|
4522
|
+
const orderIndex = new Map(ids.map((id, index) => [id, index]))
|
|
4523
|
+
const items = tabs.filter(([id]) => orderIndex.has(id))
|
|
4524
|
+
.sort((a, b) => orderIndex.get(a[0]) - orderIndex.get(b[0]))
|
|
4525
|
+
if (items.length > 0) rows.push({ items, testid: 'tab-group-' + groupKey.split('.').pop() })
|
|
4526
|
+
}
|
|
4527
|
+
// v0.34:重启不再挤在段列表里,单独拎出(托盘外独立红胶囊)。
|
|
4528
|
+
restartEntry = tabs.find(([id]) => id === 'restart') ?? null
|
|
4529
|
+
// 重启永远可见:可选功能全关到没有任何分组行时自成一行(仍钉最右)。
|
|
4530
|
+
const trayChip = (item, index, list) => {
|
|
4531
|
+
const nodes = []
|
|
4532
|
+
if (index > 0) {
|
|
4533
|
+
nodes.push(React.createElement('span', { key: 'sep-' + item[0], 'aria-hidden': 'true', style: { width: '1px', height: '14px', background: 'var(--dsw-alias-border-l1)', flexShrink: 0 } }))
|
|
4534
|
+
}
|
|
4535
|
+
nodes.push(buildTabChip(item))
|
|
4536
|
+
return nodes
|
|
4537
|
+
}
|
|
4538
|
+
// v0.34.1:重启胶囊要贴**容器右缘**(不是分段条末尾)。行改成占满宽度的
|
|
4539
|
+
// flex:托盘 inline-flex 收缩在左,重启钮 marginLeft:auto 钉到该行最右;
|
|
4540
|
+
// 托盘自身换行(窄面板)也不影响钮的贴边。挂在首行(右缘视线最好),
|
|
4541
|
+
// 其余行不再重复渲染。
|
|
4542
|
+
return rows.map((row, rowIndex) => React.createElement('div', { key: row.testid, 'data-testid': row.testid, style: { display: 'flex', minWidth: 0, width: '100%' } },
|
|
4543
|
+
React.createElement('div', {
|
|
4544
|
+
'data-testid': row.testid + '-tray',
|
|
4545
|
+
style: { display: 'inline-flex', flexWrap: 'wrap', alignItems: 'center', minWidth: 0, border: '0.5px solid var(--dsw-alias-border-l2)', borderRadius: '12px', overflow: 'hidden' },
|
|
4546
|
+
}, row.items.flatMap(trayChip)),
|
|
4547
|
+
rowIndex === 0 && restartEntry !== null
|
|
4548
|
+
? (() => {
|
|
4549
|
+
const button = buildTabChip(restartEntry)
|
|
4550
|
+
return React.createElement('button', Object.assign({}, button.props, {
|
|
4551
|
+
style: Object.assign({}, button.props.style, {
|
|
4552
|
+
marginLeft: 'auto', border: '0.5px solid var(--dsw-alias-state-error-primary)',
|
|
4553
|
+
borderRadius: '999px', padding: '4px 12px',
|
|
4554
|
+
background: visibleActiveTab === 'restart' ? 'var(--dsh-svc-tab-active-danger)' : 'transparent',
|
|
4555
|
+
}),
|
|
4556
|
+
}), ...(button.children ?? []))
|
|
4557
|
+
})()
|
|
4558
|
+
: null))
|
|
4559
|
+
})()),
|
|
4409
4560
|
React.createElement('div', { 'data-testid': 'tab-panel', style: tabPanel }, tabContent))
|
|
4410
4561
|
}
|
|
4411
4562
|
|