Skip to content

Conversation

@microbit-robert
Copy link

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

This is a first pass at storing multiple projects and builds on the storage branch which transitions from using localStorage to IndexedDB. There may well be bugs in this implementation, please document these if you hit them during testing.

If additional code changes are made, you will probably need to manually delete the "ml" database in IndexedDB using devtools.

TODO:

  • Testing, lots of testing
  • UI design / changes
    • Consider project cards (date and id are for debugging purposes at the moment / image / icons), capturing project name upfront, importing data with a choice to create a new project or append or replace actions in existing project
  • Look at the diff with the storage branch to determine what changes need to be pulled in for an easy migration from single to multiple projects
  • Work out why e2e test was failing (commented out for now - it relates to the resume session button which is probably going away, but nice to understand why it was failing
  • Add e2e tests
  • More consideration and testing of cross-tab changes
  • Investigate localStorage migration bug
    • To reproduce the bug, clear ml database in IndexedDB, add project to localStorage under 'ml' name, then refresh the page.
  • ...

@github-actions
Copy link

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

Copy link

@microbit-matt-hillsdon microbit-matt-hillsdon left a comment

Choose a reason for hiding this comment

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

WIP review but making comments visible as I go

src/storage.ts Outdated
}

async removeModel() {
console.trace("when");

Choose a reason for hiding this comment

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

Suggested change
console.trace("when");

Copy link
Author

Choose a reason for hiding this comment

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

src/storage.ts Outdated
const settings = assertData(
await settingsStore.get(DatabaseStore.SETTINGS)
);
makeCodeData.project.header?.name;

Choose a reason for hiding this comment

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

Was this intended to do anything?

Copy link
Author

Choose a reason for hiding this comment

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

Unclear. Likely leftover from debugging and I can't think of what else it would be needed for so removing 3eb2d37

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

async deleteProject(id: string): Promise<PersistedProjectData | boolean> {

Choose a reason for hiding this comment

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

If we need all the info being returned here I think we should model it more clearly.

Or perhaps some of the responsibility belongs elsewhere? I'm a bit unsure about the storage layer having an idea of the current project.

Copy link
Author

Choose a reason for hiding this comment

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

Probably worth talking this bit through. It's messy in the method itself and where it is called.

We can easily move away from the storage layer having an idea of the current project. For a long time the projectId was isolated to the storage layer, but it's now required in state to react to model changes.

src/storage.ts Outdated
const localStorageProject = getLocalStorageProject();
if (localStorageProject) {
const model = await tf.loadLayersModel(oldModelUrl);
if (model) {

Choose a reason for hiding this comment

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

Is this definitely right? The type definitions suggest this doesn't return undefined/null and so might instead throw. Worth a comment if it is correct. There's also one other use.

Choose a reason for hiding this comment

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

See loadModelFromStorage which is handling this error at some distance from its cause.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, it's return a model or throw. I've moved the error handling closer to the function calls for all model storage actions e786ff1

}
};

useStore.subscribe(async (state, prevState) => {

Choose a reason for hiding this comment

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

Feels like it's worth doing multiple model storage soon so we don't have this hard to reason about code dealing with the only thing that isn't per project.

Copy link
Author

Choose a reason for hiding this comment

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

This version does have multiple model storage. The projectId check prevents your current model from being removed when you start a new session. The flow at things stand:

  • Existing project with existing model (all saved in IndexedDB)
  • Start a new session
    • This updates state first with a new empty project and new project id
    • The subscription callback runs and without the project id check, the existing model is cleared which we don't want
    • The storage layer is then called with a new project and new project id

microbit-matt-hillsdon

This comment was marked as duplicate.

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