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
23 changes: 22 additions & 1 deletion src/praisonai-desktop/frontend/tests/first-run.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ async function boot({ provision = 'ok', steps = [], savedView = null,
const dom = new JSDOM(HTML, {
runScripts: 'dangerously', resources: 'usable', url: ORIGIN + '/',
beforeParse(w) {
if (savedView) w.localStorage.setItem('view', savedView);
// Model a machine where the user last used the Train tab: the app
// restores that view synchronously, before the async engine check runs.
if (savedView) try { w.localStorage.setItem('view', savedView); } catch {}
w.__TAURI__ = {
core: {
invoke: async (cmd) => {
Expand Down Expand Up @@ -186,3 +188,22 @@ test('a failed setup says why and offers another go', async () => {
'the reason was swallowed');
assert.ok(b.doc.querySelector('.setup li.failed'), 'the failing step is not marked');
});

// A restored Train view hides #thread, where the setup wizard renders. Left
// alone, that buries setup: the title bar says "setup needed" and nothing is on
// screen to act on -- the reported Windows dead end. The engine gate must win
// over the restored view while the engine is not ready.
test('a restored Train view does not hide the setup screen', async () => {
const b = await boot({ savedView: 'train' });
assert.ok(b.doc.querySelector('.setup'), 'no setup screen');
assert.equal(b.doc.body.classList.contains('training'), false,
'the Train view is still up, hiding the setup wizard');
});

// The forced switch must not clobber the deliberate choice: once the engine is
// up, the user's Train tab should return, so we must not have persisted 'chat'.
test('the forced Chat switch does not overwrite the saved Train choice', async () => {
const b = await boot({ savedView: 'train' });
assert.equal(b.window.localStorage.getItem('view'), 'train',
'the saved view was overwritten by the engine gate');
});
7 changes: 7 additions & 0 deletions src/praisonai-desktop/ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1400,6 +1400,8 @@ <h2>Fine-tune a model</h2>
// is the difference between a product and an error message: "No usable
// Python" is true and useless to someone who has never installed one.
status.textContent='setup needed'; status.className='s-boot';
// engineBlocked forced Chat above, so #thread is visible: a restored Train
// view can no longer bury the wizard firstRun() renders there.
firstRun(st);
}else{
status.textContent='engine failed'; status.className='s-fail';
Expand Down Expand Up @@ -2208,6 +2210,11 @@ <h2>Fine-tune a model</h2>
let trainStream=null, trainCursor=-1, trainRunId=null, lossSeries=[], logLines=[];
const MAX_LOG_LINES=600; // the pane is a tail, not an archive; the log file has it all

// A restored Train view hides #thread (body.training #thread{display:none}),
// where the setup wizard and failure banner render. While the engine is not
// ready, a requested Train view is forced to Chat so that UI stays visible;
// the deliberate choice is still persisted, and the post-boot restore below
// returns Train once the engine is up.
function showView(name,{persist=true}={}){
const requested=name;
if(name==='train' && engineBlocked) name='chat';
Expand Down
Loading