feat(editor): F4.6c the software installation on a computer's desktop

A new oracle, InstallRun, installs each of Java's programs on new
computers, all of them on one, each installed and removed again, and a
DNS and an e-mail server installed again after their removal; Java saves
the result as a project. A new program is switched off (a computer's
firewall is on), makes the folders and files it lacks (the web server's
start page in FILIUS' language and its picture, /peer2peer,
/mailserver/konten.txt, /dns/hosts), and removing it takes its settings
and leaves its files; a server installed again reads its records or
accounts from them. Java installs in the order of its list and starts
the program at once.

The document's setSoftware does the same, checked against Java's saved
installation. The core knows what a program makes in the files and
installs or removes a program while the simulation runs; the room
watches the document's programs and hands changes to the engine, so a
new command line works at once. The desktop offers Java's dialog with
two lists, arrows, double click and apply changes.

Also: Java's file may name a number it rolled by the result of any
getter (an idref, here a thread's priority); GetterDefaults now
measures the priority of the saved thread classes, which the import
read as 0 before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 15:03:35 +00:00
co-authored by Claude Opus 5.5
parent ac48e969f4
commit f0e7c73ec7
29 changed files with 1264 additions and 52 deletions
@@ -257,6 +257,25 @@ test.describe('on a phone', () => {
await window.locator('input[name="terminalInput"]').press('Enter');
await expect(window.locator('.terminal-text')).toContainText('IP Adresse . . . : 141.99.1.10');
});
test('offers the installation’s programs as targets for a finger', async ({ page }) => {
await openEditor(page, server.base, 'internetwork_komplett.fls');
await simulationButton(page).tap();
await expect(page.locator('svg.filius-canvas')).toHaveAttribute('data-mode', 'simulation');
await page.getByRole('button', { name: 'Alles zeigen' }).tap();
const id = await deviceNamed(page, 'Notebook 1.10');
const at = await onDevice(page, id);
await page.touchscreen.tap(at.x, at.y);
await desktop(page, id).locator('[data-program="installation"]').tap();
const panel = desktop(page, id).locator('[data-program-window="installation"]');
const first = (await panel.locator('[data-list="available"] [role="option"]').first().boundingBox())!;
expect(first.height).toBeGreaterThanOrEqual(44);
const arrow = (await panel.getByRole('button', { name: 'Installieren' }).boundingBox())!;
expect(arrow.height).toBeGreaterThanOrEqual(44);
await panel.locator('[data-list="available"] [role="option"]').first().tap();
await panel.getByRole('button', { name: 'Installieren' }).tap();
await expect(panel.locator('[data-list="installed"] [role="option"]')).toHaveText(['Befehlszeile', 'Bildbetrachter', 'Webbrowser']);
});
});
/** Opens a computer's command line on its desktop. */
@@ -343,6 +362,61 @@ test('keeps the command line over leaving it, over a return to the design, and e
await expect(window).toBeVisible();
});
test("installs and removes programs as Java's installation does, and a program installed runs at once", async ({ page }) => {
await openEditor(page, server.base, 'internetwork_komplett.fls');
const id = await deviceNamed(page, 'Rechner 3.10');
expect((await desktopOf(page, id))!.programs).toEqual([]);
await start(page);
await tap(page, id);
const window = desktop(page, id);
await window.locator('[data-program="installation"]').click();
const panel = window.locator('[data-program-window="installation"]');
await expect(panel.getByRole('heading')).toHaveText('Software-Installation');
const installed = panel.locator('[data-list="installed"] [role="option"]');
const available = panel.locator('[data-list="available"] [role="option"]');
await expect(installed).toHaveCount(0);
await expect(available).toHaveText(['Befehlszeile', 'Bildbetrachter', 'Datei-Explorer', 'DNS-Server', 'E-Mail-Programm', 'E-Mail-Server', 'Echo-Server', 'Einfacher Client', 'Firewall', 'Gnutella', 'Text-Editor', 'Webserver', 'Webbrowser']);
// Chosen with a tap each, moved over with the arrow; the list keeps Java's order.
await available.filter({ hasText: 'Webserver' }).click();
await available.filter({ hasText: 'Befehlszeile' }).click();
await expect(available.filter({ hasText: 'Webserver' })).toHaveAttribute('aria-selected', 'true');
// A second tap lets a program go again.
await available.filter({ hasText: 'Gnutella' }).click();
await available.filter({ hasText: 'Gnutella' }).click();
await expect(available.filter({ hasText: 'Gnutella' })).toHaveAttribute('aria-selected', 'false');
await panel.getByRole('button', { name: 'Installieren' }).click();
await expect(installed).toHaveText(['Befehlszeile', 'Webserver']);
// Nothing changes before "apply changes".
expect((await desktopOf(page, id))!.programs).toEqual([]);
await panel.getByRole('button', { name: 'Änderungen annehmen' }).click();
await expect(panel).toHaveCount(0);
await expect(window.locator('.desktop-icon span')).toHaveText(['Software-Installation', 'Befehlszeile', 'Webserver']);
expect([...(await desktopOf(page, id))!.programs].sort()).toEqual(['commandPrompt', 'webServer']);
// The command line runs at once, and sees the web server's files.
await window.locator('[data-program="commandPrompt"]').click();
const input = window.locator('input[name="terminalInput"]');
await input.fill('ls /webserver');
await input.press('Enter');
await expect(window.locator('.terminal-text')).toContainText('index.html');
await window.getByRole('button', { name: 'Startbildschirm' }).click();
// A double click moves a program back; applied, it is gone.
await window.locator('[data-program="installation"]').click();
await installed.filter({ hasText: 'Webserver' }).dblclick();
await expect(installed).toHaveText(['Befehlszeile']);
await panel.getByRole('button', { name: 'Änderungen annehmen' }).click();
await expect(window.locator('.desktop-icon span')).toHaveText(['Software-Installation', 'Befehlszeile']);
expect((await desktopOf(page, id))!.programs).toEqual(['commandPrompt']);
// Taken on and given back before applying: nothing happens.
await window.locator('[data-program="installation"]').click();
await available.filter({ hasText: 'Gnutella' }).dblclick();
await installed.filter({ hasText: 'Gnutella' }).click();
await panel.getByRole('button', { name: 'Entfernen' }).click();
await panel.getByRole('button', { name: 'Änderungen annehmen' }).click();
expect((await desktopOf(page, id))!.programs).toEqual(['commandPrompt']);
});
test('says so when the simulation fails, and goes back to the design', async ({ page }) => {
// FILIUS' modem example: the core has no modems yet (remote links); a ping to the other side fails it.
await openEditor(page, server.base, 'modem_beispiel.fls');