From 5a189ff7e462763f118ba3857ba402fedeade19f Mon Sep 17 00:00:00 2001 From: Curry Yang <1019yanglu@gmail.com> Date: Tue, 28 May 2024 15:30:32 +0800 Subject: [PATCH] perf/io-parallelization --- .../vcs/migrate-projects-into-organization.ts | 65 +++++----- packages/insomnia/src/sync/vcs/vcs.ts | 1 + .../insomnia/src/ui/routes/organization.tsx | 80 +++++-------- packages/insomnia/src/ui/routes/project.tsx | 112 ++++++++++-------- 4 files changed, 128 insertions(+), 130 deletions(-) diff --git a/packages/insomnia/src/sync/vcs/migrate-projects-into-organization.ts b/packages/insomnia/src/sync/vcs/migrate-projects-into-organization.ts index 9257d2e3118a..814babb51edb 100644 --- a/packages/insomnia/src/sync/vcs/migrate-projects-into-organization.ts +++ b/packages/insomnia/src/sync/vcs/migrate-projects-into-organization.ts @@ -17,16 +17,16 @@ import { Project, RemoteProject } from '../../models/project'; // which is now the remoteId for tracking the projects within an org export const shouldMigrateProjectUnderOrganization = async () => { - const localProjectCount = await database.count(models.project.type, { - remoteId: null, - parentId: null, - _id: { $ne: models.project.SCRATCHPAD_PROJECT_ID }, - }); - - const legacyRemoteProjectCount = await database.count(models.project.type, { - remoteId: { $ne: null }, - parentId: null, - }); + const [localProjectCount, legacyRemoteProjectCount] = await Promise.all([ + database.count(models.project.type, { + remoteId: null, + parentId: null, + }), + database.count(models.project.type, { + remoteId: { $ne: null }, + parentId: null, + }), + ]); return localProjectCount > 0 || legacyRemoteProjectCount > 0; }; @@ -37,29 +37,38 @@ export const migrateProjectsIntoOrganization = async ({ personalOrganization: Organization; }) => { // Legacy remote projects without organizations - const legacyRemoteProjects = await database.find(models.project.type, { - remoteId: { $ne: null }, - parentId: null, - }); + // Local projects without organizations except scratchpad + const [legacyRemoteProjects, localProjects] = await Promise.all([ + database.find(models.project.type, { + remoteId: { $ne: null }, + parentId: null, + }), + database.find(models.project.type, { + remoteId: null, + parentId: null, + _id: { $ne: models.project.SCRATCHPAD_PROJECT_ID }, + }), + ]); + + const updatePromises = []; // Legacy remoteId should be orgId and legacy _id should be remoteId for (const remoteProject of legacyRemoteProjects) { - await models.project.update(remoteProject, { - parentId: remoteProject.remoteId, - remoteId: remoteProject._id, - }); + updatePromises.push( + models.project.update(remoteProject, { + parentId: remoteProject.remoteId, + remoteId: remoteProject._id, + }) + ); } - // Local projects without organizations except scratchpad - const localProjects = await database.find(models.project.type, { - remoteId: null, - parentId: null, - _id: { $ne: models.project.SCRATCHPAD_PROJECT_ID }, - }); - // Assign all local projects to personal organization for (const localProject of localProjects) { - await models.project.update(localProject, { - parentId: personalOrganization.id, - }); + updatePromises.push( + models.project.update(localProject, { + parentId: personalOrganization.id, + }) + ); } + + await Promise.all(updatePromises); }; diff --git a/packages/insomnia/src/sync/vcs/vcs.ts b/packages/insomnia/src/sync/vcs/vcs.ts index f54e3e727cca..cb444e2112a2 100644 --- a/packages/insomnia/src/sync/vcs/vcs.ts +++ b/packages/insomnia/src/sync/vcs/vcs.ts @@ -626,6 +626,7 @@ export class VCS { return this._queryCreateProject(rootDocumentId, name, teamId, teamProjectId, teamKeys.memberKeys); } + // TODO: may be we can create another push function for initial push, so that we can reduce some api calls async push({ teamId, teamProjectId }: { teamId: string; teamProjectId: string }) { await this._getOrCreateRemoteBackendProject({ teamId, teamProjectId }); const branch = await this._getCurrentBranch(); diff --git a/packages/insomnia/src/ui/routes/organization.tsx b/packages/insomnia/src/ui/routes/organization.tsx index 804f15a28a00..eb45f862a44c 100644 --- a/packages/insomnia/src/ui/routes/organization.tsx +++ b/packages/insomnia/src/ui/routes/organization.tsx @@ -127,41 +127,46 @@ function sortOrganizations(accountId: string, organizations: Organization[]): Or ]; } -export const indexLoader: LoaderFunction = async () => { - const { id: sessionId, accountId } = await userSession.getOrCreate(); - if (sessionId) { - try { - const organizationsResult = await insomniaFetch({ +async function syncOrganization(sessionId: string, accountId: string) { + try { + const [organizationsResult, user, currentPlan] = await Promise.all([ + insomniaFetch({ method: 'GET', path: '/v1/organizations', sessionId, - }); - const user = await insomniaFetch({ + }), + insomniaFetch({ method: 'GET', path: '/v1/user/profile', sessionId, - }); - - const currentPlan = await insomniaFetch({ + }), + insomniaFetch({ method: 'GET', path: '/v1/billing/current-plan', sessionId, - }); + }), + ]); - invariant(organizationsResult && organizationsResult.organizations, 'Failed to load organizations'); - invariant(user && user.id, 'Failed to load user'); - invariant(currentPlan && currentPlan.planId, 'Failed to load current plan'); + invariant(organizationsResult && organizationsResult.organizations, 'Failed to load organizations'); + invariant(user && user.id, 'Failed to load user'); + invariant(currentPlan && currentPlan.planId, 'Failed to load current plan'); - const { organizations } = organizationsResult; + const { organizations } = organizationsResult; - invariant(accountId, 'Account ID is not defined'); + invariant(accountId, 'Account ID is not defined'); - localStorage.setItem(`${accountId}:organizations`, JSON.stringify(sortOrganizations(accountId, organizations))); - localStorage.setItem(`${accountId}:user`, JSON.stringify(user)); - localStorage.setItem(`${accountId}:currentPlan`, JSON.stringify(currentPlan)); - } catch (error) { - console.log('Failed to load Organizations', error); - } + localStorage.setItem(`${accountId}:organizations`, JSON.stringify(sortOrganizations(accountId, organizations))); + localStorage.setItem(`${accountId}:user`, JSON.stringify(user)); + localStorage.setItem(`${accountId}:currentPlan`, JSON.stringify(currentPlan)); + } catch (error) { + console.log('Failed to load Organizations', error); + } +} + +export const indexLoader: LoaderFunction = async () => { + const { id: sessionId, accountId } = await userSession.getOrCreate(); + if (sessionId) { + await syncOrganization(sessionId, accountId); const organizations = JSON.parse(localStorage.getItem(`${accountId}:organizations`) || '[]') as Organization[]; invariant(organizations, 'Failed to fetch organizations.'); @@ -214,36 +219,7 @@ export const syncOrganizationsAction: ActionFunction = async () => { const { id: sessionId, accountId } = await userSession.getOrCreate(); if (sessionId) { - try { - - const organizationsResult = await insomniaFetch({ - method: 'GET', - path: '/v1/organizations', - sessionId, - }); - - const user = await insomniaFetch({ - method: 'GET', - path: '/v1/user/profile', - sessionId, - }); - - const currentPlan = await insomniaFetch({ - method: 'GET', - path: '/v1/billing/current-plan', - sessionId, - }); - - invariant(organizationsResult, 'Failed to load organizations'); - invariant(user, 'Failed to load user'); - invariant(currentPlan, 'Failed to load current plan'); - invariant(accountId, 'Account ID is not defined'); - localStorage.setItem(`${accountId}:organizations`, JSON.stringify(sortOrganizations(accountId, organizationsResult.organizations))); - localStorage.setItem(`${accountId}:user`, JSON.stringify(user)); - localStorage.setItem(`${accountId}:currentPlan`, JSON.stringify(currentPlan)); - } catch (error) { - console.log('Failed to load Organizations', error); - } + await syncOrganization(sessionId, accountId); } return null; diff --git a/packages/insomnia/src/ui/routes/project.tsx b/packages/insomnia/src/ui/routes/project.tsx index 5fc1bfc8be78..9be29ba42683 100644 --- a/packages/insomnia/src/ui/routes/project.tsx +++ b/packages/insomnia/src/ui/routes/project.tsx @@ -315,21 +315,23 @@ async function getAllLocalFiles({ projectId: string; }) { const projectWorkspaces = await models.workspace.findByParentId(projectId); - const workspaceMetas = await database.find(models.workspaceMeta.type, { - parentId: { - $in: projectWorkspaces.map(w => w._id), - }, - }); - const apiSpecs = await database.find(models.apiSpec.type, { - parentId: { - $in: projectWorkspaces.map(w => w._id), - }, - }); - const mockServers = await database.find(models.mockServer.type, { - parentId: { - $in: projectWorkspaces.map(w => w._id), - }, - }); + const [workspaceMetas, apiSpecs, mockServers] = await Promise.all([ + database.find(models.workspaceMeta.type, { + parentId: { + $in: projectWorkspaces.map(w => w._id), + }, + }), + database.find(models.apiSpec.type, { + parentId: { + $in: projectWorkspaces.map(w => w._id), + }, + }), + database.find(models.mockServer.type, { + parentId: { + $in: projectWorkspaces.map(w => w._id), + }, + }), + ]); const files: InsomniaFile[] = projectWorkspaces.map(workspace => { const apiSpec = apiSpecs.find(spec => spec.parentId === workspace._id); @@ -416,9 +418,11 @@ async function getAllRemoteFiles({ invariant(remoteId, 'Project is not a remote project'); const vcs = VCSInstance(); - const allPulledBackendProjectsForRemoteId = (await vcs.localBackendProjects()).filter(p => p.id === remoteId); + const [allPulledBackendProjectsForRemoteId, allFetchedRemoteBackendProjectsForRemoteId] = await Promise.all([ + vcs.localBackendProjects().then(projects => projects.filter(p => p.id === remoteId)), // Remote backend projects are fetched from the backend since they are not stored locally - const allFetchedRemoteBackendProjectsForRemoteId = await vcs.remoteBackendProjects({ teamId: organizationId, teamProjectId: remoteId }); + vcs.remoteBackendProjects({ teamId: organizationId, teamProjectId: remoteId }), + ]); // Get all workspaces that are connected to backend projects and under the current project const workspacesWithBackendProjects = await database.find(models.workspace.type, { @@ -491,6 +495,37 @@ export const projectIdLoader: LoaderFunction = async ({ params }): Promise { + let learningFeature = fallbackLearningFeature; + const lastFetchedString = window.localStorage.getItem('learning-feature-last-fetch'); + const lastFetched = lastFetchedString ? parseInt(lastFetchedString, 10) : 0; + const oneDay = 86400000; + const hasOneDayPassedSinceLastFetch = (Date.now() - lastFetched) > oneDay; + const wasDismissed = window.localStorage.getItem('learning-feature-dismissed'); + const wasNotDismissedAndOneDayHasPassed = !wasDismissed && hasOneDayPassedSinceLastFetch; + if (wasNotDismissedAndOneDayHasPassed) { + try { + learningFeature = await insomniaFetch({ + method: 'GET', + path: '/insomnia-production-public-assets/inapp-learning.json', + origin: 'https://storage.googleapis.com', + sessionId: '', + }); + window.localStorage.setItem('learning-feature-last-fetch', Date.now().toString()); + } catch (err) { + console.log('Could not fetch learning feature data.'); + } + } + return learningFeature; +}; + export const loader: LoaderFunction = async ({ params, }): Promise => { @@ -528,43 +563,20 @@ export const loader: LoaderFunction = async ({ const project = await models.project.getById(projectId); invariant(project, `Project was not found ${projectId}`); - const localFiles = await getAllLocalFiles({ projectId }); - const remoteFiles = await getAllRemoteFiles({ projectId, organizationId }); - const files = [...localFiles, ...remoteFiles]; + const [localFiles, remoteFiles, organizationProjects = [], learningFeature] = await Promise.all([ + getAllLocalFiles({ projectId }), + getAllRemoteFiles({ projectId, organizationId }), + database.find(models.project.type, { + parentId: organizationId, + }), + getLearningFeature(fallbackLearningFeature), + ]); + console.log(localFiles); - const organizationProjects = await database.find(models.project.type, { - parentId: organizationId, - }) || []; + const files = [...localFiles, ...remoteFiles]; const projects = sortProjects(organizationProjects); - let learningFeature = fallbackLearningFeature; - const lastFetchedString = window.localStorage.getItem('learning-feature-last-fetch'); - const lastFetched = lastFetchedString ? parseInt(lastFetchedString, 10) : 0; - const oneDay = 86400000; - const hasOneDayPassedSinceLastFetch = (Date.now() - lastFetched) > oneDay; - const wasDismissed = window.localStorage.getItem('learning-feature-dismissed'); - const wasNotDismissedAndOneDayHasPassed = !wasDismissed && hasOneDayPassedSinceLastFetch; - if (wasNotDismissedAndOneDayHasPassed) { - try { - learningFeature = await insomniaFetch<{ - active: boolean; - title: string; - message: string; - cta: string; - url: string; - }>({ - method: 'GET', - path: '/insomnia-production-public-assets/inapp-learning.json', - origin: 'https://storage.googleapis.com', - sessionId: '', - }); - window.localStorage.setItem('learning-feature-last-fetch', Date.now().toString()); - } catch (err) { - console.log('Could not fetch learning feature data.'); - } - } - return { files, learningFeature,