Add Personal Cloud project library#12574
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
d2fb4a5 to
2950972
Compare
2950972 to
298d2dc
Compare
pierremtb
left a comment
There was a problem hiding this comment.
Approving now so you're not blocked on me since I'm off today.
Dropped a few notes. Testing felt great on web and desktop (macOS)!
| onDragOver={ | ||
| canReorderLibraries | ||
| ? (event) => handleDragOver(event, index) | ||
| : undefined | ||
| } | ||
| onDrop={ | ||
| canReorderLibraries | ||
| ? (event) => handleDrop(event, index) | ||
| : undefined | ||
| } |
| return ( | ||
| snapshot.context as unknown as Record< | ||
| string, | ||
| | Record< | ||
| string, | ||
| { current?: unknown; default?: unknown; user?: unknown } | undefined | ||
| > | ||
| | undefined | ||
| > | ||
| )[activationSetting.category]?.[activationSetting.settingName] |
There was a problem hiding this comment.
We might want to improve this if we can 😅
There was a problem hiding this comment.
Totally fair, although this type was actually introduced way back here, and it's really just being moved around here (you can see the code gets removed down at lines 560–566, it used to be called desiredActive).
There was a problem hiding this comment.
Ultimately that type is correct, but I do agree we should find a way to
- make that more readable
- Figure out a cleaner way to accomplish what
syncPluginSettingsdoes: it's hella effectful.
There was a problem hiding this comment.
But I'd like to do that in future PRs
cea7df4 to
e29d88d
Compare
Co-authored-by: Jace Browning <jacebrowning@gmail.com>
| ...runtimeConfig.value, | ||
| enabled: runtimeConfig.value.enabled && cloudSyncPluginEnabled, | ||
| projectDirectoryPath: currentSettings | ||
| ? getDefaultDirectoryProjectLibraryPath( |
There was a problem hiding this comment.
I think this should use getDefaultCloudProjectDirectoryPath instead?
Now what happens:
- I create a new cloud project in the browser
- open ZDS -> Cloud sync
- the new project appears under Personal Cloud (correct)
- but once I click on it, which downloads it, will make it appear under Default Project Directory too
I assume that's not intended?
There was a problem hiding this comment.
No that is not intended! Thank you for finding that.
There was a problem hiding this comment.
I think the way that I need to fix this is actually to get the the appropriate directory into ensureCloudProjectLocallySynced.
There was a problem hiding this comment.
That fires during the project "open" action, and does the actual downloading. That needs to know what library the project hails from.
|
Something from user testing: if you disable Cloud-sync setting in the web, then your cloud projects go away (Expected), but your web-local projects don't come back and you can't create any new ones either. |
Oh! Since we want that policy to be that web users can't have "local", directory-type libraries, should we model this as an optional plugin only on desktop, and a required extension on web? |
…orrectly Addresses @andrewvarga's comment [here](#12574 (comment)) by letting projects from cloud libraries supply their local sync directory location into `ensureCloudProjectLocallySynced`, so that they can materialize the project to the correct local path, which now might not be the "default project directory" setting.
On web the Personal Cloud library replaces the default directory library and points at the same OPFS folder, so after enabling cloud sync it is the only configured library. But the `cloud` library type's readEntries/ createProject lived inside the toggle-able cloud-sync plugin slot, so disabling cloud sync removed the only way to list or create projects, stranding the user until reload. - Register the `cloud` project-library type as always-on infrastructure (new extensions/cloudSyncLibrary barrel) instead of inside the plugin slot; the plugin now toggles only the sync surface (remote entries, status bar, project-menu actions, Personal Cloud row). - Relax the type's createProject so it no longer requires sync to be enabled: it creates in the local folder and only enrolls for sync when cloud sync is on. - Make cloud sync non-optional on web via a single registration: hide the activation toggle on web (hideOnPlatform threaded through createZdsPlugin) and have the auto-enable policy ignore a prior opt-out on web, keeping the setting the source of truth and the activation-keyed migrations untouched. Desktop stays opt-in. - Add defense-in-depth warnings when a configured library has no registered type handler / no create target. Addresses #12574 (comment) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@andrewvarga this commit should address your comment af0c8f9. We'll block turning off cloud sync on web. |
PluginsList rendered every plugin's activation toggle regardless of its hideOnLevel/hideOnPlatform config, so on web a flagged user could still flip cloud sync off from the Plugins tab even though its settings field is hidden there. Filter the list through the same shouldHideSetting logic the settings panel and command bar use, and move cloud sync's feature gate onto its activation setting (hideWithoutFeature) so the filter is generic instead of special-casing the plugin id. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remote-only cloud projects (listed from the cloud index but not yet materialized locally) had their rename/delete actions disabled: the home project capability guards required a local path, and the cloud project-library type defined no rename/delete operations. Add remote-acting rename/delete to the cloud library type. When a project has a local materialization they mutate the local files and let sync replicate; when it is still remote-only they act on the remote directly via new engine functions (rename re-uploads the archive with a new title under expected_revision, since the cloud API has no title-only update). Relax the home project capability guards to drop the local-path requirement now that each operation owns its local-vs-remote handling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
One critical thing I changed at the end here: I fixed a problem where cloud projects couldn't be renamed even after they were "materialized" locally. I fixed that by actually allowing renaming and deletion even on "unmaterialized" projects, which just updates the remote project entry. That required additional code, which is why the diff has grown. |
Confirmed these are working!
|
Ah good point, you should be able to open locally-materialized projects from cloud projects without a connection. Let's make that an issue. |
Summary
cloudproject library type and the defaultcloud-personalPersonal Cloud libraryZoo/personalfolderWhy
This is the Personal Cloud library PR in the project-library stack. It adds the cloud library model and default personal library without including the legacy synced-directory migration prompt.
The cloud-sync activation behavior is intentionally modeled as app product policy instead of plugin startup reconciliation. The plugin can stay statically default-off, while the settled app runtime decides when a feature-flagged user should be opted in and when the Personal Cloud library row should be added to
app.libraries. That avoids a brittle settings mutation during registry construction and keeps user opt-outs respected.The web policy is also intentional: OPFS is an implementation detail, so enabling Personal Cloud should not create a second visible directory-style library or physically move the browser's default project storage. Instead, the default browser project library is represented as Personal Cloud once cloud sync is enabled. Browser users also cannot create or edit directory libraries, but they can remove a directory-library row if one already exists in their settings.
Stack
Validation
npm run test -- src/registry/contracts/projectLibraries.spec.ts src/lib/projectLibraries/settings/ProjectLibrariesSettingInput.spec.tsx src/lib/cloudSync/registry/plugin.spec.tsxnpm run test:integration -- src/lib/settings/settingsUtils.spec.ts src/lib/app.spec.tsnpm run tsc -- --noEmitnpm run lint -- src/lib/app.ts src/lib/app.spec.ts src/lib/cloudSync/index.test.ts src/lib/cloudSync/paths.ts src/lib/cloudSync/registry/plugin.spec.tsx src/lib/projectLibraries/settings/ProjectLibrariesSetting.tsx src/lib/projectLibraries/settings/ProjectLibrariesSettingInput.tsx src/lib/projectLibraries/settings/ProjectLibrariesSettingInput.spec.tsx src/lib/routeLoaders.ts src/lib/settings/settingsUtils.ts src/machines/settingsMachine.ts src/registry/contracts/projectLibraries.ts src/registry/contracts/projectLibraries.spec.ts src/registry/extensions/homeProjects/index.ts src/registry/extensions/settings/index.ts src/unitTestUtils.tsnpx biome check --formatter-enabled=true --linter-enabled=false --assist-enabled=false --files-ignore-unknown=true src/lib/app.ts src/lib/app.spec.ts src/lib/cloudSync/index.test.ts src/lib/cloudSync/paths.ts src/lib/cloudSync/registry/plugin.spec.tsx src/lib/projectLibraries/settings/ProjectLibrariesSetting.tsx src/lib/projectLibraries/settings/ProjectLibrariesSettingInput.tsx src/lib/projectLibraries/settings/ProjectLibrariesSettingInput.spec.tsx src/lib/routeLoaders.ts src/lib/settings/settingsUtils.ts src/machines/settingsMachine.ts src/registry/contracts/projectLibraries.ts src/registry/contracts/projectLibraries.spec.ts src/registry/extensions/homeProjects/index.ts src/registry/extensions/settings/index.ts src/unitTestUtils.tsgit diff --check