diff --git a/packages/insomnia-app/app/sync/vcs/index.js b/packages/insomnia-app/app/sync/vcs/index.js index ff687da3e2..5871ad3be3 100644 --- a/packages/insomnia-app/app/sync/vcs/index.js +++ b/packages/insomnia-app/app/sync/vcs/index.js @@ -367,8 +367,8 @@ export default class VCS { }; } - async getHistoryCount(): Promise { - const branch = await this._getCurrentBranch(); + async getHistoryCount(branchName?: string): Promise { + const branch = branchName ? await this._getBranch(branchName) : await this._getCurrentBranch(); return branch.snapshots.length; } @@ -716,6 +716,7 @@ export default class VCS { const { data, errors } = await fetch.post('/graphql?' + name, { query, variables }, sessionId); if (errors && errors.length) { + console.log(`[sync] Failed to query ${name}`, errors); throw new Error(`Failed to query ${name}`); } @@ -727,7 +728,7 @@ export default class VCS { ` query ($projectId: ID!, $ids: [ID!]!) { blobsMissing(project: $projectId, ids: $ids) { - missing + missing } } `, @@ -766,7 +767,7 @@ export default class VCS { await this._runGraphQL( ` mutation ($projectId: ID!, $branch: String!) { - branchRemove(project: $projectId, name: $branch) + branchRemove(project: $projectId, name: $branch) }`, { projectId: this._projectId(), @@ -1127,32 +1128,25 @@ export default class VCS { } async _queryProjectTeams(): Promise> { - const run = async () => { - const { project } = await this._runGraphQL( - ` - query ($id: ID!) { - project(id: $id) { - teams { - id - name - } + const { project } = await this._runGraphQL( + ` + query ($id: ID!) { + project(id: $id) { + teams { + id + name } } - `, - { - id: this._projectId(), - }, - 'project.teams', - ); - return project; - }; + } + `, + { + id: this._projectId(), + }, + 'project.teams', + ); - let project = await run(); - - // Retry once if project doesn't exist yet - if (project === null) { - await this._getOrCreateRemoteProject(); - project = await run(); + if (!project) { + throw new Error('Please push the workspace to be able to share it'); } return project.teams; diff --git a/packages/insomnia-app/app/ui/components/dropdowns/sync-dropdown.js b/packages/insomnia-app/app/ui/components/dropdowns/sync-dropdown.js index 85f45dd4d3..0a27567726 100644 --- a/packages/insomnia-app/app/ui/components/dropdowns/sync-dropdown.js +++ b/packages/insomnia-app/app/ui/components/dropdowns/sync-dropdown.js @@ -19,6 +19,7 @@ import LoginModal from '../modals/login-modal'; import * as session from '../../../account/session'; import PromptButton from '../base/prompt-button'; import * as db from '../../../common/database'; +import * as models from '../../../models'; // Stop refreshing if user hasn't been active in this long const REFRESH_USER_ACTIVITY = 1000 * 60 * 10; @@ -26,6 +27,8 @@ const REFRESH_USER_ACTIVITY = 1000 * 60 * 10; // Refresh dropdown periodically const REFRESH_PERIOD = 1000 * 60 * 1; +const DEFAULT_BRANCH_NAME = 'master'; + type Props = { workspace: Workspace, vcs: VCS, @@ -256,23 +259,51 @@ class SyncDropdown extends React.PureComponent { const { vcs } = this.props; this.setState({ loadingProjectPull: true }); await vcs.setProject(p); - await vcs.checkout([], 'master'); - // Pull changes - await vcs.pull([]); // There won't be any existing docs since it's a new pull - const flushId = await db.bufferChanges(); - for (const doc of await vcs.allDocuments()) { - await db.upsert(doc); + await vcs.checkout([], DEFAULT_BRANCH_NAME); + + const remoteBranches = await vcs.getRemoteBranches(); + const defaultBranchMissing = !remoteBranches.includes(DEFAULT_BRANCH_NAME); + + // The default branch does not exist, so we create it and the workspace locally + if (defaultBranchMissing) { + const workspace: Workspace = await models.initModel(models.workspace.type, { + _id: p.rootDocumentId, + name: p.name, + }); + + await db.upsert(workspace); + } else { + // Pull changes + await vcs.pull([]); // There won't be any existing docs since it's a new pull + const flushId = await db.bufferChanges(); + for (const doc of await vcs.allDocuments()) { + await db.upsert(doc); + } + await db.flushChanges(flushId); } - await db.flushChanges(flushId); await this.refreshMainAttributes({ loadingProjectPull: false }); } async _handleSwitchBranch(branch: string) { const { vcs, syncItems } = this.props; + try { const delta = await vcs.checkout(syncItems, branch); + + if (branch === DEFAULT_BRANCH_NAME) { + const { historyCount } = this.state; + const defaultBranchHistoryCount = await vcs.getHistoryCount(DEFAULT_BRANCH_NAME); + + // If the default branch has no snapshots, but the current branch does + // It will result in the workspace getting deleted + // So we filter out the workspace from the delta to prevent this + if (!defaultBranchHistoryCount && historyCount) { + delta.remove = delta.remove.filter(e => e.type !== models.workspace.type); + } + } + await db.batchModifyDocs(delta); } catch (err) { showAlert({ diff --git a/packages/insomnia-app/app/ui/components/dropdowns/workspace-dropdown.js b/packages/insomnia-app/app/ui/components/dropdowns/workspace-dropdown.js index 807e710caf..c42084c4b2 100644 --- a/packages/insomnia-app/app/ui/components/dropdowns/workspace-dropdown.js +++ b/packages/insomnia-app/app/ui/components/dropdowns/workspace-dropdown.js @@ -152,15 +152,32 @@ class WorkspaceDropdown extends React.PureComponent { await newVCS.removeProjectsForRoot(project.rootDocumentId); // Set project, checkout master, and pull - await newVCS.setProject(project); - await newVCS.checkout([], 'master'); - await newVCS.pull([]); // There won't be any existing docs since it's a new pull + const defaultBranch = 'master'; - const flushId = await db.bufferChanges(); - for (const doc of await newVCS.allDocuments()) { - await db.upsert(doc); + await newVCS.setProject(project); + await newVCS.checkout([], defaultBranch); + + const remoteBranches = await newVCS.getRemoteBranches(); + const defaultBranchMissing = !remoteBranches.includes(defaultBranch); + + // The default branch does not exist, so we create it and the workspace locally + if (defaultBranchMissing) { + const workspace: Workspace = await models.initModel(models.workspace.type, { + _id: project.rootDocumentId, + name: project.name, + }); + + await db.upsert(workspace); + } else { + await newVCS.pull([]); // There won't be any existing docs since it's a new pull + + const flushId = await db.bufferChanges(); + for (const doc of await newVCS.allDocuments()) { + await db.upsert(doc); + } + await db.flushChanges(flushId); } - await db.flushChanges(flushId); + await this._refreshRemoteWorkspaces(); } catch (err) { this._dropdown && this._dropdown.hide(); diff --git a/packages/insomnia-app/app/ui/components/modals/sync-merge-modal.js b/packages/insomnia-app/app/ui/components/modals/sync-merge-modal.js index 2ca5da3917..608b190845 100644 --- a/packages/insomnia-app/app/ui/components/modals/sync-merge-modal.js +++ b/packages/insomnia-app/app/ui/components/modals/sync-merge-modal.js @@ -25,9 +25,12 @@ class SyncMergeModal extends React.PureComponent { modal: ?Modal; _handleDone: (Array) => void; - state = { - conflicts: [], - }; + constructor(props: Props) { + super(props); + this.state = { + conflicts: [], + }; + } _setModalRef(n: ?Modal) { this.modal = n; @@ -90,7 +93,6 @@ class SyncMergeModal extends React.PureComponent { Mine{' '} this._handleToggleSelect(conflict.key, e)} @@ -100,7 +102,6 @@ class SyncMergeModal extends React.PureComponent { Theirs{' '} this._handleToggleSelect(conflict.key, e)} diff --git a/packages/insomnia-app/app/ui/components/modals/sync-share-modal.js b/packages/insomnia-app/app/ui/components/modals/sync-share-modal.js index 890f253ac6..08695103c0 100644 --- a/packages/insomnia-app/app/ui/components/modals/sync-share-modal.js +++ b/packages/insomnia-app/app/ui/components/modals/sync-share-modal.js @@ -72,6 +72,14 @@ class SyncShareModal extends React.PureComponent { this.setState({ loading: true }); this.modal && this.modal.show(); + if (!vcs.hasProject()) { + this.setState({ + error: 'Please set up sync to be able to share the workspace', + loading: false, + }); + return; + } + let results; try { results = await Promise.all([vcs.teams(), vcs.projectTeams()]);