Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Workspace layer refactor #7657

Closed
wants to merge 52 commits into from
Closed

[DRAFT] Workspace layer refactor #7657

wants to merge 52 commits into from

Conversation

darzu
Copy link
Contributor

@darzu darzu commented Nov 23, 2020

While working on cloud sync, I ended up discovering a bunch of inconsistencies and potential race conditions and other problems in our workspace layering, so I've started a clean up and refactor of that area of the code.

This is going on the back-burner however and we're going to take a simpler, incremental approach to cloud sync for now here: #7743

EDIT: closed and reopened here: #7902

@@ -28,7 +28,8 @@ declare namespace pxt.workspace {
tutorialCompleted?: pxt.tutorial.TutorialCompletionInfo;
// workspace guid of the extension under test
extensionUnderTest?: string;
cloudSync?: boolean; // Mark a header for syncing with a cloud provider
Copy link
Contributor Author

@darzu darzu Nov 23, 2020

Choose a reason for hiding this comment

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

note:
was used to determine if a project was cloud synced (old Sam work?)
problem was it didn't distinguish account A or B

@@ -28,7 +28,8 @@ declare namespace pxt.workspace {
tutorialCompleted?: pxt.tutorial.TutorialCompletionInfo;
// workspace guid of the extension under test
extensionUnderTest?: string;
cloudSync?: boolean; // Mark a header for syncing with a cloud provider
// id of cloud user who created this project
cloudUserId?: string;
}

export interface Header extends InstallHeader {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

header is meta info for a project

blobCurrent_: boolean; // has the current version of the script been pushed to cloud

cloudVersion: string; // The cloud-assigned version number (e.g. etag)
cloudCurrent: boolean; // Has the current version of the project been pushed to cloud
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO: do we need / how do we use cloudCurrent exactly?

blobVersion: string; // version of the cloud blob
blobCurrent: boolean; // has the current version of the script been pushed to cloud
// For cloud providers -- DEPRECATED
blobId_: string; // id of the cloud blob holding this script
Copy link
Contributor Author

Choose a reason for hiding this comment

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

note that "project id" is assigned by client and its user ID + project ID. Note "id" field

@@ -215,12 +215,11 @@ namespace pxt.editor {
importExampleAsync(options: ExampleImportOptions): Promise<void>;
showScriptManager(): void;
importProjectDialog(): void;
cloudSync(): boolean;
cloudSignInDialog(): void;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

cloudSignInDialog is unneeded because we have new dialog

removeProject(): void;
editText(): void;

hasCloudSync(): boolean;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

renamed from cloudSync to find usages

checks to see if we're signed in.

@@ -28,7 +28,8 @@ declare namespace pxt.workspace {
tutorialCompleted?: pxt.tutorial.TutorialCompletionInfo;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is the difference between "Header" and "InstallHeader" ?

@@ -3090,6 +3036,10 @@ export class ProjectView
}
}

hasCloudSync() {
return this.isLoggedIn();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: maybe once we go to AAD we might not be able to store data ourselves and we might need OneDrive? Probably worth adding a TODO comment

@@ -4545,7 +4495,8 @@ document.addEventListener("DOMContentLoaded", () => {
else if (isSandbox) workspace.setupWorkspace("mem");
else if (pxt.winrt.isWinRT()) workspace.setupWorkspace("uwp");
else if (pxt.BrowserUtils.isIpcRenderer()) workspace.setupWorkspace("idb");
else if (pxt.BrowserUtils.isLocalHost() || pxt.BrowserUtils.isPxtElectron()) workspace.setupWorkspace("fs");
//else if (pxt.BrowserUtils.isLocalHost() || pxt.BrowserUtils.isPxtElectron()) workspace.setupWorkspace("fs");
Copy link
Contributor Author

@darzu darzu Nov 23, 2020

Choose a reason for hiding this comment

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

TODO uncomment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this disabled the filesystem workspace

}

function deleteAsync(h: Header, prevVersion: Version, text?: ScriptText): Promise<void> {
return Promise.resolve();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

add comment that this is intentionally left unimplemented ?

}

function resetAsync(): Promise<void> {
return Promise.resolve();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO: need to implement

return Promise.resolve();
}

export async function syncAsync(): Promise<any> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

modeled after: cloudsync.ts:syncAsync

Copy link
Contributor Author

Choose a reason for hiding this comment

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

bi-directional,
looks at local cloud project headers (with matching user IDs)
looks at remote headers
resolves them

workspace.saveAsync(file.header, file.text, file.version);
} else {
// Conflict.
// TODO: Figure out how to register these.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need to show cloud status on the cards

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See Cloud Sync OneNote

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we need timestamps or incremental version numbers? Or the user in the loop?
LastWrite wins?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hunch: auto-handling merges would be heavier lift and harder to get right than presenting options to user.

const FIELD_WORKING = "working";
export const UPLOADING = `${MODULE}:${FIELD_UPLOADING}`;
export const DOWNLOADING = `${MODULE}:${FIELD_DOWNLOADING}`;
export const WORKING = `${MODULE}:${FIELD_WORKING}`;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

note these are activity flags globally.. maybe we want per-project? TBD

@@ -501,7 +503,7 @@ export function refreshToken() {
}

export function syncAsync(): Promise<void> {
return Promise.all([githubSyncAsync(), cloudSyncAsync()])
return Promise.all([githubSyncAsync(), cloud.syncAsync()])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

note important change: instead of local cloudSyncAsync function, we're pointing to new cloud.syncAsync

@@ -405,14 +405,14 @@ export class EditorPackage {
}

savePkgAsync() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Notes:
Work to do to work with our cloud stuff?
Switch blobCurrent to cloudCurrent ?

When you create a new project, it currently doesn't sync to the cloud. This might be responsible.. TBD

@@ -480,7 +475,7 @@ export class ProjectsCarousel extends data.Component<ProjectsCarouselProps, Proj
}

fetchLocalData(): pxt.workspace.Header[] {
const headers: pxt.workspace.Header[] = this.getData("header:*")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note this was only fetching local headers... but it is called fetchLocal.. is it supposed to be local or cloud+local?

@@ -184,11 +185,11 @@ export class ScriptManagerDialog extends data.Component<ScriptManagerDialogProps
.then(text => workspace.duplicateAsync(header, text, res))
.then(clonedHeader => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

called when you say "view all projects"

@@ -25,14 +25,9 @@ type Header = pxt.workspace.Header;
type ScriptText = pxt.workspace.ScriptText;
type WorkspaceProvider = pxt.workspace.WorkspaceProvider;
type InstallHeader = pxt.workspace.InstallHeader;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

NOTE about this file: this operates on a layer agnostic of the specific workspace; it uses the interfaces

let r = allScripts.map(e => e.header).filter(h =>
(withDeleted || !h.isDeleted) &&
!h.isBackup &&
(!h.cloudUserId || h.cloudUserId === cloudUserId))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

note this is now responsible for including cloud projects if signed in

let r = allScripts.map(e => e.header).filter(h =>
(withDeleted || !h.isDeleted) &&
!h.isBackup &&
(!h.cloudUserId || h.cloudUserId === cloudUserId))
r.sort((a, b) => b.recentUse - a.recentUse)
return r
}
Copy link
Contributor Author

@darzu darzu Nov 23, 2020

Choose a reason for hiding this comment

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

Some thoughts on merging two workspaces (instead of layer cloud on top of workspace-agnostic layer):

  • This was the path Sam and Peli took
  • Might be easier to work offline if we're not merging workspaces?
    • or maybe not?

@@ -1352,21 +1335,6 @@ export function saveToCloudAsync(h: Header) {
return cloudsync.saveToCloudAsync(h)
}

export function resetCloudAsync(): Promise<void> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this wasn't used?

@pelikhan
Copy link
Member

draft PR?

@darzu
Copy link
Contributor Author

darzu commented Nov 30, 2020

draft PR?

Yes, I accidentally created it as non-draft and I don't see a way to demote it :(

@jwunderl
Copy link
Member

Under 'reviewers' there should be an option, it's a bit hidden (only shows as clickable on hover):

image

@pelikhan
Copy link
Member

very hidden

@darzu darzu changed the title [DRAFT] Client changes for cloud sync [DRAFT] Workspace layer refactor Jan 4, 2021
@darzu
Copy link
Contributor Author

darzu commented Feb 20, 2021

moved here: #7902

@darzu darzu closed this Feb 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants