From 0e0cd8099c509fe49f4180413a2c2ffa31a0990b Mon Sep 17 00:00:00 2001 From: cocomarine Date: Thu, 2 Jul 2026 16:09:12 +0100 Subject: [PATCH 1/3] add saveDisabled to wc and redux --- src/redux/EditorSlice.js | 5 +++++ src/redux/EditorSlice.test.js | 7 +++++++ src/web-component.js | 2 ++ 3 files changed, 14 insertions(+) diff --git a/src/redux/EditorSlice.js b/src/redux/EditorSlice.js index abf7b5276..d6bd05c51 100644 --- a/src/redux/EditorSlice.js +++ b/src/redux/EditorSlice.js @@ -128,6 +128,7 @@ export const editorInitialState = { scratchIframeProjectIdentifier: null, friendlyErrorsEnabled: false, friendlyError: null, + saveDisabled: false, }; const isScratchProject = (state) => @@ -300,6 +301,9 @@ const EditorSlice = createSlice({ setFriendlyError: (state, action) => { state.friendlyError = action.payload; }, + setSaveDisabled: (state, action) => { + state.saveDisabled = action.payload; + }, setLoadRemixDisabled: (state, action) => { state.loadRemixDisabled = action.payload; }, @@ -531,6 +535,7 @@ export const { setSenseHatEnabled, setFriendlyErrorsEnabled, setLoadRemixDisabled, + setSaveDisabled, setReactAppApiEndpoint, setScratchApiEndpoint, stopCodeRun, diff --git a/src/redux/EditorSlice.test.js b/src/redux/EditorSlice.test.js index 37c529f0f..6e4b9897d 100644 --- a/src/redux/EditorSlice.test.js +++ b/src/redux/EditorSlice.test.js @@ -23,6 +23,7 @@ import reducer, { scratchSaveFailed, setFriendlyErrorsEnabled, setFriendlyError, + setSaveDisabled, } from "./EditorSlice"; const mockCreateRemix = jest.fn(); @@ -128,6 +129,12 @@ test("Action setOfflineEnabled correctly sets offlineEnabled", () => { ); }); +test("Action setSaveDisabled sets saveDisabled", () => { + const previousState = { saveDisabled: false }; + const expectedState = { saveDisabled: true }; + expect(reducer(previousState, setSaveDisabled(true))).toEqual(expectedState); +}); + test("Action addProjectComponent adds component to project with correct content", () => { const previousState = { project: { diff --git a/src/web-component.js b/src/web-component.js index 537a4d267..bb3d52b09 100644 --- a/src/web-component.js +++ b/src/web-component.js @@ -79,6 +79,7 @@ class WebComponent extends HTMLElement { "load_cache", "offline_enabled", "friendly_errors_enabled", + "save_disabled", ]; } @@ -99,6 +100,7 @@ class WebComponent extends HTMLElement { "load_cache", "offline_enabled", "friendly_errors_enabled", + "save_disabled", ]; const jsonAttrs = [ "instructions", From 5f4b228c7d2cae6c8c16419a024aedd69a4264d6 Mon Sep 17 00:00:00 2001 From: cocomarine Date: Thu, 2 Jul 2026 16:12:44 +0100 Subject: [PATCH 2/3] dispatch saveDisabled in wc loader --- src/containers/WebComponentLoader.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/containers/WebComponentLoader.jsx b/src/containers/WebComponentLoader.jsx index 0aef37da2..72198c689 100644 --- a/src/containers/WebComponentLoader.jsx +++ b/src/containers/WebComponentLoader.jsx @@ -5,6 +5,7 @@ import { setSenseHatAlwaysEnabled, setOfflineEnabled, setFriendlyErrorsEnabled, + setSaveDisabled, setLoadRemixDisabled, setReactAppApiEndpoint, setScratchApiEndpoint, @@ -72,6 +73,7 @@ const WebComponentLoader = (props) => { loadCache = true, // Always use cache unless explicitly disabled initialProject = null, offlineEnabled = false, + saveDisabled = false, } = props; const dispatch = useDispatch(); @@ -204,6 +206,10 @@ const WebComponentLoader = (props) => { dispatch(setOfflineEnabled(offlineEnabled)); }, [offlineEnabled, dispatch]); + useEffect(() => { + dispatch(setSaveDisabled(saveDisabled)); + }, [saveDisabled, dispatch]); + useEffect(() => { // Create a script element to save the existing Prism object if there is one const script = document.createElement("script"); From 5c8bb113052096a2603baa966b1672d1d6e6e4ef Mon Sep 17 00:00:00 2001 From: cocomarine Date: Thu, 2 Jul 2026 17:01:22 +0100 Subject: [PATCH 3/3] do not show save button when saveDisabled --- src/components/ProjectBar/ProjectBar.jsx | 3 ++- src/components/ProjectBar/ProjectBar.test.js | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/ProjectBar/ProjectBar.jsx b/src/components/ProjectBar/ProjectBar.jsx index 1b790663e..33c331166 100644 --- a/src/components/ProjectBar/ProjectBar.jsx +++ b/src/components/ProjectBar/ProjectBar.jsx @@ -19,6 +19,7 @@ const ProjectBar = ({ nameEditable = true }) => { const loading = useSelector((state) => state.editor.loading); const lastSavedTime = useSelector((state) => state.editor.lastSavedTime); const offlineEnabled = useSelector((state) => state.editor.offlineEnabled); + const saveDisabled = useSelector((state) => state.editor.saveDisabled); const projectOwner = isOwner(user, project); const readOnly = useSelector((state) => state.editor.readOnly); const isOnline = useIsOnline(); @@ -39,7 +40,7 @@ const ProjectBar = ({ nameEditable = true }) => { type="tertiary" /> - {!projectOwner && !readOnly && ( + {!projectOwner && !readOnly && !saveDisabled && (
diff --git a/src/components/ProjectBar/ProjectBar.test.js b/src/components/ProjectBar/ProjectBar.test.js index 46c7f0cfc..0db25b777 100644 --- a/src/components/ProjectBar/ProjectBar.test.js +++ b/src/components/ProjectBar/ProjectBar.test.js @@ -95,6 +95,25 @@ describe("When logged in and user owns project", () => { }); }); +describe("When logged in and save is disabled", () => { + beforeEach(() => { + renderProjectBar({ + editor: { + project, + saveDisabled: true, + lastSavedTime: new Date().getTime(), + }, + auth: { + user, + }, + }); + }); + + test("Save button is not shown", () => { + expect(screen.queryByText("header.save")).not.toBeInTheDocument(); + }); +}); + describe("When logged in and no project identifier", () => { const projectWithoutId = { ...project, identifier: null };