Skip to content

Make it easier to work with instructions - #1580

Open
zetter-rpf wants to merge 6 commits into
mainfrom
instructions-refactor
Open

Make it easier to work with instructions#1580
zetter-rpf wants to merge 6 commits into
mainfrom
instructions-refactor

Conversation

@zetter-rpf

@zetter-rpf zetter-rpf commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Done to make https://github.com/RaspberryPiFoundation/digital-editor-issues/issues/1681 easier

This are some refactors and improvements to instructions that:

  • Fixes instruction format in example projects
  • Make it possible to preview code club project style instructions from example projects
  • Simplifying instruction state management and rendering
    • Previously the rendering happened far away from the instruction panel which was hard to follow
    • The state management was also complex as we would store the rendered instructions in state and have to have an effect to re-create them rather than just rendering when needed.
  • Splitting out large Instruction panel into separate components

See commits for more

Made with help from Claude

The markdown string format is what code classroom uses, the array with content is used by the projects site and has pre-rendered html
At the moment these instructions can only be passed as a web component attribute rather than as project props.

Decouple the type of instruction from where it came from.
Previously WebComponentProject converted project instructions to
HTML with marked.parse before storing them in the instructions
slice, so redux only ever held pre-rendered markup. That made the
raw source harder to work with for editing since it led to a more
complex chain of state updates.

This change stores the unconverted markdown string in the
instructions slice instead, and moves the marked.parse call (along
with its custom target=_blank link renderer) into InstructionsPanel,
which now converts to HTML immediately before rendering each step.
Pre-rendered HTML content from authored lesson JSON continues to
pass through marked.parse unchanged, so no other call sites needed
updating.

Updated WebComponentProject and InstructionsPanel tests to match:
the dispatched payload now carries raw markdown, and the target=_blank
link conversion is verified where the conversion now happens.
Previously every instruction step went through marked.parse in
InstructionsPanel, relying on markdown parsing being a safe no-op
passthrough for pre-rendered HTML from authored lesson JSON. That
coupling was accidental: there was no explicit signal for which
steps needed markdown conversion and which were already HTML.

This change renames the key used for the single-string project
instructions case from `content` to `markdown_content` in
WebComponentProject, and teaches InstructionsPanel to branch on the
key present on a step: `content` is displayed as-is, while
`markdown_content` is run through marked.parse. This makes the
distinction explicit rather than relying on marked's HTML
passthrough behaviour.
Previously WebComponentProject held a useEffect that dispatched
setInstructions into the instructions slice whenever
editor.project.instructions changed. Since editing instructions writes
to editor.project.instructions on every keystroke, this fired a redux
action on every keystroke too, just to keep a derived copy of the same
data in sync.

This change replaces that effect with selectInstructionSteps, a
memoized reselect selector (via @reduxjs/toolkit) that computes the
steps to display directly from editor.project.instructions,
instructions.permitOverride, and any steps already loaded into the
slice (e.g. by WebComponentLoader for pre-authored lessons). Nothing
is dispatched to derive it, so InstructionsPanel and ProgressBar can
both read the same selector without WebComponentProject needing to
run first or re-run on every edit.

Alternatively the sync logic could have moved into InstructionsPanel
directly, but ProgressBar (and any future reader) needs the same
derived steps, so a shared selector avoids duplicating the branching
logic per component.
Previously InstructionsPanel mixed two concerns in one component: the
surrounding UI (buttons, tabs, empty state, progress bar) and current
step management, alongside the actual rendering of a step's HTML
(markdown conversion, syntax highlighting, scratchblocks, quiz-ready
signalling) into a ref'd DOM node. That made the file large and meant
quiz questions were rendered through ad-hoc branching rather than a
reusable path.

This change extracts InstructionsStep, a component responsible only
for rendering a single step (or a quiz question, passed in the same
{content} shape) into its own DOM node. InstructionsPanel now computes
which step to show (the real current step, or a synthesized
{content: quiz.questions[...]} step while a quiz is active) and passes
it down, keeping its own responsibility to managing state and the
current step.

This also let two pieces of incidental complexity go: react-tabs
mounts each InstructionsStep instance fresh when its tab is selected,
so the instructionsTab dependency previously needed to force the
content effect to re-run is no longer necessary, and Prism's one-time
config now lives with the only component that renders highlighted code.

Splitting out a dedicated step component also sets up the next step:
editing a single instruction, rather than the whole project
instructions string, will live in InstructionsStep rather than
requiring changes to the surrounding panel.

Test coverage for step rendering (markdown conversion, syntax
highlighting, scratchblocks, quiz-ready signalling) moved to a new
InstructionsStep.test.jsx; InstructionsPanel.test.jsx keeps a mix of
panel-level tests plus one representative example of each moved
behaviour to confirm the wiring still works end-to-end.
@zetter-rpf
zetter-rpf force-pushed the instructions-refactor branch from 739561f to d870ae4 Compare August 7, 2026 13:18
@zetter-rpf
zetter-rpf marked this pull request as ready for review August 7, 2026 14:16
@zetter-rpf zetter-rpf changed the title Instructions refactor Make it easier to work with instructions Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant