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 #7902

Draft
wants to merge 53 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
46c524c
wip
eanders-ms Nov 23, 2020
cc33cf2
wip
darzu Dec 1, 2020
010da76
show icon for cloud projects
darzu Dec 1, 2020
5f8085b
remove debug statements
darzu Dec 1, 2020
e15f586
investigative changes
darzu Dec 3, 2020
195b4e1
trying out cloudworkspace again
darzu Dec 4, 2020
20328c6
add browserdbworkspace.ts
darzu Dec 4, 2020
6909468
refactor browser workspace to build off more pure table db worksapce
darzu Dec 4, 2020
1c81516
error TOOO
darzu Dec 7, 2020
b19911d
debug logging
darzu Dec 7, 2020
c975d5d
create workspaces/ folder
darzu Dec 7, 2020
3ff57dd
refactor setupWorkspace into pure chooseWorkspace
darzu Dec 8, 2020
a5063a7
export
darzu Dec 8, 2020
423fe0a
cloud debug logging
darzu Dec 8, 2020
7c73231
debugging and type cleanup
darzu Dec 8, 2020
142b6c6
investigative comments
darzu Dec 8, 2020
b64be99
starting JointWorkspace
darzu Dec 8, 2020
631f200
toying with sync workspace
darzu Dec 9, 2020
c0fd88f
trying out joint workspace
darzu Dec 9, 2020
6d05fa5
experimenting
darzu Dec 9, 2020
98d30cb
unreachable helper
darzu Dec 9, 2020
c7bed33
header comments
darzu Dec 9, 2020
ffdcbad
debug logging
darzu Dec 9, 2020
0300ad1
rename
darzu Dec 9, 2020
7da5f13
taking a stab at synchronization
darzu Dec 9, 2020
dfbd3db
wip on sync
darzu Dec 10, 2020
a7523ad
trying cloud sync workspace again
darzu Dec 11, 2020
bc8a1a3
lots of work on cloud sync
darzu Dec 12, 2020
b8e8393
much better joint workspace
darzu Dec 13, 2020
f8201ce
fix build issue
darzu Dec 14, 2020
6939562
fix lint issues
darzu Dec 14, 2020
e6c3f9b
lots of debugging
darzu Dec 16, 2020
94605ea
debugging
darzu Dec 16, 2020
592c1ec
horrible debugging
darzu Dec 17, 2020
7971ff3
fix project transfer & debugging
darzu Dec 17, 2020
88717cf
fixining sync
darzu Dec 18, 2020
d711126
fix debug crash
darzu Dec 19, 2020
71941fd
debugging
darzu Dec 21, 2020
ae41778
big progress on race conditions & sanity
darzu Dec 24, 2020
be015c5
deprecate allscripts
darzu Dec 24, 2020
e83fd6e
investigative comments and todos
darzu Dec 28, 2020
8700481
reworked headers hash (formerly last-mod-time)
darzu Dec 29, 2020
49fb645
todo list and progress on syncAsync
darzu Dec 29, 2020
6b388a8
return headers[] from sync; finer grain virtual api inval
darzu Jan 2, 2021
e970d53
better names
darzu Jan 2, 2021
bb676aa
unify and fix up maybeSyncHeadersAsync, refreshHeadersSession and syn…
darzu Jan 3, 2021
a62252d
undo typo
darzu Jan 3, 2021
1d52319
debugging spurious saves
darzu Jan 4, 2021
a3155bd
first-save TODOs
darzu Jan 4, 2021
d70f46a
debugging empty saves
darzu Jan 4, 2021
0ea5813
fix issues with getTextAsync and lookup(); investigating double save …
darzu Jan 4, 2021
1e93dd1
handling 404s from the cloud
darzu Jan 4, 2021
6285fa3
thinking about a fresh start
darzu Feb 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 14 additions & 7 deletions localtypings/projectheader.d.ts
Expand Up @@ -28,23 +28,30 @@ 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 {
id: string; // guid (generated by us)
path?: string; // for workspaces that require it
recentUse: number; // seconds since epoch
modificationTime: number; // seconds since epoch
recentUse: number; // seconds since epoch UTC (cloud safe)
modificationTime: number; // seconds since epoch UTC (cloud safe)
icon?: string; // icon uri

isDeleted: boolean; // mark whether or not a header has been deleted
saveId?: any; // used to determine whether a project has been edited while we're saving to cloud

// TODO @darzu: remove all of these?

// For cloud providers
blobId: string; // id of the cloud blob holding this script
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
blobVersion_: string; // version of the cloud blob
blobCurrent_: boolean; // has the current version of the script been pushed to cloud

cloudVersion: string; // The cloud-assigned version number (e.g. etag)
// TODO @darzu: "cloudCurrent" seems very bad. This is a stateful notation and it is hard to reason about whether or not this is true.
cloudCurrent: boolean; // Has the current version of the project been pushed to cloud

// Used for Updating projects
backupRef?: string; // guid of backed-up project (present if an update was interrupted)
Expand Down
2 changes: 2 additions & 0 deletions localtypings/pxtpackage.d.ts
Expand Up @@ -2,6 +2,7 @@ declare namespace pxt {

type CodeCardType = "file" | "example" | "codeExample" | "tutorial" | "side" | "template" | "package" | "hw" | "forumUrl" | "forumExample" | "sharedExample";
type CodeCardEditorType = "blocks" | "js" | "py";
type CodeCardCloudState = "local" | "cloud";

interface Map<T> {
[index: string]: T;
Expand Down Expand Up @@ -159,6 +160,7 @@ declare namespace pxt {
cardType?: CodeCardType;
editor?: CodeCardEditorType;
otherActions?: CodeCardAction[];
cloudState?: CodeCardCloudState;

header?: string;

Expand Down
5 changes: 2 additions & 3 deletions pxteditor/editor.ts
Expand Up @@ -215,12 +215,11 @@ namespace pxt.editor {
importExampleAsync(options: ExampleImportOptions): Promise<void>;
showScriptManager(): void;
importProjectDialog(): void;
cloudSync(): boolean;
cloudSignInDialog(): void;
cloudSignOut(): void;
removeProject(): void;
editText(): void;

hasCloudSync(): boolean;

getPreferredEditor(): string;
saveAndCompile(): void;
updateHeaderName(name: string): void;
Expand Down
1 change: 1 addition & 0 deletions pxteditor/localStorage.ts
@@ -1,4 +1,5 @@
namespace pxt.storage {
// TODO @darzu: why is this different from the WorkspaceProvider api?
interface IStorage {
removeItem(key: string): void;
getItem(key: string): string;
Expand Down
24 changes: 20 additions & 4 deletions pxteditor/workspace.ts
Expand Up @@ -3,6 +3,8 @@
namespace pxt.workspace {
export type ScriptText = pxt.Map<string>;


// TODO @darzu: ugh. why is there a "Project" that is different from a "File". They are nearly identical...
export interface Project {
header?: Header;
text?: ScriptText;
Expand All @@ -14,17 +16,28 @@ namespace pxt.workspace {
url: string;
}

// TODO @darzu: why is version "any" ? that's really annoying to reason about. used as: string | ScriptText
// TODO @darzu: _rev is a string; modificationTime is an int
export type Version = any;

export interface File {
header: Header;
text: ScriptText;
// This version field is reserved for the storage mechanism. E.g. PouchDB requires a _rev field containing
// the currently stored version.
version: Version;
}

export interface WorkspaceProvider {
listAsync(): Promise<Header[]>; // called from workspace.syncAsync (including upon startup)
listAsync(): Promise<Header[]>;
/*
Tries to get the corrisponding File with the current version if it exists.
If it does not exist, returns undefined.
*/
getAsync(h: Header): Promise<File>;
/*
If text is empty, then only update the header.
*/
setAsync(h: Header, prevVersion: Version, text?: ScriptText): Promise<Version>;
deleteAsync?: (h: Header, prevVersion: Version) => Promise<void>;
resetAsync(): Promise<void>;
Expand Down Expand Up @@ -54,9 +67,12 @@ namespace pxt.workspace {
id: U.guidGen(),
recentUse: modTime,
modificationTime: modTime,
blobId: null,
blobVersion: null,
blobCurrent: false,
blobId_: null,
blobVersion_: null,
blobCurrent_: false,
cloudUserId: null,
cloudCurrent: false,
cloudVersion: null,
isDeleted: false,
}
return header
Expand Down
4 changes: 4 additions & 0 deletions pxtlib/util.ts
Expand Up @@ -1409,6 +1409,10 @@ namespace ts.pxtc.Util {
return res
})
}

export function unreachable(...ns: never[]): never {
throw new Error("Type error: this code should be unreachable");
}
}

namespace ts.pxtc.BrowserImpl {
Expand Down
7 changes: 7 additions & 0 deletions src/store/store.js
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.helloWorld = void 0;
function helloWorld() {
console.log("hello, world!");
}
exports.helloWorld = helloWorld;
4 changes: 4 additions & 0 deletions src/store/store.ts
@@ -0,0 +1,4 @@

export function helloWorld() {
console.log("hello, world!");
}
70 changes: 70 additions & 0 deletions src/tsconfig.json
@@ -0,0 +1,70 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */

/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */

/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */

/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */

/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */

/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}
27 changes: 27 additions & 0 deletions webapp/public/skillmap.html
@@ -0,0 +1,27 @@
<!doctype html>
<html lang="@locale@">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>MakeCode Skill Map</title>
<link rel="stylesheet" data-rtl="/blb/rtlsemantic.css" href="/blb/semantic.css">
<link href="/blb/skillmap/css/main.7bac9166.chunk.css" rel="stylesheet"></head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

<!-- @include tracking.html -->
<!-- @include tickevent.html -->

<!-- target.js is generated by the CLI -->
<script type="text/javascript" src="/blb/target.js"></script>
<script type="text/javascript" src="/blb/pxtlib.js"></script>

<div id="root"></div>

<!-- begin usabilla live embed code -->
<script type="text/javascript">window.lightningjs||function(s){function e(e,n){var t,v,f,i,a,r;return n&&(n+=(/\?/.test(n)?"&":"?")+"lv=1"),s[e]||(t=window,v=document,f=e,i=v.location.protocol,a="load",r=0,function(){function e(){h.P(a),h.w=1,s[f]("_load")}s[f]=function(){function o(){return o.id=d,s[f].apply(o,arguments)}var e,d=++r;return e=this&&this!=t&&this.id||0,(h.s=h.s||[]).push([d,e,arguments]),o.then=function(e,n,t){var i=h.fh[d]=h.fh[d]||[],a=h.eh[d]=h.eh[d]||[],r=h.ph[d]=h.ph[d]||[];return e&&i.push(e),n&&a.push(n),t&&r.push(t),o},o};var h=s[f]._={};h.fh={},h.eh={},h.ph={},h.l=n?n.replace(/^\/\//,("https:"==i?i:"http:")+"//"):n,h.p={0:+new Date},h.P=function(e){h.p[e]=new Date-h.p[0]},h.w&&e(),t.addEventListener?t.addEventListener(a,e,!1):t.attachEvent("on"+a,e);var p=function(){function n(){return["<head></head><",e,' onload="var d=',c,";d.getElementsByTagName('head')[0].",a,"(d.",r,"('script')).",o,"='",h.l,"'\"></",e,">"].join("")}var e="body",t=v[e];if(!t)return setTimeout(p,100);h.P(1);var i,a="appendChild",r="createElement",o="src",d=v[r]("div"),s=d[a](v[r]("div")),l=v[r]("iframe"),c="document";d.style.display="none",t.insertBefore(d,t.firstChild).id=w+"-"+f,l.frameBorder="0",l.id=w+"-frame-"+f,/MSIE[ ]+6/.test(navigator.userAgent)&&(l[o]="javascript:false"),l.allowTransparency="true",s[a](l);try{l.contentWindow[c].open()}catch(e){h.domain=v.domain,i="javascript:var d="+c+".open();d.domain='"+v.domain+"';",l[o]=i+"void(0);"}try{var u=l.contentWindow[c];u.write(n()),u.close()}catch(e){l[o]=i+'d.write("'+n().replace(/"/g,String.fromCharCode(92)+'"')+'");d.close();'}h.P(2)};h.l&&setTimeout(p,0)}()),s[e].lv="1",s[e]}var w="lightningjs",n=window[w]=e(w);n.require=e,n.modules=s}({}),window.usabilla_live=lightningjs.require("usabilla_live","//w.usabilla.com/1bba04d66c15.js")</script>
<!-- end usabilla live embed code -->

<!-- @include thin-footer.html -->
<script>!function(a){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],l=0,i=[];l<n.length;l++)t=n[l],Object.prototype.hasOwnProperty.call(f,t)&&f[t]&&i.push(f[t][0]),f[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(a[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),p()}function p(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==f[u]&&(n=!1)}n&&(c.splice(r--,1),e=l(l.s=t[0]))}return e}var t={},f={1:0},c=[];function l(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return a[e].call(r.exports,r,r.exports,l),r.l=!0,r.exports}l.m=a,l.c=t,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(r,e){if(1&e&&(r=l(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)l.d(t,n,function(e){return r[e]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var r=window.webpackJsonpskillsmap=window.webpackJsonpskillsmap||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;p()}([])</script><script src="/blb/skillmap/js/2.0080f766.chunk.js"></script><script src="/blb/skillmap/js/main.173a5af5.chunk.js"></script></body>
</html>
2 changes: 1 addition & 1 deletion webapp/public/vs/editor/editor.main.css

Large diffs are not rendered by default.