Skip to content

Conversation

@microbit-robert
Copy link

@microbit-robert microbit-robert commented Dec 8, 2025

Requires thorough testing and review. The current loading page is a simple proof-of-concept - this could probably be a bit nicer and handle the project load failure case as well.

The storage has error handling that isn't currently doing anything other than logging to the console.

TODO:

  • Migrate from Date.now to uuid for action and recording ids
  • Migrate from ID to id
  • Handle changes in multiple tabs (done except check MakeCode open in both places)
    • Opening MakeCode in one tab seems to cause the other to be hidden. I've also observed the "this project is open in another tab" message. The MakeCode project can also somehow get out of sync and making a change causes a "project loaded" event.
  • Only load from IndexedDB once when the app loads - it is currently loading as a result of navigation changes inside the ProjectProvider. I think this is because of where this layer is in the component tree. A work around is in place.
  • Implement sensible response to storage error

A more sensible diff discounting the white space shift from removing the old persist middleware, but still quite large.

This can now support multiple projects, and I'll create a new PR targeting this one to work as a proof of concept. This should now be a simple case of not clearing the stores for a new session and project import.

Turns out that the upgrade callback should not be async and it's working by luck right now, so we need a new approach to migrate from localStorage / setup default values. Fixed in 3cdc10e

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

Preview build will be at
https://review-createai.microbit.org/storage/

Everything that updates multiple stores is now a transaction.
Assert data loaded from storage.
Update project 'updatedAt' when appropriate
src/storage.ts Outdated
const projectDataStore = tx.objectStore(DatabaseStore.PROJECT_DATA);
const projectData = assertData(await projectDataStore.get(this.projectId));
const updatedActionIds = Array.from(
new Set(...actions.map((a) => a.id), projectData.actionIds)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this spread right?

> new Set(["1", "2"])
Set(2) { '1', '2' }
> new Set(...["1", "2"])
Set(1) { '1' }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it wasn't. Fixed in ac3961a

src/storage.ts Outdated
return tx.done;
}

// TODO: TypeScript to ensure that a transaction with DatabaseStore.PROJECT_DATA is passed in.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flagging TODO

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot find a TypeScript type that does the right thing here, so I've gone with just duplicating the code twice and removing this method 0809259

src/storage.ts Outdated
interface ProjectData {
id: string;
timestamp?: number;
actionIds: string[];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative modelling suggestion:

Potentially, data integrity would be better if we removed actionIds and recordingIds from records for project and action respectively, and instead had an projectId and actionId columns on action and recording, with a non-unique index for querying.

This would structurally enforce that actions/recordings aren't shared between projects and are always owned by a project. What do you think?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So e.g. action querying would be something like:

const actionsForProject = await actionsStore.index('projectId').getAll(projectId);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this seems worth trying.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes made in b5b272f

Seems to work well, but would be better tested in the multiple projects branch. At the moment, each action and recording still have unique ids (we could go back to datetime, the one advantage of this would be that we wouldn't have to sort actions and recordings when pulling from IndexedDB)

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.

3 participants