From 1bf097d5d9c4eb52658d3637d55b8f9e7348eb8e Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Tue, 8 Sep 2020 12:21:30 +0000 Subject: [PATCH 01/18] Deal with binary files --- .../app/overmind/namespaces/git/actions.ts | 104 +++++++++--------- packages/common/src/types/index.ts | 5 +- 2 files changed, 56 insertions(+), 53 deletions(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index a8548d825b7..aebdbec3c85 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -479,71 +479,25 @@ export const resolveOutOfSync: AsyncAction = async ({ effects.analytics.track('GitHub - Resolve out of sync'); const git = state.git; const { added, deleted, modified } = git.outOfSyncUpdates; - git.isResolving = true; - if (added.length) { - await actions.files.createModulesByPath({ - files: added.reduce((aggr, change) => { - aggr[change.filename] = { content: change.content }; - - return aggr; - }, {}), - }); - // We optimistically keep source in sync - added.forEach(change => { - git.sourceModulesByPath['/' + change.filename] = change.content!; - }); - } - if (deleted.length) { - await Promise.all( - deleted.map(change => { - const module = state.editor.modulesByPath['/' + change.filename]; - - return actions.files.moduleDeleted({ moduleShortid: module.shortid }); - }) - ); - // We optimistically keep source in sync - deleted.forEach(change => { - delete git.sourceModulesByPath['/' + change.filename]; - }); - } - if (modified.length) { - await Promise.all( - modified.map(change => { - const module = state.editor.modulesByPath['/' + change.filename]; - - actions.editor.setCode({ - moduleShortid: module.shortid, - code: change.content!, - }); - return actions.editor.codeSaved({ - moduleShortid: module.shortid, - code: change.content!, - cbID: null, - }); - }) - ); - // We optimistically keep source in sync - modified.forEach(change => { - git.sourceModulesByPath['/' + change.filename] = change.content!; - }); - } + git.isResolving = true; const sandbox = state.editor.currentSandbox!; - // When we have a PR and the source is out of sync with base, we need to create a commit to update it + // When we have a PR and the source is out of sync with base, we need to create a commit to update it. We do this + // first, because we need the new source to deal with binary files if (git.gitState === SandboxGitState.OUT_OF_SYNC_PR_BASE) { const changes: GitChanges = { added: added.map(change => ({ path: '/' + change.filename, content: change.content!, - encoding: 'utf-8', + encoding: change.isBinary ? 'base64' : 'utf-8', })), deleted: deleted.map(change => '/' + change.filename), modified: modified.map(change => ({ path: '/' + change.filename, content: change.content!, - encoding: 'utf-8', + encoding: change.isBinary ? 'base64' : 'utf-8', })), }; const commit = await effects.api.createGitCommit( @@ -568,6 +522,52 @@ export const resolveOutOfSync: AsyncAction = async ({ await actions.git._loadSourceSandbox(); + if (added.length) { + await actions.files.createModulesByPath({ + files: added.reduce((aggr, change) => { + aggr[change.filename] = change.isBinary + ? { + content: git.sourceModulesByPath['/' + change.filename], + isBinary: true, + } + : { content: change.content }; + + return aggr; + }, {}), + }); + } + + if (deleted.length) { + await Promise.all( + deleted.map(change => { + const module = state.editor.modulesByPath['/' + change.filename]; + + return actions.files.moduleDeleted({ moduleShortid: module.shortid }); + }) + ); + } + if (modified.length) { + await Promise.all( + modified.map(change => { + const module = state.editor.modulesByPath['/' + change.filename]; + + actions.editor.setCode({ + moduleShortid: module.shortid, + code: change.isBinary + ? git.sourceModulesByPath['/' + change.filename] + : change.content!, + }); + return actions.editor.codeSaved({ + moduleShortid: module.shortid, + code: change.isBinary + ? git.sourceModulesByPath['/' + change.filename] + : change.content!, + cbID: null, + }); + }) + ); + } + actions.git._setGitChanges(); git.outOfSyncUpdates.added = []; git.outOfSyncUpdates.deleted = []; @@ -620,6 +620,7 @@ export const _evaluateGitChanges: AsyncAction< if ( change.status === 'removed' && state.editor.modulesByPath[path] && + !(state.editor.modulesByPath[path] as Module).isBinary && (state.editor.modulesByPath[path] as Module).code !== change.content ) { return aggr.concat(change); @@ -634,6 +635,7 @@ export const _evaluateGitChanges: AsyncAction< // We are in conflict if the source changed the file and sandbox also changed the file if ( change.status === 'modified' && + !(state.editor.modulesByPath[path] as Module).isBinary && (state.editor.modulesByPath[path] as Module).code !== change.content && (state.editor.modulesByPath[path] as Module).code !== state.git.sourceModulesByPath[path] diff --git a/packages/common/src/types/index.ts b/packages/common/src/types/index.ts index e31cd2fe733..a585ba7dc0b 100644 --- a/packages/common/src/types/index.ts +++ b/packages/common/src/types/index.ts @@ -301,6 +301,7 @@ export type GitFileCompare = { deletions: number; filename: string; status: 'added' | 'modified' | 'removed'; + isBinary: boolean; content?: string; }; @@ -715,12 +716,12 @@ export type GitPathChanges = { }; export type GitChanges = { - added: Array<{ path: string; content: string; encoding: 'utf-8' | 'binary' }>; + added: Array<{ path: string; content: string; encoding: 'utf-8' | 'base64' }>; deleted: string[]; modified: Array<{ path: string; content: string; - encoding: 'utf-8' | 'binary'; + encoding: 'utf-8' | 'base64'; }>; }; From 1aa36c4d57a208c5d905ea4104c37d8c1a7b8898 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Thu, 10 Sep 2020 13:38:44 +0000 Subject: [PATCH 02/18] Add uploadId --- packages/app/package.json | 2 +- .../app/overmind/namespaces/git/actions.ts | 29 ++++++++++++------- .../src/app/overmind/namespaces/git/state.ts | 8 ++++- packages/common/src/types/index.ts | 1 + yarn.lock | 16 +++++++++- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index bd6cedadcb9..5e9e789d9df 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -107,7 +107,7 @@ "circular-json": "^0.4.0", "codemirror": "^5.27.4", "codesandbox-api": "0.0.24", - "codesandbox-import-utils": "^2.1.14", + "codesandbox-import-utils": "^2.2.0", "color": "^0.11.4", "compare-versions": "^3.1.0", "console": "^0.7.2", diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index aebdbec3c85..32b73b8eaf7 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -237,10 +237,10 @@ export const createCommitClicked: AsyncAction = async ({ : [git.sourceCommitSha!] ); changes.added.forEach(change => { - git.sourceModulesByPath[change.path] = change.content; + git.sourceModulesByPath[change.path].code = change.content; }); changes.modified.forEach(change => { - git.sourceModulesByPath[change.path] = change.content; + git.sourceModulesByPath[change.path].code = change.content; }); changes.deleted.forEach(path => { delete git.sourceModulesByPath[path]; @@ -324,10 +324,10 @@ export const createPrClicked: AsyncAction = async ({ ); changes.added.forEach(change => { - git.sourceModulesByPath[change.path] = change.content; + git.sourceModulesByPath[change.path].code = change.content; }); changes.modified.forEach(change => { - git.sourceModulesByPath[change.path] = change.content; + git.sourceModulesByPath[change.path].code = change.content; }); changes.deleted.forEach(path => { delete git.sourceModulesByPath[path]; @@ -418,7 +418,9 @@ export const addConflictedFile: AsyncAction = async ( [conflict.filename]: { content: conflict.content!, isBinary: false }, }, }); - state.git.sourceModulesByPath['/' + conflict.filename] = conflict.content!; + state.git.sourceModulesByPath[ + '/' + conflict.filename + ].code = conflict.content!; state.git.conflictsResolving.splice( state.git.conflictsResolving.indexOf(conflict.filename), @@ -527,8 +529,9 @@ export const resolveOutOfSync: AsyncAction = async ({ files: added.reduce((aggr, change) => { aggr[change.filename] = change.isBinary ? { - content: git.sourceModulesByPath['/' + change.filename], + content: git.sourceModulesByPath['/' + change.filename].code, isBinary: true, + uploadId: git.sourceModulesByPath['/' + change.filename].uploadId, } : { content: change.content }; @@ -554,13 +557,13 @@ export const resolveOutOfSync: AsyncAction = async ({ actions.editor.setCode({ moduleShortid: module.shortid, code: change.isBinary - ? git.sourceModulesByPath['/' + change.filename] + ? git.sourceModulesByPath['/' + change.filename].code : change.content!, }); return actions.editor.codeSaved({ moduleShortid: module.shortid, code: change.isBinary - ? git.sourceModulesByPath['/' + change.filename] + ? git.sourceModulesByPath['/' + change.filename].code : change.content!, cbID: null, }); @@ -592,7 +595,7 @@ export const _setGitChanges: Action = ({ state }) => { changes.added.push(module.path); } else if ( !module.isBinary && - state.git.sourceModulesByPath[module.path] !== module.code + state.git.sourceModulesByPath[module.path].code !== module.code ) { changes.modified.push(module.path); } @@ -638,7 +641,7 @@ export const _evaluateGitChanges: AsyncAction< !(state.editor.modulesByPath[path] as Module).isBinary && (state.editor.modulesByPath[path] as Module).code !== change.content && (state.editor.modulesByPath[path] as Module).code !== - state.git.sourceModulesByPath[path] + state.git.sourceModulesByPath[path].code ) { return aggr.concat(change); } @@ -714,7 +717,11 @@ export const _loadSourceSandbox: AsyncAction = async ({ state, effects }) => { ); module.path = path; if (path) { - aggr[path] = module.code; + aggr[path] = { + code: module.code, + isBinary: module.isBinary, + uploadId: module.uploadId, + }; } return aggr; diff --git a/packages/app/src/app/overmind/namespaces/git/state.ts b/packages/app/src/app/overmind/namespaces/git/state.ts index cd25f8a7236..e4a98764f67 100755 --- a/packages/app/src/app/overmind/namespaces/git/state.ts +++ b/packages/app/src/app/overmind/namespaces/git/state.ts @@ -23,7 +23,13 @@ type State = { sourceGitChanges: { [path: string]: GitFileCompare; }; - sourceModulesByPath: { [path: string]: string }; + sourceModulesByPath: { + [path: string]: { + code: string; + isBinary: boolean; + uploadId?: string; + }; + }; permission: 'admin' | 'write' | 'read'; conflictsResolving: string[]; outOfSyncUpdates: { diff --git a/packages/common/src/types/index.ts b/packages/common/src/types/index.ts index a585ba7dc0b..accc237f6f2 100644 --- a/packages/common/src/types/index.ts +++ b/packages/common/src/types/index.ts @@ -65,6 +65,7 @@ export type Module = { insertedAt: string; updatedAt: string; path: string; + uploadId?: string; type: 'file'; }; diff --git a/yarn.lock b/yarn.lock index 5916d65485f..37f81474c9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9001,7 +9001,12 @@ codesandbox-import-util-types@^2.1.9: resolved "https://registry.yarnpkg.com/codesandbox-import-util-types/-/codesandbox-import-util-types-2.1.9.tgz#24ba5ec3d966f51f18b78c48d32e6411da90aa74" integrity sha512-Vc4qh+neVfHtS3RG+7wvaErMoEKdNTnLFnyj4Dcbn3NV7v9nlPj/z6MGhHp9S+vAjegWorFzxg9lKB1WGHTt5Q== -codesandbox-import-utils@^2.1.14, codesandbox-import-utils@^2.1.9: +codesandbox-import-util-types@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/codesandbox-import-util-types/-/codesandbox-import-util-types-2.2.0.tgz#f94799f83838a1e8ba776189a8275870d6579ab6" + integrity sha512-EFXFKCSE7I2VABNa11cgkFJAY8MQCMDhD147xntXw4O/wg5DkGmvor9s0bpk4IYlTOVwZT86H0My1xRhkIzHOA== + +codesandbox-import-utils@^2.1.9: version "2.1.14" resolved "https://registry.yarnpkg.com/codesandbox-import-utils/-/codesandbox-import-utils-2.1.14.tgz#b8222d95208048173ddc754f00618dde5e892eda" integrity sha512-IOV1lk/hEnp6KV4uuHvfjrdIbYSVx11WXr75ABjHPuBh117AgKEbujTduoAChDuEofevV6GwlIyl32EBNECE1Q== @@ -9010,6 +9015,15 @@ codesandbox-import-utils@^2.1.14, codesandbox-import-utils@^2.1.9: istextorbinary "^2.2.1" lz-string "^1.4.4" +codesandbox-import-utils@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/codesandbox-import-utils/-/codesandbox-import-utils-2.2.0.tgz#281b4449746b411cca8934b93fd1817cb4a3e898" + integrity sha512-d2sQnwbsegkjmx6x2Q7RBiLPtSDBKQHSQgekU6h8AimtaNO9d/nc/jWWR/kMnB+T6NorUxCpmoLtHWDqBihFRw== + dependencies: + codesandbox-import-util-types "^2.2.0" + istextorbinary "^2.2.1" + lz-string "^1.4.4" + codesandbox@^2.1.10: version "2.1.10" resolved "https://registry.yarnpkg.com/codesandbox/-/codesandbox-2.1.10.tgz#61cd1ae35b62dd99aae829085335f6270fb514d0" From e6789f6262a84eda83144bc4c347e84e089c84b6 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Fri, 11 Sep 2020 07:38:33 +0000 Subject: [PATCH 03/18] Properly load source on commits to update --- .../app/overmind/namespaces/files/actions.ts | 57 +++---- .../app/overmind/namespaces/git/actions.ts | 148 +++++++++--------- 2 files changed, 100 insertions(+), 105 deletions(-) diff --git a/packages/app/src/app/overmind/namespaces/files/actions.ts b/packages/app/src/app/overmind/namespaces/files/actions.ts index 0275f7f1713..d735d0eeefa 100755 --- a/packages/app/src/app/overmind/namespaces/files/actions.ts +++ b/packages/app/src/app/overmind/namespaces/files/actions.ts @@ -1,7 +1,7 @@ import { getDirectoryPath, getModulePath, - getModulesAndDirectoriesInDirectory, + getModulesAndDirectoriesInDirectory } from '@codesandbox/common/lib/sandbox/modules'; import getDefinition from '@codesandbox/common/lib/templates'; import { Directory, Module, UploadFile } from '@codesandbox/common/lib/types'; @@ -15,7 +15,7 @@ import denormalize from 'codesandbox-import-utils/lib/utils/files/denormalize'; import { resolveDirectoryWrapped, - resolveModuleWrapped, + resolveModuleWrapped } from '../../utils/resolve-module-wrapped'; import * as internalActions from './internalActions'; @@ -33,13 +33,13 @@ export const applyRecover: Action { actions.editor.codeChanged({ moduleShortid: module.shortid, - code: recoverData.code, + code: recoverData.code }); effects.vscode.setModuleCode(module); }); effects.analytics.track('Files Recovered', { - fileCount: recoveredList.length, + fileCount: recoveredList.length }); }; @@ -56,13 +56,13 @@ export const createRecoverDiffs: Action = async ( } catch (error) { actions.internal.handleError({ message: 'Unable to get uploaded files information', - error, + error }); } }; @@ -491,7 +491,7 @@ export const addedFileToSandbox: AsyncAction = async ( state.uploadedFiles.splice(index, 0, ...removedFiles); actions.internal.handleError({ message: 'Unable to delete uploaded file', - error, + error }); } }; @@ -544,28 +544,29 @@ export const filesUploaded: AsyncAction<{ const { modules, directories } = await actions.files.internal.uploadFiles( { files, - directoryShortid, + directoryShortid } ); actions.files.massCreateModules({ modules, directories, - directoryShortid, + directoryShortid }); effects.executor.updateFiles(sandbox); + actions.git.updateGitChanges(); } catch (error) { if (error.message.indexOf('413') !== -1) { actions.internal.handleError({ message: `The uploaded file is bigger than 7MB, contact hello@codesandbox.io if you want to raise this limit`, error, - hideErrorMessage: true, + hideErrorMessage: true }); } else { actions.internal.handleError({ message: 'Unable to upload files', - error, + error }); } } @@ -631,7 +632,7 @@ export const massCreateModules: AsyncAction<{ actions.internal.handleError({ message: 'Unable to create new files', - error, + error }); } }, @@ -662,7 +663,7 @@ export const moduleCreated: AsyncAction<{ sourceId: sandbox.sourceId, isNotSynced: true, ...(code ? { code } : {}), - ...(typeof isBinary === 'boolean' ? { isBinary } : {}), + ...(typeof isBinary === 'boolean' ? { isBinary } : {}) }); // We have to push the module to the array before we can figure out its path, @@ -733,7 +734,7 @@ export const moduleCreated: AsyncAction<{ actions.internal.handleError({ message: 'Unable to save new file', - error, + error }); } @@ -806,7 +807,7 @@ export const createModulesByPath: AsyncAction<{ modules, directories, directoryShortid: null, - cbID, + cbID }); effects.executor.updateFiles(sandbox); @@ -880,7 +881,7 @@ export const syncSandbox: AsyncAction = async ( actions.internal.handleError({ message: "We weren't able to retrieve the latest files of the sandbox, please refresh", - error, + error }); } diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 2a2dfb9586c..c72cfa1e052 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -4,7 +4,7 @@ import { GitFileCompare, GitInfo, Module, - SandboxGitState, + SandboxGitState } from '@codesandbox/common/lib/types'; import { convertTypeToStatus } from '@codesandbox/common/lib/utils/notifications'; import { hasPermission } from '@codesandbox/common/lib/utils/permission'; @@ -44,7 +44,7 @@ export const repoTitleChanged: Action<{ export const loadGitSource: AsyncAction = async ({ state, actions, - effects, + effects }) => { const sandbox = state.editor.currentSandbox!; state.git.isExported = false; @@ -69,7 +69,7 @@ export const loadGitSource: AsyncAction = async ({ actions.internal.handleError({ error, message: - 'Could not load the source sandbox for this GitHub sandbox, please refresh or report the issue.', + 'Could not load the source sandbox for this GitHub sandbox, please refresh or report the issue.' }); return; } @@ -80,7 +80,7 @@ export const loadGitSource: AsyncAction = async ({ actions.internal.handleError({ error, message: - 'Could not get information about your permissions, please refresh or report the issue.', + 'Could not get information about your permissions, please refresh or report the issue.' }); return; } @@ -93,7 +93,7 @@ export const loadGitSource: AsyncAction = async ({ actions.internal.handleError({ error, message: - 'We were not able to compare the content with the source, please refresh or report the issue.', + 'We were not able to compare the content with the source, please refresh or report the issue.' }); return; } @@ -105,7 +105,7 @@ export const loadGitSource: AsyncAction = async ({ actions.internal.handleError({ error, message: - 'We were not able to compare the content with the PR, please refresh or report the issue.', + 'We were not able to compare the content with the PR, please refresh or report the issue.' }); return; } @@ -118,7 +118,7 @@ export const loadGitSource: AsyncAction = async ({ export const createRepoClicked: AsyncAction = async ({ state, effects, - actions, + actions }) => { effects.analytics.track('GitHub - Create Repo'); const { repoTitle } = state.git; @@ -166,15 +166,15 @@ export const createRepoClicked: AsyncAction = async ({ state.currentModal = null; actions.editor.internal.forkSandbox({ - sandboxId: `github/${git.username}/${git.repo}/tree/${git.branch}/${ - git.path || '' - }`, + sandboxId: `github/${git.username}/${git.repo}/tree/${ + git.branch + }/${git.path || ''}` }); } catch (error) { actions.internal.handleError({ error, message: - 'Unable to create the repo. Please refresh and try again or report issue.', + 'Unable to create the repo. Please refresh and try again or report issue.' }); } }; @@ -186,7 +186,7 @@ export const importFromGithub: AsyncAction = async ( actions.modalClosed(); state.currentModal = 'exportGithub'; await actions.editor.forkExternalSandbox({ - sandboxId: sandboxUrl.replace('/s/', ''), + sandboxId: sandboxUrl.replace('/s/', '') }); state.currentModal = null; }; @@ -203,7 +203,7 @@ export const openSourceSandbox: Action = ({ state, effects }) => { export const createCommitClicked: AsyncAction = async ({ state, effects, - actions, + actions }) => { effects.analytics.track('GitHub - Create Commit'); const sandbox = state.editor.currentSandbox!; @@ -236,18 +236,12 @@ export const createCommitClicked: AsyncAction = async ({ ? [git.sourceCommitSha!, git.baseCommitSha] : [git.sourceCommitSha!] ); - changes.added.forEach(change => { - git.sourceModulesByPath[change.path].code = change.content; - }); - changes.modified.forEach(change => { - git.sourceModulesByPath[change.path].code = change.content; - }); - changes.deleted.forEach((path) => { - delete git.sourceModulesByPath[path]; - }); - actions.git._setGitChanges(); + // We need to load the source again as it has now changed. We can not optimistically deal with + // this, cause you might have added a binary sandbox.originalGit!.commitSha = commit.sha; sandbox.originalGitCommitSha = commit.sha; + await actions.git._loadSourceSandbox(); + actions.git._setGitChanges(); state.git.isCommitting = false; state.git.title = ''; state.git.description = ''; @@ -271,15 +265,15 @@ export const createCommitClicked: AsyncAction = async ({ effects.browser.openWindow( 'docs/git#committing-to-organizations' ); - }, - }, - }, + } + } + } }); } else { actions.internal.handleError({ error, message: - 'We were unable to create your commit. Please try again or report the issue.', + 'We were unable to create your commit. Please try again or report the issue.' }); } } @@ -296,7 +290,7 @@ export const descriptionChanged: Action = ({ state }, description) => { export const createPrClicked: AsyncAction = async ({ state, effects, - actions, + actions }) => { effects.analytics.track('GitHub - Open PR'); const git = state.git; @@ -329,13 +323,13 @@ export const createPrClicked: AsyncAction = async ({ changes.modified.forEach(change => { git.sourceModulesByPath[change.path].code = change.content; }); - changes.deleted.forEach((path) => { + changes.deleted.forEach(path => { delete git.sourceModulesByPath[path]; }); actions.git._setGitChanges(); sandbox.baseGit = { - ...sandbox.originalGit, + ...sandbox.originalGit } as GitInfo; sandbox.baseGitCommitSha = sandbox.originalGit!.commitSha; sandbox.originalGit = { @@ -343,7 +337,7 @@ export const createPrClicked: AsyncAction = async ({ commitSha: pr.commitSha, repo: pr.repo, username: pr.username, - path: '', + path: '' }; sandbox.originalGitCommitSha = pr.commitSha; sandbox.prNumber = pr.number; @@ -367,16 +361,16 @@ export const createPrClicked: AsyncAction = async ({ sandbox.baseGit!.repo }/pull/${sandbox.prNumber!}` ); - }, - }, - }, + } + } + } }); } catch (error) { git.isCreatingPr = false; actions.internal.handleError({ error, message: - 'We were unable to create your PR. Please try again or report the issue.', + 'We were unable to create your PR. Please try again or report the issue.' }); } }; @@ -391,7 +385,7 @@ export const resolveConflicts: AsyncAction = async ( module ) => { const conflict = state.git.conflicts.find( - (conflictItem) => module.path === '/' + conflictItem.filename + conflictItem => module.path === '/' + conflictItem.filename ); if (conflict && module.code.indexOf('<<<<<<< Codesandbox') === -1) { @@ -400,7 +394,7 @@ export const resolveConflicts: AsyncAction = async ( await actions.editor.codeSaved({ moduleShortid: module.shortid, code: module.code, - cbID: null, + cbID: null }); effects.analytics.track('GitHub - Resolve Conflicts'); @@ -415,8 +409,8 @@ export const addConflictedFile: AsyncAction = async ( state.git.conflictsResolving.push(conflict.filename); await actions.files.createModulesByPath({ files: { - [conflict.filename]: { content: conflict.content!, isBinary: false }, - }, + [conflict.filename]: { content: conflict.content!, isBinary: false } + } }); state.git.sourceModulesByPath[ '/' + conflict.filename @@ -469,19 +463,19 @@ export const diffConflictedFile: AsyncAction = async ( actions.editor.setCode({ moduleShortid: module.shortid, - code: createDiff(module.code, conflict.content), + code: createDiff(module.code, conflict.content) }); }; export const resolveOutOfSync: AsyncAction = async ({ state, actions, - effects, + effects }) => { effects.analytics.track('GitHub - Resolve out of sync'); const git = state.git; const { added, deleted, modified } = git.outOfSyncUpdates; - + git.isResolving = true; const sandbox = state.editor.currentSandbox!; @@ -490,17 +484,17 @@ export const resolveOutOfSync: AsyncAction = async ({ // first, because we need the new source to deal with binary files if (git.gitState === SandboxGitState.OUT_OF_SYNC_PR_BASE) { const changes: GitChanges = { - added: added.map((change) => ({ + added: added.map(change => ({ path: '/' + change.filename, content: change.content!, - encoding: change.isBinary ? 'base64' : 'utf-8', + encoding: change.isBinary ? 'base64' : 'utf-8' })), - deleted: deleted.map((change) => '/' + change.filename), - modified: modified.map((change) => ({ + deleted: deleted.map(change => '/' + change.filename), + modified: modified.map(change => ({ path: '/' + change.filename, content: change.content!, - encoding: change.isBinary ? 'base64' : 'utf-8', - })), + encoding: change.isBinary ? 'base64' : 'utf-8' + })) }; const commit = await effects.api.createGitCommit( sandbox.id, @@ -531,12 +525,12 @@ export const resolveOutOfSync: AsyncAction = async ({ ? { content: git.sourceModulesByPath['/' + change.filename].code, isBinary: true, - uploadId: git.sourceModulesByPath['/' + change.filename].uploadId, + uploadId: git.sourceModulesByPath['/' + change.filename].uploadId } : { content: change.content }; return aggr; - }, {}), + }, {}) }); } @@ -558,14 +552,14 @@ export const resolveOutOfSync: AsyncAction = async ({ moduleShortid: module.shortid, code: change.isBinary ? git.sourceModulesByPath['/' + change.filename].code - : change.content!, + : change.content! }); return actions.editor.codeSaved({ moduleShortid: module.shortid, code: change.isBinary ? git.sourceModulesByPath['/' + change.filename].code : change.content!, - cbID: null, + cbID: null }); }) ); @@ -587,10 +581,10 @@ export const _setGitChanges: Action = ({ state }) => { } = { added: [], deleted: [], - modified: [], + modified: [] }; - state.editor.currentSandbox!.modules.forEach((module) => { + state.editor.currentSandbox!.modules.forEach(module => { if (!(module.path in state.git.sourceModulesByPath)) { changes.added.push(module.path); } else if ( @@ -600,7 +594,7 @@ export const _setGitChanges: Action = ({ state }) => { changes.modified.push(module.path); } }); - Object.keys(state.git.sourceModulesByPath).forEach((path) => { + Object.keys(state.git.sourceModulesByPath).forEach(path => { if (!state.editor.modulesByPath[path]) { changes.deleted.push(path); } @@ -687,7 +681,7 @@ export const _evaluateGitChanges: AsyncAction< toUpdate.added.length + toUpdate.modified.length + toUpdate.deleted.length, - conflicts, + conflicts }; }; @@ -720,7 +714,7 @@ export const _loadSourceSandbox: AsyncAction = async ({ state, effects }) => { aggr[path] = { code: module.code, isBinary: module.isBinary, - uploadId: module.uploadId, + uploadId: module.uploadId }; } @@ -733,7 +727,7 @@ export const _loadSourceSandbox: AsyncAction = async ({ state, effects }) => { export const _compareWithSource: AsyncAction = async ({ state, effects, - actions, + actions }) => { const sandbox = state.editor.currentSandbox!; const originalGitCommitSha = sandbox.originalGitCommitSha; @@ -762,7 +756,7 @@ export const _compareWithSource: AsyncAction = async ({ label: 'Resolve', run: () => { actions.workspace.setWorkspaceItem({ item: 'github' }); - }, + } }, secondary: { label: 'See changes', @@ -774,9 +768,9 @@ export const _compareWithSource: AsyncAction = async ({ sandbox.originalGit!.branch }` ); - }, - }, - }, + } + } + } }); effects.preview.refresh(); state.git.gitState = updates.conflicts.length @@ -790,7 +784,7 @@ export const _compareWithSource: AsyncAction = async ({ export const _compareWithBase: AsyncAction = async ({ state, effects, - actions, + actions }) => { const sandbox = state.editor.currentSandbox!; @@ -823,7 +817,7 @@ export const _compareWithBase: AsyncAction = async ({ label: 'Resolve', run: () => { actions.workspace.setWorkspaceItem({ item: 'github' }); - }, + } }, secondary: { label: 'See changes', @@ -835,9 +829,9 @@ export const _compareWithBase: AsyncAction = async ({ sandbox.originalGit!.branch }` ); - }, - }, - }, + } + } + } }); effects.preview.refresh(); state.git.gitState = updates.conflicts.length @@ -853,36 +847,36 @@ export const _getGitChanges: Action = ({ state }) => { const sandbox = state.editor.currentSandbox!; return { - added: git.gitChanges.added.map((path) => { + added: git.gitChanges.added.map(path => { const module = sandbox.modules.find( - (moduleItem) => moduleItem.path === path + moduleItem => moduleItem.path === path ); return { path, content: module!.code, - encoding: 'utf-8', + encoding: 'utf-8' }; }), deleted: git.gitChanges.deleted, - modified: git.gitChanges.modified.map((path) => { + modified: git.gitChanges.modified.map(path => { const module = sandbox.modules.find( - (moduleItem) => moduleItem.path === path + moduleItem => moduleItem.path === path ); return { path, content: module!.code, - encoding: 'utf-8', + encoding: 'utf-8' }; - }), + }) }; }; export const _tryResolveConflict: AsyncAction = async ({ state, effects, - actions, + actions }) => { const git = state.git; actions.git._setGitChanges(); @@ -933,14 +927,14 @@ export const linkToGitSandbox: AsyncAction = async ( state.editor.currentSandbox = { ...state.editor.currentSandbox, originalGitCommitSha: newGitData.originalGitCommitSha, - originalGit: newGitData.originalGit, + originalGit: newGitData.originalGit }; await actions.git.loadGitSource(); } catch (error) { actions.internal.handleError({ error, message: - 'There has been a problem connecting your sandbox to the GitHub repo. Please try again.', + 'There has been a problem connecting your sandbox to the GitHub repo. Please try again.' }); } finally { state.git.isLinkingToGitSandbox = false; From 67d45b0573661d0bc9f860f52b548b8d3945d039 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Fri, 11 Sep 2020 08:28:02 +0000 Subject: [PATCH 04/18] deal with adding binary --- packages/app/src/app/overmind/effects/http.ts | 14 ++ .../app/overmind/namespaces/git/actions.ts | 177 ++++++++++-------- 2 files changed, 110 insertions(+), 81 deletions(-) diff --git a/packages/app/src/app/overmind/effects/http.ts b/packages/app/src/app/overmind/effects/http.ts index 0330211dbc8..b6617844b40 100755 --- a/packages/app/src/app/overmind/effects/http.ts +++ b/packages/app/src/app/overmind/effects/http.ts @@ -7,4 +7,18 @@ export default { delete: axios.delete, put: axios.put, request: axios.request, + blobToBase64: (url: string): Promise => + fetch(url) + .then((response) => response.blob()) + .then( + (blob) => + new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = function () { + resolve(String(this.result)); + }; + reader.onerror = reject; + reader.readAsDataURL(blob); + }) + ), }; diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index c72cfa1e052..0c82fcdf7c6 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -4,7 +4,7 @@ import { GitFileCompare, GitInfo, Module, - SandboxGitState + SandboxGitState, } from '@codesandbox/common/lib/types'; import { convertTypeToStatus } from '@codesandbox/common/lib/utils/notifications'; import { hasPermission } from '@codesandbox/common/lib/utils/permission'; @@ -44,7 +44,7 @@ export const repoTitleChanged: Action<{ export const loadGitSource: AsyncAction = async ({ state, actions, - effects + effects, }) => { const sandbox = state.editor.currentSandbox!; state.git.isExported = false; @@ -69,7 +69,7 @@ export const loadGitSource: AsyncAction = async ({ actions.internal.handleError({ error, message: - 'Could not load the source sandbox for this GitHub sandbox, please refresh or report the issue.' + 'Could not load the source sandbox for this GitHub sandbox, please refresh or report the issue.', }); return; } @@ -80,7 +80,7 @@ export const loadGitSource: AsyncAction = async ({ actions.internal.handleError({ error, message: - 'Could not get information about your permissions, please refresh or report the issue.' + 'Could not get information about your permissions, please refresh or report the issue.', }); return; } @@ -93,7 +93,7 @@ export const loadGitSource: AsyncAction = async ({ actions.internal.handleError({ error, message: - 'We were not able to compare the content with the source, please refresh or report the issue.' + 'We were not able to compare the content with the source, please refresh or report the issue.', }); return; } @@ -105,7 +105,7 @@ export const loadGitSource: AsyncAction = async ({ actions.internal.handleError({ error, message: - 'We were not able to compare the content with the PR, please refresh or report the issue.' + 'We were not able to compare the content with the PR, please refresh or report the issue.', }); return; } @@ -118,7 +118,7 @@ export const loadGitSource: AsyncAction = async ({ export const createRepoClicked: AsyncAction = async ({ state, effects, - actions + actions, }) => { effects.analytics.track('GitHub - Create Repo'); const { repoTitle } = state.git; @@ -166,15 +166,15 @@ export const createRepoClicked: AsyncAction = async ({ state.currentModal = null; actions.editor.internal.forkSandbox({ - sandboxId: `github/${git.username}/${git.repo}/tree/${ - git.branch - }/${git.path || ''}` + sandboxId: `github/${git.username}/${git.repo}/tree/${git.branch}/${ + git.path || '' + }`, }); } catch (error) { actions.internal.handleError({ error, message: - 'Unable to create the repo. Please refresh and try again or report issue.' + 'Unable to create the repo. Please refresh and try again or report issue.', }); } }; @@ -186,7 +186,7 @@ export const importFromGithub: AsyncAction = async ( actions.modalClosed(); state.currentModal = 'exportGithub'; await actions.editor.forkExternalSandbox({ - sandboxId: sandboxUrl.replace('/s/', '') + sandboxId: sandboxUrl.replace('/s/', ''), }); state.currentModal = null; }; @@ -203,7 +203,7 @@ export const openSourceSandbox: Action = ({ state, effects }) => { export const createCommitClicked: AsyncAction = async ({ state, effects, - actions + actions, }) => { effects.analytics.track('GitHub - Create Commit'); const sandbox = state.editor.currentSandbox!; @@ -225,7 +225,7 @@ export const createCommitClicked: AsyncAction = async ({ } } - const changes = actions.git._getGitChanges(); + const changes = await actions.git._getGitChanges(); const commit = await effects.api.createGitCommit( sandbox.id, `${git.title}\n${git.description}`, @@ -265,15 +265,15 @@ export const createCommitClicked: AsyncAction = async ({ effects.browser.openWindow( 'docs/git#committing-to-organizations' ); - } - } - } + }, + }, + }, }); } else { actions.internal.handleError({ error, message: - 'We were unable to create your commit. Please try again or report the issue.' + 'We were unable to create your commit. Please try again or report the issue.', }); } } @@ -290,7 +290,7 @@ export const descriptionChanged: Action = ({ state }, description) => { export const createPrClicked: AsyncAction = async ({ state, effects, - actions + actions, }) => { effects.analytics.track('GitHub - Open PR'); const git = state.git; @@ -309,7 +309,7 @@ export const createPrClicked: AsyncAction = async ({ } } - const changes = actions.git._getGitChanges(); + const changes = await actions.git._getGitChanges(); const pr = await effects.api.createGitPr( id, state.git.title, @@ -317,19 +317,19 @@ export const createPrClicked: AsyncAction = async ({ changes ); - changes.added.forEach(change => { + changes.added.forEach((change) => { git.sourceModulesByPath[change.path].code = change.content; }); - changes.modified.forEach(change => { + changes.modified.forEach((change) => { git.sourceModulesByPath[change.path].code = change.content; }); - changes.deleted.forEach(path => { + changes.deleted.forEach((path) => { delete git.sourceModulesByPath[path]; }); actions.git._setGitChanges(); sandbox.baseGit = { - ...sandbox.originalGit + ...sandbox.originalGit, } as GitInfo; sandbox.baseGitCommitSha = sandbox.originalGit!.commitSha; sandbox.originalGit = { @@ -337,7 +337,7 @@ export const createPrClicked: AsyncAction = async ({ commitSha: pr.commitSha, repo: pr.repo, username: pr.username, - path: '' + path: '', }; sandbox.originalGitCommitSha = pr.commitSha; sandbox.prNumber = pr.number; @@ -361,16 +361,16 @@ export const createPrClicked: AsyncAction = async ({ sandbox.baseGit!.repo }/pull/${sandbox.prNumber!}` ); - } - } - } + }, + }, + }, }); } catch (error) { git.isCreatingPr = false; actions.internal.handleError({ error, message: - 'We were unable to create your PR. Please try again or report the issue.' + 'We were unable to create your PR. Please try again or report the issue.', }); } }; @@ -385,7 +385,7 @@ export const resolveConflicts: AsyncAction = async ( module ) => { const conflict = state.git.conflicts.find( - conflictItem => module.path === '/' + conflictItem.filename + (conflictItem) => module.path === '/' + conflictItem.filename ); if (conflict && module.code.indexOf('<<<<<<< Codesandbox') === -1) { @@ -394,7 +394,7 @@ export const resolveConflicts: AsyncAction = async ( await actions.editor.codeSaved({ moduleShortid: module.shortid, code: module.code, - cbID: null + cbID: null, }); effects.analytics.track('GitHub - Resolve Conflicts'); @@ -409,8 +409,8 @@ export const addConflictedFile: AsyncAction = async ( state.git.conflictsResolving.push(conflict.filename); await actions.files.createModulesByPath({ files: { - [conflict.filename]: { content: conflict.content!, isBinary: false } - } + [conflict.filename]: { content: conflict.content!, isBinary: false }, + }, }); state.git.sourceModulesByPath[ '/' + conflict.filename @@ -463,14 +463,14 @@ export const diffConflictedFile: AsyncAction = async ( actions.editor.setCode({ moduleShortid: module.shortid, - code: createDiff(module.code, conflict.content) + code: createDiff(module.code, conflict.content), }); }; export const resolveOutOfSync: AsyncAction = async ({ state, actions, - effects + effects, }) => { effects.analytics.track('GitHub - Resolve out of sync'); const git = state.git; @@ -484,17 +484,17 @@ export const resolveOutOfSync: AsyncAction = async ({ // first, because we need the new source to deal with binary files if (git.gitState === SandboxGitState.OUT_OF_SYNC_PR_BASE) { const changes: GitChanges = { - added: added.map(change => ({ + added: added.map((change) => ({ path: '/' + change.filename, content: change.content!, - encoding: change.isBinary ? 'base64' : 'utf-8' + encoding: change.isBinary ? 'base64' : 'utf-8', })), - deleted: deleted.map(change => '/' + change.filename), - modified: modified.map(change => ({ + deleted: deleted.map((change) => '/' + change.filename), + modified: modified.map((change) => ({ path: '/' + change.filename, content: change.content!, - encoding: change.isBinary ? 'base64' : 'utf-8' - })) + encoding: change.isBinary ? 'base64' : 'utf-8', + })), }; const commit = await effects.api.createGitCommit( sandbox.id, @@ -525,18 +525,18 @@ export const resolveOutOfSync: AsyncAction = async ({ ? { content: git.sourceModulesByPath['/' + change.filename].code, isBinary: true, - uploadId: git.sourceModulesByPath['/' + change.filename].uploadId + uploadId: git.sourceModulesByPath['/' + change.filename].uploadId, } : { content: change.content }; return aggr; - }, {}) + }, {}), }); } if (deleted.length) { await Promise.all( - deleted.map(change => { + deleted.map((change) => { const module = state.editor.modulesByPath['/' + change.filename]; return actions.files.moduleDeleted({ moduleShortid: module.shortid }); @@ -545,21 +545,21 @@ export const resolveOutOfSync: AsyncAction = async ({ } if (modified.length) { await Promise.all( - modified.map(change => { + modified.map((change) => { const module = state.editor.modulesByPath['/' + change.filename]; actions.editor.setCode({ moduleShortid: module.shortid, code: change.isBinary ? git.sourceModulesByPath['/' + change.filename].code - : change.content! + : change.content!, }); return actions.editor.codeSaved({ moduleShortid: module.shortid, code: change.isBinary ? git.sourceModulesByPath['/' + change.filename].code : change.content!, - cbID: null + cbID: null, }); }) ); @@ -581,10 +581,10 @@ export const _setGitChanges: Action = ({ state }) => { } = { added: [], deleted: [], - modified: [] + modified: [], }; - state.editor.currentSandbox!.modules.forEach(module => { + state.editor.currentSandbox!.modules.forEach((module) => { if (!(module.path in state.git.sourceModulesByPath)) { changes.added.push(module.path); } else if ( @@ -594,7 +594,7 @@ export const _setGitChanges: Action = ({ state }) => { changes.modified.push(module.path); } }); - Object.keys(state.git.sourceModulesByPath).forEach(path => { + Object.keys(state.git.sourceModulesByPath).forEach((path) => { if (!state.editor.modulesByPath[path]) { changes.deleted.push(path); } @@ -681,7 +681,7 @@ export const _evaluateGitChanges: AsyncAction< toUpdate.added.length + toUpdate.modified.length + toUpdate.deleted.length, - conflicts + conflicts, }; }; @@ -714,7 +714,7 @@ export const _loadSourceSandbox: AsyncAction = async ({ state, effects }) => { aggr[path] = { code: module.code, isBinary: module.isBinary, - uploadId: module.uploadId + uploadId: module.uploadId, }; } @@ -727,7 +727,7 @@ export const _loadSourceSandbox: AsyncAction = async ({ state, effects }) => { export const _compareWithSource: AsyncAction = async ({ state, effects, - actions + actions, }) => { const sandbox = state.editor.currentSandbox!; const originalGitCommitSha = sandbox.originalGitCommitSha; @@ -756,7 +756,7 @@ export const _compareWithSource: AsyncAction = async ({ label: 'Resolve', run: () => { actions.workspace.setWorkspaceItem({ item: 'github' }); - } + }, }, secondary: { label: 'See changes', @@ -768,9 +768,9 @@ export const _compareWithSource: AsyncAction = async ({ sandbox.originalGit!.branch }` ); - } - } - } + }, + }, + }, }); effects.preview.refresh(); state.git.gitState = updates.conflicts.length @@ -784,7 +784,7 @@ export const _compareWithSource: AsyncAction = async ({ export const _compareWithBase: AsyncAction = async ({ state, effects, - actions + actions, }) => { const sandbox = state.editor.currentSandbox!; @@ -817,7 +817,7 @@ export const _compareWithBase: AsyncAction = async ({ label: 'Resolve', run: () => { actions.workspace.setWorkspaceItem({ item: 'github' }); - } + }, }, secondary: { label: 'See changes', @@ -829,9 +829,9 @@ export const _compareWithBase: AsyncAction = async ({ sandbox.originalGit!.branch }` ); - } - } - } + }, + }, + }, }); effects.preview.refresh(); state.git.gitState = updates.conflicts.length @@ -842,41 +842,56 @@ export const _compareWithBase: AsyncAction = async ({ } }; -export const _getGitChanges: Action = ({ state }) => { +export const _getGitChanges: AsyncAction = async ({ + state, + effects, +}) => { const git = state.git; const sandbox = state.editor.currentSandbox!; return { - added: git.gitChanges.added.map(path => { - const module = sandbox.modules.find( - moduleItem => moduleItem.path === path - ); + added: await Promise.all( + git.gitChanges.added.map(async (path) => { + const module = sandbox.modules.find( + (moduleItem) => moduleItem.path === path + ); - return { - path, - content: module!.code, - encoding: 'utf-8' - }; - }), + if (module.isBinary) { + return { + path, + content: await effects.http.blobToBase64(module.code), + encoding: 'base64' as 'base64', + }; + } + + return { + path, + content: module!.code, + encoding: 'utf-8' as 'utf-8', + }; + }) + ), deleted: git.gitChanges.deleted, - modified: git.gitChanges.modified.map(path => { + modified: git.gitChanges.modified.map((path) => { const module = sandbox.modules.find( - moduleItem => moduleItem.path === path + (moduleItem) => moduleItem.path === path ); + // A binary can not be modified, because we have no mechanism for comparing + // private binary files, as their urls are based on moduleId (which is different across sandboxes) return { path, content: module!.code, - encoding: 'utf-8' + encoding: 'utf-8', }; - }) + }), }; }; export const _tryResolveConflict: AsyncAction = async ({ state, effects, - actions + actions, }) => { const git = state.git; actions.git._setGitChanges(); @@ -897,7 +912,7 @@ export const _tryResolveConflict: AsyncAction = async ({ ) { state.git.isCommitting = true; const sandbox = state.editor.currentSandbox!; - const changes = actions.git._getGitChanges(); + const changes = await actions.git._getGitChanges(); state.git.title = 'Resolve conflict'; const commit = await effects.api.createGitCommit( sandbox.id, @@ -927,14 +942,14 @@ export const linkToGitSandbox: AsyncAction = async ( state.editor.currentSandbox = { ...state.editor.currentSandbox, originalGitCommitSha: newGitData.originalGitCommitSha, - originalGit: newGitData.originalGit + originalGit: newGitData.originalGit, }; await actions.git.loadGitSource(); } catch (error) { actions.internal.handleError({ error, message: - 'There has been a problem connecting your sandbox to the GitHub repo. Please try again.' + 'There has been a problem connecting your sandbox to the GitHub repo. Please try again.', }); } finally { state.git.isLinkingToGitSandbox = false; From 4c91418b3216872e437f4d4404314791a5e88d11 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Fri, 11 Sep 2020 08:45:47 +0000 Subject: [PATCH 05/18] fix typing --- packages/app/src/app/overmind/namespaces/git/actions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 0c82fcdf7c6..4c6831ed5fb 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -856,10 +856,10 @@ export const _getGitChanges: AsyncAction = async ({ (moduleItem) => moduleItem.path === path ); - if (module.isBinary) { + if (module!.isBinary) { return { path, - content: await effects.http.blobToBase64(module.code), + content: await effects.http.blobToBase64(module!.code), encoding: 'base64' as 'base64', }; } From da8559943a7a2e27cf5f673ff76f72f01f0c89b1 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Fri, 11 Sep 2020 10:41:11 +0000 Subject: [PATCH 06/18] try with utf-8 --- packages/app/src/app/overmind/namespaces/git/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 4c6831ed5fb..9966f01876f 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -860,7 +860,7 @@ export const _getGitChanges: AsyncAction = async ({ return { path, content: await effects.http.blobToBase64(module!.code), - encoding: 'base64' as 'base64', + encoding: 'utf-8' as 'utf-8', }; } From 2d1da112b27ceeacb332ff4c841104e3fb65586a Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Fri, 11 Sep 2020 11:02:27 +0000 Subject: [PATCH 07/18] Try binary string --- packages/app/src/app/overmind/effects/http.ts | 2 +- packages/app/src/app/overmind/namespaces/git/actions.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/app/src/app/overmind/effects/http.ts b/packages/app/src/app/overmind/effects/http.ts index b6617844b40..c87f9286a23 100755 --- a/packages/app/src/app/overmind/effects/http.ts +++ b/packages/app/src/app/overmind/effects/http.ts @@ -18,7 +18,7 @@ export default { resolve(String(this.result)); }; reader.onerror = reject; - reader.readAsDataURL(blob); + reader.readAsBinaryString(blob); }) ), }; diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 9966f01876f..4c6831ed5fb 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -860,7 +860,7 @@ export const _getGitChanges: AsyncAction = async ({ return { path, content: await effects.http.blobToBase64(module!.code), - encoding: 'utf-8' as 'utf-8', + encoding: 'base64' as 'base64', }; } From 8242f8dbb2754bea152d41ba2fbb558130550603 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Fri, 11 Sep 2020 11:36:59 +0000 Subject: [PATCH 08/18] try something weird --- packages/app/src/app/overmind/effects/http.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/app/src/app/overmind/effects/http.ts b/packages/app/src/app/overmind/effects/http.ts index c87f9286a23..4921ea066fb 100755 --- a/packages/app/src/app/overmind/effects/http.ts +++ b/packages/app/src/app/overmind/effects/http.ts @@ -15,10 +15,14 @@ export default { new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = function () { - resolve(String(this.result)); + resolve( + window.btoa( + window.atob((reader.result as string).replace(/^(.+,)/, '')) + ) + ); }; reader.onerror = reject; - reader.readAsBinaryString(blob); + reader.readAsDataURL(blob); }) ), }; From b81cfb81ad74948921c628549203c247fb53d657 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Fri, 11 Sep 2020 11:59:13 +0000 Subject: [PATCH 09/18] add comment --- packages/app/src/app/overmind/effects/http.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/app/src/app/overmind/effects/http.ts b/packages/app/src/app/overmind/effects/http.ts index 4921ea066fb..114ec68a739 100755 --- a/packages/app/src/app/overmind/effects/http.ts +++ b/packages/app/src/app/overmind/effects/http.ts @@ -15,6 +15,8 @@ export default { new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = function () { + // Github interprets base64 differently, so this fixes it, insane right? + // https://stackoverflow.com/questions/39234218/github-api-upload-an-image-to-repo-from-base64-array?rq=1 resolve( window.btoa( window.atob((reader.result as string).replace(/^(.+,)/, '')) From fd45406b60189865858c862bfa3992595b4b56af Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Mon, 14 Sep 2020 10:43:04 +0000 Subject: [PATCH 10/18] deal with binary shas --- packages/app/src/app/overmind/namespaces/git/actions.ts | 4 +++- packages/app/src/app/overmind/namespaces/git/state.ts | 1 + packages/common/src/types/index.ts | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 4c6831ed5fb..f51d30b813c 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -588,7 +588,8 @@ export const _setGitChanges: Action = ({ state }) => { if (!(module.path in state.git.sourceModulesByPath)) { changes.added.push(module.path); } else if ( - !module.isBinary && + (module.sha && + state.git.sourceModulesByPath[module.path].sha !== module.code) || state.git.sourceModulesByPath[module.path].code !== module.code ) { changes.modified.push(module.path); @@ -715,6 +716,7 @@ export const _loadSourceSandbox: AsyncAction = async ({ state, effects }) => { code: module.code, isBinary: module.isBinary, uploadId: module.uploadId, + sha: module.sha, }; } diff --git a/packages/app/src/app/overmind/namespaces/git/state.ts b/packages/app/src/app/overmind/namespaces/git/state.ts index e4a98764f67..afc3160d79f 100755 --- a/packages/app/src/app/overmind/namespaces/git/state.ts +++ b/packages/app/src/app/overmind/namespaces/git/state.ts @@ -28,6 +28,7 @@ type State = { code: string; isBinary: boolean; uploadId?: string; + sha?: string; }; }; permission: 'admin' | 'write' | 'read'; diff --git a/packages/common/src/types/index.ts b/packages/common/src/types/index.ts index accc237f6f2..d569233f5f2 100644 --- a/packages/common/src/types/index.ts +++ b/packages/common/src/types/index.ts @@ -66,6 +66,7 @@ export type Module = { updatedAt: string; path: string; uploadId?: string; + sha?: string; type: 'file'; }; From 0ed55c034ad622238700a6769b6240ffd471811d Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Tue, 22 Sep 2020 08:52:00 +0000 Subject: [PATCH 11/18] properly compare binary shas --- .../app/overmind/namespaces/git/actions.ts | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 2b9a3cbd2f1..a363420ef60 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -166,9 +166,9 @@ export const createRepoClicked: AsyncAction = async ({ state.currentModal = null; actions.editor.internal.forkSandbox({ - sandboxId: `github/${git.username}/${git.repo}/tree/${ - git.branch - }/${git.path || ''}`, + sandboxId: `github/${git.username}/${git.repo}/tree/${git.branch}/${ + git.path || '' + }`, }); } catch (error) { actions.internal.handleError({ @@ -338,10 +338,10 @@ export const createPrClicked: AsyncAction = async ({ changes ); - changes.added.forEach((change) => { + changes.added.forEach(change => { git.sourceModulesByPath[change.path].code = change.content; }); - changes.modified.forEach((change) => { + changes.modified.forEach(change => { git.sourceModulesByPath[change.path].code = change.content; }); changes.deleted.forEach(path => { @@ -379,7 +379,7 @@ export const createPrClicked: AsyncAction = async ({ run: () => { effects.browser.openWindow( `https://github.com/${sandbox.baseGit!.username}/${ - sandbox.baseGit!.repo + sandbox.baseGit!.repo }/pull/${sandbox.prNumber!}` ); }, @@ -544,10 +544,10 @@ export const resolveOutOfSync: AsyncAction = async ({ files: added.reduce((aggr, change) => { aggr[change.filename] = change.isBinary ? { - content: git.sourceModulesByPath['/' + change.filename].code, - isBinary: true, - uploadId: git.sourceModulesByPath['/' + change.filename].uploadId, - } + content: git.sourceModulesByPath['/' + change.filename].code, + isBinary: true, + uploadId: git.sourceModulesByPath['/' + change.filename].uploadId, + } : { content: change.content }; return aggr; @@ -557,7 +557,7 @@ export const resolveOutOfSync: AsyncAction = async ({ if (deleted.length) { await Promise.all( - deleted.map((change) => { + deleted.map(change => { const module = state.editor.modulesByPath['/' + change.filename]; return actions.files.moduleDeleted({ moduleShortid: module.shortid }); @@ -566,7 +566,7 @@ export const resolveOutOfSync: AsyncAction = async ({ } if (modified.length) { await Promise.all( - modified.map((change) => { + modified.map(change => { const module = state.editor.modulesByPath['/' + change.filename]; actions.editor.setCode({ @@ -609,9 +609,10 @@ export const _setGitChanges: Action = ({ state }) => { if (!(module.path in state.git.sourceModulesByPath)) { changes.added.push(module.path); } else if ( - (module.sha && - state.git.sourceModulesByPath[module.path].sha !== module.code) || - state.git.sourceModulesByPath[module.path].code !== module.code + ('sha' in module && + state.git.sourceModulesByPath[module.path].sha !== module.sha) || + (!('sha' in module) && + state.git.sourceModulesByPath[module.path].code !== module.code) ) { changes.modified.push(module.path); } @@ -657,7 +658,7 @@ export const _evaluateGitChanges: AsyncAction< !(state.editor.modulesByPath[path] as Module).isBinary && (state.editor.modulesByPath[path] as Module).code !== change.content && (state.editor.modulesByPath[path] as Module).code !== - state.git.sourceModulesByPath[path].code + state.git.sourceModulesByPath[path].code ) { return aggr.concat(change); } @@ -687,7 +688,7 @@ export const _evaluateGitChanges: AsyncAction< state.editor.modulesByPath['/' + change.filename]) || (change.status === 'modified' && (state.editor.modulesByPath['/' + change.filename] as Module).code !== - change.content) + change.content) ) { aggr[change.status === 'removed' ? 'deleted' : change.status].push( change @@ -717,7 +718,7 @@ export const _loadSourceSandbox: AsyncAction = async ({ state, effects }) => { const sourceSandbox = await effects.api.getSandbox( `github/${originalGit.username}/${ - originalGit.repo + originalGit.repo }/tree/${sandbox.originalGitCommitSha!}/${originalGit.path}` ); @@ -770,7 +771,7 @@ export const _compareWithSource: AsyncAction = async ({ effects.notificationToast.add({ message: `The sandbox is out of sync with "${ sandbox.originalGit!.branch - }" ${updates.conflicts.length ? 'and there are conflicts' : ''}`, + }" ${updates.conflicts.length ? 'and there are conflicts' : ''}`, title: 'Out of sync', status: convertTypeToStatus('notice'), sticky: false, @@ -786,9 +787,9 @@ export const _compareWithSource: AsyncAction = async ({ run: () => { effects.browser.openWindow( `https://github.com/${sandbox.originalGit!.username}/${ - sandbox.originalGit!.repo + sandbox.originalGit!.repo }/compare/${originalGitCommitSha}...${ - sandbox.originalGit!.branch + sandbox.originalGit!.branch }` ); }, @@ -831,7 +832,7 @@ export const _compareWithBase: AsyncAction = async ({ effects.notificationToast.add({ message: `The sandbox is out of sync with "${sandbox.baseGit!.branch}" ${ updates.conflicts.length ? 'and there are conflicts' : '' - }`, + }`, title: 'Out of sync', status: convertTypeToStatus('notice'), sticky: false, @@ -847,9 +848,9 @@ export const _compareWithBase: AsyncAction = async ({ run: () => { effects.browser.openWindow( `https://github.com/${sandbox.originalGit!.username}/${ - sandbox.originalGit!.repo + sandbox.originalGit!.repo }/compare/${sandbox.baseGit!.branch}...${ - sandbox.originalGit!.branch + sandbox.originalGit!.branch }` ); }, @@ -874,9 +875,9 @@ export const _getGitChanges: AsyncAction = async ({ return { added: await Promise.all( - git.gitChanges.added.map(async (path) => { + git.gitChanges.added.map(async path => { const module = sandbox.modules.find( - (moduleItem) => moduleItem.path === path + moduleItem => moduleItem.path === path ); if (module!.isBinary) { From aacb283180201b2df5ee422216242805e70f0d4f Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Tue, 22 Sep 2020 09:50:36 +0000 Subject: [PATCH 12/18] fix sha check --- packages/app/src/app/overmind/namespaces/git/actions.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index a363420ef60..3b6c216edee 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -609,10 +609,9 @@ export const _setGitChanges: Action = ({ state }) => { if (!(module.path in state.git.sourceModulesByPath)) { changes.added.push(module.path); } else if ( - ('sha' in module && + (module.sha && state.git.sourceModulesByPath[module.path].sha !== module.sha) || - (!('sha' in module) && - state.git.sourceModulesByPath[module.path].code !== module.code) + state.git.sourceModulesByPath[module.path].code !== module.code ) { changes.modified.push(module.path); } From 6121468506261e7648ee280caf69234815765432 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Tue, 22 Sep 2020 13:27:57 +0200 Subject: [PATCH 13/18] use sha when adding module using latest import utils --- packages/app/package.json | 2 +- packages/app/src/app/overmind/namespaces/git/actions.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/app/package.json b/packages/app/package.json index d82d1ac575a..7e5854ff538 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -107,7 +107,7 @@ "circular-json": "^0.4.0", "codemirror": "^5.27.4", "codesandbox-api": "0.0.24", - "codesandbox-import-utils": "^2.2.0", + "codesandbox-import-utils": "^2.3.0", "color": "^0.11.4", "compare-versions": "^3.1.0", "console": "^0.7.2", diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 3b6c216edee..e8dd55bdbea 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -547,6 +547,7 @@ export const resolveOutOfSync: AsyncAction = async ({ content: git.sourceModulesByPath['/' + change.filename].code, isBinary: true, uploadId: git.sourceModulesByPath['/' + change.filename].uploadId, + sha: git.sourceModulesByPath['/' + change.filename].sha, } : { content: change.content }; From 770491e3f0898e6c0b4d6d034ce819a706714108 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Wed, 23 Sep 2020 08:21:33 +0200 Subject: [PATCH 14/18] change version --- packages/app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/package.json b/packages/app/package.json index 7e5854ff538..c561e3cf7f9 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -107,7 +107,7 @@ "circular-json": "^0.4.0", "codemirror": "^5.27.4", "codesandbox-api": "0.0.24", - "codesandbox-import-utils": "^2.3.0", + "codesandbox-import-utils": "^2.2.1", "color": "^0.11.4", "compare-versions": "^3.1.0", "console": "^0.7.2", From da44bc618d8cc1f7ec50ec44fdcde9b61bda98a9 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Mon, 28 Sep 2020 08:52:40 +0000 Subject: [PATCH 15/18] explicitly check if sha is available --- packages/app/src/app/overmind/namespaces/git/actions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index e8dd55bdbea..41aa21e491d 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -612,7 +612,8 @@ export const _setGitChanges: Action = ({ state }) => { } else if ( (module.sha && state.git.sourceModulesByPath[module.path].sha !== module.sha) || - state.git.sourceModulesByPath[module.path].code !== module.code + (!module.sha && + state.git.sourceModulesByPath[module.path].code !== module.code) ) { changes.modified.push(module.path); } From f3ea1c541c58be1a184e44e41f603369ba73cb06 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Mon, 28 Sep 2020 09:45:39 +0000 Subject: [PATCH 16/18] deal with updating private binary file --- .../app/src/app/overmind/effects/api/index.ts | 18 ++++++++++++++++++ .../src/app/overmind/namespaces/git/actions.ts | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/packages/app/src/app/overmind/effects/api/index.ts b/packages/app/src/app/overmind/effects/api/index.ts index d9538d2e7f8..2d0e44fbe7d 100755 --- a/packages/app/src/app/overmind/effects/api/index.ts +++ b/packages/app/src/app/overmind/effects/api/index.ts @@ -139,6 +139,24 @@ export default { ) .then(transformModule); }, + saveModulePrivateUpload( + sandboxId: string, + moduleShortid: string, + data: { + code: string; + uploadId: string; + sha: string; + } + ): Promise { + return api + .put( + `/sandboxes/${sandboxId}/modules/${moduleShortid}`, + { + module: data, + } + ) + .then(transformModule); + }, saveModules(sandboxId: string, modules: Module[]): Promise { return api .put(`/sandboxes/${sandboxId}/modules/mupdate`, { diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 41aa21e491d..b78922a3e19 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -570,6 +570,18 @@ export const resolveOutOfSync: AsyncAction = async ({ modified.map(change => { const module = state.editor.modulesByPath['/' + change.filename]; + // If we are dealing with a private binary change, we need to bluntly update + // the module + if (git.sourceModulesByPath['/' + change.filename].sha) { + return effects.api + .saveModulePrivateUpload(sandbox.id, module.shortid, { + code: git.sourceModulesByPath['/' + change.filename].code, + uploadId: git.sourceModulesByPath['/' + change.filename] + .uploadId!, + sha: git.sourceModulesByPath['/' + change.filename].sha!, + }) + .then(() => {}); + } actions.editor.setCode({ moduleShortid: module.shortid, code: change.isBinary From 9d21acb22b8a2be1ab07cb97723ebecaf574f26f Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Mon, 28 Sep 2020 10:21:41 +0000 Subject: [PATCH 17/18] optimistically update binary change --- .../app/overmind/namespaces/git/actions.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index b78922a3e19..12857845986 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -573,12 +573,23 @@ export const resolveOutOfSync: AsyncAction = async ({ // If we are dealing with a private binary change, we need to bluntly update // the module if (git.sourceModulesByPath['/' + change.filename].sha) { + const code = git.sourceModulesByPath['/' + change.filename].code; + const uploadId = git.sourceModulesByPath['/' + change.filename] + .uploadId!; + const sha = git.sourceModulesByPath['/' + change.filename].sha!; + + const sandboxModule = sandbox.modules.find( + moduleItem => moduleItem.shortid === module.shortid + ); + sandboxModule.code = code; + sandboxModule.uploadId = uploadId; + sandboxModule.sha = sha; + return effects.api .saveModulePrivateUpload(sandbox.id, module.shortid, { - code: git.sourceModulesByPath['/' + change.filename].code, - uploadId: git.sourceModulesByPath['/' + change.filename] - .uploadId!, - sha: git.sourceModulesByPath['/' + change.filename].sha!, + code, + uploadId, + sha, }) .then(() => {}); } From 30aa7fdd3e7ae942d589b56de85bd6d0fc4b068d Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Mon, 28 Sep 2020 10:22:37 +0000 Subject: [PATCH 18/18] typing --- packages/app/src/app/overmind/namespaces/git/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/app/overmind/namespaces/git/actions.ts b/packages/app/src/app/overmind/namespaces/git/actions.ts index 12857845986..17406935e50 100755 --- a/packages/app/src/app/overmind/namespaces/git/actions.ts +++ b/packages/app/src/app/overmind/namespaces/git/actions.ts @@ -580,7 +580,7 @@ export const resolveOutOfSync: AsyncAction = async ({ const sandboxModule = sandbox.modules.find( moduleItem => moduleItem.shortid === module.shortid - ); + )!; sandboxModule.code = code; sandboxModule.uploadId = uploadId; sandboxModule.sha = sha;