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
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ npm run lint # oxlint; 7 known warnings, all in the vendored public/coi-servi
npm run test:browser # after a build: scripts/check-ide-browser.mjs, the IDE in headless Chrome
```

The one automated check is `test:browser` (`scripts/check-ide-browser.mjs`): `playwright-core` drives the installed Chrome (GitHub's runner has one) against `vite preview` of `dist/`, with Pyodide from its CDN and its own fixtures (it serves a library by URL itself). It covers tab switches with a read-only file, per-tab projects, share links (library by URL, 404, cut and long links), ▶ and Tests, ⋮ «Info», and `input()` in the console (a recursive REPL, Stop → `EOFError`); add regression cases there. The browser's «leave the page» question and the iPad stay manual. `.github/workflows/ci.yml` runs `npm ci`, the build (tsc catches type changes in a new editor tag), lint and `test:browser` on every pull request. Pushes to `main` deploy to GitHub Pages (`deploy-pages.yml`). To check a change in the browser, use `npm run dev`; `npm run build && npm run preview` serves the production layout. The embed is a separate project site under the same origin, https://glpython-edu.github.io/glpython-editor/. The IDE's `coi-serviceworker.js` registers for scope `/`, which includes it, so after a change to that worker check the embed too: its demo page opened directly, and a LiaScript course.
The one automated check is `test:browser` (`scripts/check-ide-browser.mjs`): `playwright-core` drives the installed Chrome (GitHub's runner has one) against `vite preview` of `dist/`, with Pyodide from its CDN and its own fixtures (it serves a library by URL itself). It covers tab switches with a read-only file, per-tab projects, share links (library by URL, 404, cut and long links), ▶ and Tests, ⋮ «Info», `input()` in the console (a recursive REPL, Stop → `EOFError`), and a task's instructions as a tab (`openFile`, a read-only `aufgabe.md` as a page, sanitizing); add regression cases there. The browser's «leave the page» question and the iPad stay manual. `.github/workflows/ci.yml` runs `npm ci`, the build (tsc catches type changes in a new editor tag), lint and `test:browser` on every pull request. Pushes to `main` deploy to GitHub Pages (`deploy-pages.yml`). To check a change in the browser, use `npm run dev`; `npm run build && npm run preview` serves the production layout. The embed is a separate project site under the same origin, https://glpython-edu.github.io/glpython-editor/. The IDE's `coi-serviceworker.js` registers for scope `/`, which includes it, so after a change to that worker check the embed too: its demo page opened directly, and a LiaScript course.

## Layout

- `src/App.tsx` — the shell. It renders `GlPythonWorkspace` (stacked layout; its buttons go into the bar through `actionsContainer`, every file is a tab with `closeFileTabs: false`) and uses glpython-editor's project helpers (`addProjectFile`, `renameProjectFile`, …).
- `src/index.css` — the shell's styles (`ide-*` classes), from glpython-editor's `--glp-*` tokens. glpython-editor's `style.css` styles only the workspace (plus `icon-button`, `hidden-input` and `auth-notice`, which the shell uses too).
- `src/i18n.ts` — only the shell's own strings (`ShellStrings`, de/en). The workspace's strings come from glpython-editor's `coreStrings`, so don't copy them here. A new workspace string goes into glpython-editor's `src/i18n.ts`.
- `src/tabProjects.ts`: per-tab projects (P25). The tab's id is in sessionStorage and `history.state` (never in the address); projects are in localStorage, one entry per id. Nothing is deleted when a tab goes away: a page can't tell a close from iPad Safari unloading it (only `history.state` survives that). Open tabs answer over a BroadcastChannel, which finds duplicated tabs and the projects for «Zuletzt geschlossen».
- `src/projectStorage.ts` (folder/ZIP) and `src/projectShare.ts` (`?project=` share links, lz-string, versioned payload: v1 every file's code, v2 also libraries by URL, fetched by `src/libraries.ts`; a link that can't be read opens an empty project with a notice).
- `src/projectStorage.ts` (folder/ZIP) and `src/projectShare.ts` (`?project=` share links, lz-string, versioned payload: v1 every file's code, v2 also libraries by URL, fetched by `src/libraries.ts`; optional `openFile`, the tab to open with (a library by URL once fetched, unless the learner chose a tab: `tabChosenRef`), kept on the `TabEntry`, in «Teilen» links and in the ZIP; the tabs in the link's order (`fileOrder`), which «Teilen» keeps; a link that can't be read opens an empty project with a notice).
- `src/markdown.ts`: the workspace's `renderMarkdown` (marked + DOMPurify, both pinned; HTML in the Markdown becomes text, links get `target="_blank"` and `rel="noopener noreferrer"`).
- `src/auth.ts` — MSAL. Only active with `VITE_ENTRA_CLIENT_ID` in `.env.local` (README «Microsoft sign-in»).
- `vite.config.ts` — `optimizeDeps.exclude: ['glpython-editor']` keeps the editor's worker next to its `dist/index.js`. Don't remove it.

Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,43 @@ lock: it can be read, run and imported, but not edited, renamed or deleted -
e.g. a parser that learners use as a black box. This local format is also the shape planned for OneDrive
folder synchronization.

**A task's instructions as a tab.** A share link can name the tab that is
open when the project opens: `"openFile": "aufgabe.md"` next to `mainFile`
(any version; one that isn't among the files is ignored, and an IDE from
before opens the link as it did). ▶, **Tests** and **Visualisieren** always
act on `mainFile`, whichever tab is open. A Markdown file (`.md`) has a switch
**Ansicht / Text** at the end of the tabs: a read-only one opens as a page, an
editable one as its text. The page is rendered with
[marked](https://marked.js.org/) and sanitized with
[DOMPurify](https://github.com/cure53/DOMPurify) (both pinned): HTML written
in the Markdown shows as text, scripts, event attributes and `javascript:`
links are removed, links open in a new tab, code is only shown. The tab's
project, **Teilen**, a reload and the ZIP (`"openFile"` in `glpython.json`)
keep `openFile`. The instructions can come by URL, like a library (a shorter
link for the hand-in): that tab becomes the open one once it has loaded,
unless the learner has chosen another tab in the meantime; if it can't be
loaded, `mainFile` stays open. The tabs follow the order of the files in the
link (libraries by URL among them), and **Teilen** writes them in that order;
a new file comes last. For example:

```json
{
"v": 2,
"name": "Aufgabe 1",
"mainFile": "auswerter.py",
"openFile": "aufgabe.md",
"files": {
"aufgabe.md": { "path": "aufgabe.md", "url": "https://…/aufgabe.md", "readOnly": true },
"parser.py": { "path": "parser.py", "url": "https://…/parser.py", "readOnly": true },
"auswerter.py": { "path": "auswerter.py", "label": "auswerter", "kind": "python", "code": "…" }
}
}
```

as `?project=` + `LZString.compressToEncodedURIComponent(JSON.stringify(…))`.
A Markdown file can also carry its code (`"kind": "text", "code": "…"`,
`"readOnly": true`); then it is open at once.

## Microsoft sign-in

Copy `.env.example` to `.env.local` and set the client ID from a Microsoft
Expand Down
Loading
Loading