fix: 工作台状态持久化(视图覆盖写回views[id],布局条目照旧) + feat: tsx/css等代码文件点击预览
This commit is contained in:
@@ -380,10 +380,16 @@ function WorktableSection(props: any) {
|
||||
setActiveSplitId(splitStore.active && splitStore.spec ? splitStore.spec.id : null)
|
||||
}), [])
|
||||
|
||||
// 引擎内 spec 变更(窗内容/聊天位置/窗位互换)→ 回写布局条目持久化
|
||||
// 引擎内 spec 变更(窗内容/聊天位置/窗位互换)→ 回写持久化:
|
||||
// 布局项目写 layouts 条目;入驻项目(视图覆盖工作区)写 views[id]。每个项目都保持上一次的样子。
|
||||
useEffect(() => {
|
||||
splitStore.onSpecMutated = (spec) => {
|
||||
persistProjects((prev) => ({ ...prev, layouts: prev.layouts.map((l) => (l.id === spec.id ? spec : l)) }))
|
||||
persistProjects((prev) => {
|
||||
if (prev.layouts.some((l) => l.id === spec.id)) {
|
||||
return { ...prev, layouts: prev.layouts.map((l) => (l.id === spec.id ? spec : l)) }
|
||||
}
|
||||
return { ...prev, views: { ...prev.views, [spec.id]: spec } }
|
||||
})
|
||||
}
|
||||
return () => { splitStore.onSpecMutated = null }
|
||||
}, [])
|
||||
|
||||
@@ -937,7 +937,7 @@ function ExplorerPane(props: { row: PaneRow; index: number }) {
|
||||
url: '/api/worktable/site/' + encodeURIComponent(dir) + '/' + encodeURIComponent(e.name),
|
||||
title: e.name,
|
||||
})
|
||||
} else if (/\.(md|markdown|mdown|txt|log|pdf|png|jpe?g|gif|webp|svg|bmp|ico)$/i.test(e.name)) {
|
||||
} else if (/\.(md|markdown|mdown|txt|log|tsx|ts|jsx|js|css|json|pdf|png|jpe?g|gif|webp|svg|bmp|ico)$/i.test(e.name)) {
|
||||
splitStore.openTab(props.row, props.index, { kind: 'file', path: e.path })
|
||||
} else {
|
||||
setError(T('pane.openLater'))
|
||||
|
||||
@@ -639,14 +639,17 @@
|
||||
原生视图内部是浏览器扩展页,插件注入不了按钮、拦不到鼠标,也驱动不了内部滚动——
|
||||
向用户如实说明后按指示回退);② 视图选项改名「设置」,点开直接内嵌「排序方式 + 管理项目
|
||||
展开列表」,不再二次点击;③ 管理项目里给现有项目加「变更视图」:换预设拓扑,
|
||||
## 补记(卡片选中态统一判定)
|
||||
## 补记(工作台状态持久化修复 + tsx/css 代码预览)
|
||||
|
||||
- 用户反馈:旅行 Atlas 卡片选中后没有高亮边(其他 3 个项目都有);新建项目也要有。
|
||||
- 根因:ta_card 的 data-on 由它自己插件控制(自有引擎状态);用视图覆盖走工作台引擎打开时
|
||||
两边状态对不上 → 不高亮。
|
||||
- 处理:DOM 桥 sync 里选中态统一由工作台判定——activeSplitId===id → data-on=true;
|
||||
引擎开着别的 → false;引擎空闲(activeSplitId=null)→ 不动(保留卡片自带状态,
|
||||
兼容自带分栏插件的打开态)。通用规则覆盖所有注册项目与新建项目。
|
||||
- 验证(functional-diag STEP13):布局打开时 ta/pr 卡 false;旅行设置视图覆盖后点卡片 →
|
||||
engineSpecId=travelatlas 且 taOnAfterOpen=true;全 STEP 回归 ERROR_COUNT: 0。
|
||||
- 用户反馈:① 项目里布置好的窗口内容(如上面浏览器/下面终端)切换项目再切回就变回默认,
|
||||
每个项目的工作台应保持上一次的样子;② 资源管理器要能点开 tsx/css 文件预览(同 MD)。
|
||||
- 根因:onSpecMutated 回写只写 layouts 条目,漏了 views(视图覆盖工作区)→ 常驻项目
|
||||
内容丢失;布局路径本身正常(实测确认)。
|
||||
- 处理:① onSpecMutated 按 spec.id 分流:layouts 里有该 id → 更新布局条目;否则写回
|
||||
views[id](入驻项目工作区)。所有变更(开标签/关标签/换聊天边/换位)都会触发;
|
||||
② 资源管理器文件匹配加 tsx/ts/jsx/js/css/json → kind:file 预览(等宽文本展示,同 TXT 模式)。
|
||||
- 验证(functional-diag 重排 STEP14/15 到 STEP10 前 + STEP9 改查 planreview 键 +
|
||||
恢复误删的 STEP13 打印行):STEP14 布局 layoutSavedTabs=1/layoutRestoredTabs=1、
|
||||
视图覆盖 taSavedTabs=1/taRestoredTabs=1(切换回来内容保持);STEP15 tsx/css 双标签预览
|
||||
且内容含 WorktableSection;全 15 STEP ERROR_COUNT: 0。
|
||||
- 备注:纯客户端改动,F5 即生效。
|
||||
|
||||
@@ -186,7 +186,7 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
try{
|
||||
var vv=JSON.parse(localStorage.getItem('dsh.worktable.projects.v1')).views||{};
|
||||
out.viewsKeys=Object.keys(vv);
|
||||
var rv=vv[out.viewsKeys[0]];
|
||||
var rv=vv['planreview'];
|
||||
if(rv){ out.resTop=(rv.top||[]).length; out.resMain=rv.main.length; out.resChatFull=rv.chatFullHeight===true; out.resId=rv.id; }
|
||||
}catch(e){ out.resErr=String(e) }
|
||||
var rows2=document.querySelectorAll('.dsh-wt_settings .dsh-wt_manageRow:not(.dsh-wt_manageRowSc)');
|
||||
@@ -211,6 +211,84 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
})()`);
|
||||
console.log('STEP9:', JSON.stringify(step9));
|
||||
|
||||
// 工作台状态持久化:布局项目与视图覆盖项目切换回来都保持上一次内容
|
||||
const step14 = await evaluate(`(async function(){
|
||||
var out={};
|
||||
try{
|
||||
var st=window.__dshWorktable.splitStore;
|
||||
// A) 布局项目:卡片打开 → 加终端标签 → 关闭 → 再开 → 标签还在
|
||||
var layCard=document.querySelector('.dsh-wt_layout');
|
||||
if(layCard){ layCard.click(); }
|
||||
await new Promise(function(r){setTimeout(r,400)});
|
||||
out.layoutOpenId=st.spec?st.spec.id:null;
|
||||
st.openTab('main',0,{kind:'builtin',type:'terminal'});
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
try{ out.layoutSavedTabs=JSON.parse(localStorage.getItem('dsh.worktable.projects.v1')).layouts[0].main[0].tabs.length }catch(e){ out.layoutSavedTabs='ERR' }
|
||||
st.close();
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
layCard=document.querySelector('.dsh-wt_layout');
|
||||
if(layCard){ layCard.click(); }
|
||||
await new Promise(function(r){setTimeout(r,400)});
|
||||
out.layoutRestoredTabs=st.spec?st.spec.main[0].tabs.length:null;
|
||||
st.close();
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
// B) 视图覆盖项目(旅行):先经 UI 设置视图 → 卡片打开 → 加资源管理器标签 → 关闭 → 再开 → 标签还在
|
||||
var btnS=document.querySelector('.dsh-wt_actions .dsh-wt_iconBtn:nth-child(2)');
|
||||
if(btnS){ btnS.click(); }
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
var rows=document.querySelectorAll('.dsh-wt_settings .dsh-wt_manageRow:not(.dsh-wt_manageRowSc):not(.dsh-wt_manageRowRemoved)');
|
||||
var taRow=rows[1];
|
||||
var puzzle=taRow&&taRow.querySelectorAll('.dsh-wt_manageBtn')[taRow.querySelectorAll('.dsh-wt_manageBtn').length-2];
|
||||
if(puzzle){ puzzle.click(); }
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
var presets=document.querySelectorAll('.dsh-wt_presets .dsh-wt_preset');
|
||||
if(presets[0]){ presets[0].click(); }
|
||||
await new Promise(function(r){setTimeout(r,400)});
|
||||
var bd=document.querySelector('.dsh-wt_popBackdrop');
|
||||
if(bd){ bd.click(); }
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
var ta=document.querySelector('.dsh-wt_projects .ta_card');
|
||||
if(ta){ ta.click(); }
|
||||
await new Promise(function(r){setTimeout(r,400)});
|
||||
out.taOpenId=st.spec?st.spec.id:null;
|
||||
st.openTab('main',0,{kind:'builtin',type:'explorer'});
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
try{ out.taSavedTabs=JSON.parse(localStorage.getItem('dsh.worktable.projects.v1')).views['travelatlas'].main[0].tabs.length }catch(e){ out.taSavedTabs='ERR' }
|
||||
st.close();
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
ta=document.querySelector('.dsh-wt_projects .ta_card');
|
||||
if(ta){ ta.click(); }
|
||||
await new Promise(function(r){setTimeout(r,400)});
|
||||
out.taRestoredTabs=(st.spec&&st.spec.id==='travelatlas')?st.spec.main[0].tabs.length:null;
|
||||
st.close();
|
||||
await new Promise(function(r){setTimeout(r,300)});
|
||||
}catch(err){ out.err=String(err) }
|
||||
return JSON.stringify(out);
|
||||
})()`);
|
||||
console.log('STEP14:', JSON.stringify(step14));
|
||||
|
||||
// tsx/css 代码文件预览:点击后新标签页显示内容(同 MD 模式)
|
||||
const step15 = await evaluate(`(async function(){
|
||||
var out={};
|
||||
try{
|
||||
var st=window.__dshWorktable.splitStore;
|
||||
st.open({id:'t-code',title:'code',top:null,main:[{id:'c1',title:'c',min:200,content:null}],chatWidth:{default:320,min:240,max:600}});
|
||||
await new Promise(function(r){setTimeout(r,400)});
|
||||
st.openTab('main',0,{kind:'file',path:'E:\\\\AI_Workspace\\\\DeepseekHarness\\\\Projects\\\\dsh-worktable\\\\01_content\\\\src\\\\client\\\\index.tsx'});
|
||||
await new Promise(function(r){setTimeout(r,1200)});
|
||||
out.tsxTab=st.spec.main[0].tabs[0].title;
|
||||
out.tsxView=!!document.querySelector('.dsh-wt_txt');
|
||||
out.tsxHasText=document.querySelector('.dsh-wt_txt')?String(document.querySelector('.dsh-wt_txt').textContent).indexOf('WorktableSection')>=0:false;
|
||||
st.openTab('main',0,{kind:'file',path:'E:\\\\AI_Workspace\\\\DeepseekHarness\\\\Projects\\\\dsh-worktable\\\\01_content\\\\src\\\\client\\\\styles.ts'});
|
||||
await new Promise(function(r){setTimeout(r,900)});
|
||||
out.cssTab=st.spec.main[0].tabs[1].title;
|
||||
out.tabsCount=st.spec.main[0].tabs.length;
|
||||
st.close();
|
||||
}catch(err){ out.err=String(err) }
|
||||
return JSON.stringify(out);
|
||||
})()`);
|
||||
console.log('STEP15:', JSON.stringify(step15));
|
||||
|
||||
// 删除二次确认:常驻项目/布局 ✕ → 警告弹窗 → 取消不删 / 确认删除;emoji 字号与名称字重统一
|
||||
const step10 = await evaluate(`(async function(){
|
||||
var out={};
|
||||
|
||||
Reference in New Issue
Block a user