From 39f5b9218e2858831a172460925f25f6ebae8298 Mon Sep 17 00:00:00 2001 From: archy Date: Thu, 26 Oct 2023 21:26:46 +0200 Subject: [PATCH] re-enable git && fix tests #68 #28 --- .../src/network/__tests__/network.test.ts | 6 +- packages/insomnia/src/sync/git/git-vcs.ts | 2 +- .../dropdowns/git-sync-dropdown.tsx | 561 ++++++++++++++++++ .../dropdowns/workspace-sync-dropdown.tsx | 95 +++ .../git-repo-clone-modal.tsx | 15 +- .../git-repository-settings-modal.tsx | 26 +- .../components/modals/git-staging-modal.tsx | 23 +- .../modals/workspace-settings-modal.tsx | 4 +- .../src/ui/components/panes/request-pane.tsx | 23 +- .../insomnia/src/ui/hooks/use-vcs-version.ts | 4 +- packages/insomnia/src/ui/routes/debug.tsx | 4 + packages/insomnia/src/ui/routes/design.tsx | 5 +- .../insomnia/src/ui/routes/git-actions.tsx | 24 +- packages/insomnia/src/ui/routes/unit-test.tsx | 1 + 14 files changed, 739 insertions(+), 54 deletions(-) create mode 100644 packages/insomnia/src/ui/components/dropdowns/git-sync-dropdown.tsx create mode 100644 packages/insomnia/src/ui/components/dropdowns/workspace-sync-dropdown.tsx diff --git a/packages/insomnia/src/network/__tests__/network.test.ts b/packages/insomnia/src/network/__tests__/network.test.ts index c6bc4f4e5..6dd51e7a9 100644 --- a/packages/insomnia/src/network/__tests__/network.test.ts +++ b/packages/insomnia/src/network/__tests__/network.test.ts @@ -138,7 +138,7 @@ describe('sendCurlAndWriteTimeline()', () => { PROXY: '', TIMEOUT_MS: 30000, URL: 'http://localhost/?foo%20bar=hello%26world', - USERAGENT: `insomnia/${version}`, + USERAGENT: `insomnium/${version}`, VERBOSE: true, }, }); @@ -309,7 +309,7 @@ describe('sendCurlAndWriteTimeline()', () => { PROXY: '', TIMEOUT_MS: 30000, URL: 'http://localhost/?foo%20bar=hello%26world', - USERAGENT: `insomnia/${version}`, + USERAGENT: `insomnium/${version}`, VERBOSE: true, }, }); @@ -741,7 +741,7 @@ describe('sendCurlAndWriteTimeline()', () => { SSL_VERIFYPEER: 0, // should disable SSL TIMEOUT_MS: 30000, URL: 'http://localhost/?foo%20bar=hello%26world', - USERAGENT: `insomnia/${version}`, + USERAGENT: `insomnium/${version}`, VERBOSE: true, }, }); diff --git a/packages/insomnia/src/sync/git/git-vcs.ts b/packages/insomnia/src/sync/git/git-vcs.ts index 1013b30c8..3cd75f906 100644 --- a/packages/insomnia/src/sync/git/git-vcs.ts +++ b/packages/insomnia/src/sync/git/git-vcs.ts @@ -87,7 +87,7 @@ interface InitFromCloneOptions { */ export const GIT_CLONE_DIR = '.'; const gitInternalDirName = 'git'; -export const GIT_INSOMNIA_DIR_NAME = '.insomnia'; +export const GIT_INSOMNIA_DIR_NAME = '.insomnium'; export const GIT_INTERNAL_DIR = path.join(GIT_CLONE_DIR, gitInternalDirName); export const GIT_INSOMNIA_DIR = path.join(GIT_CLONE_DIR, GIT_INSOMNIA_DIR_NAME); diff --git a/packages/insomnia/src/ui/components/dropdowns/git-sync-dropdown.tsx b/packages/insomnia/src/ui/components/dropdowns/git-sync-dropdown.tsx new file mode 100644 index 000000000..8c6f4c2a8 --- /dev/null +++ b/packages/insomnia/src/ui/components/dropdowns/git-sync-dropdown.tsx @@ -0,0 +1,561 @@ +import classnames from 'classnames'; +import React, { FC, Fragment, useEffect, useRef, useState } from 'react'; +import { useFetcher, useParams, useRevalidator } from 'react-router-dom'; +import { useInterval } from 'react-use'; + +import { docsGitSync } from '../../../common/documentation'; +import { GitRepository } from '../../../models/git-repository'; +import { deleteGitRepository } from '../../../models/helpers/git-repository-operations'; +import { getOauth2FormatName } from '../../../sync/git/utils'; +import { + GitFetchLoaderData, + GitRepoLoaderData, + GitStatusResult, + PullFromGitRemoteResult, + PushToGitRemoteResult, +} from '../../routes/git-actions'; +import { + Dropdown, + DropdownButton, + type DropdownHandle, + DropdownItem, + DropdownSection, + ItemContent, +} from '../base/dropdown'; +import { Link } from '../base/link'; +import { HelpTooltip } from '../help-tooltip'; +import { showAlert } from '../modals'; +import { GitBranchesModal } from '../modals/git-branches-modal'; +import { GitLogModal } from '../modals/git-log-modal'; +import { GitRepositorySettingsModal } from '../modals/git-repository-settings-modal'; +import { GitStagingModal } from '../modals/git-staging-modal'; +import { Button } from '../themed-button'; +import { Tooltip } from '../tooltip'; + +interface Props { + gitRepository: GitRepository | null; + className?: string; + isInsomniaSyncEnabled: boolean; +} + +export const GitSyncDropdown: FC = ({ className, gitRepository, isInsomniaSyncEnabled }) => { + const { organizationId, projectId, workspaceId } = useParams() as { + organizationId: string; + projectId: string; + workspaceId: string; + }; + const dropdownRef = useRef(null); + + const [isGitRepoSettingsModalOpen, setIsGitRepoSettingsModalOpen] = + useState(false); + const [isGitBranchesModalOpen, setIsGitBranchesModalOpen] = useState(false); + const [isGitLogModalOpen, setIsGitLogModalOpen] = useState(false); + const [isGitStagingModalOpen, setIsGitStagingModalOpen] = useState(false); + + const gitPushFetcher = useFetcher(); + const gitPullFetcher = useFetcher(); + const gitCheckoutFetcher = useFetcher(); + const gitRepoDataFetcher = useFetcher(); + const gitFetchFetcher = useFetcher(); + const gitStatusFetcher = useFetcher(); + + const loadingPush = gitPushFetcher.state === 'loading'; + const loadingPull = gitPullFetcher.state === 'loading'; + const loadingFetch = gitFetchFetcher.state === 'loading'; + const loadingStatus = gitStatusFetcher.state === 'loading'; + + useEffect(() => { + if ( + gitRepository?.uri && + gitRepository?._id && + gitRepoDataFetcher.state === 'idle' && + !gitRepoDataFetcher.data + ) { + console.log('[git:fetcher] Fetching git repo data'); + gitRepoDataFetcher.submit({}, { + action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/git/repo`, + method: 'post', + }); + } + }, [ + gitRepoDataFetcher, + gitRepository?.uri, + gitRepository?._id, + organizationId, + projectId, + workspaceId, + ]); + + // Only fetch the repo status if we have a repo uri and we don't have the status already + const shouldFetchGitRepoStatus = Boolean(gitRepository?.uri && gitRepository?._id && gitStatusFetcher.state === 'idle' && !gitStatusFetcher.data && gitRepoDataFetcher.data); + + useEffect(() => { + if (shouldFetchGitRepoStatus) { + console.log('[git:fetcher] Fetching git repo status'); + gitStatusFetcher.submit({}, { + action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/git/status`, + method: 'post', + }); + } + }, [gitStatusFetcher, organizationId, projectId, shouldFetchGitRepoStatus, workspaceId]); + + useEffect(() => { + const errors = [...(gitPushFetcher.data?.errors ?? [])]; + if (errors.length > 0) { + showAlert({ + title: 'Push Failed', + message: errors.join('\n'), + }); + } + }, [gitPushFetcher.data?.errors]); + + useEffect(() => { + const gitRepoDataErrors = + gitRepoDataFetcher.data && 'errors' in gitRepoDataFetcher.data + ? gitRepoDataFetcher.data.errors + : []; + const errors = [...gitRepoDataErrors]; + if (errors.length > 0) { + showAlert({ + title: 'Loading of Git Repository Failed', + message: errors.join('\n'), + }); + } + }, [gitRepoDataFetcher.data]); + + useEffect(() => { + const errors = [...(gitPullFetcher.data?.errors ?? [])]; + if (errors.length > 0) { + showAlert({ + title: 'Pull Failed', + message: errors.join('\n'), + }); + } + }, [gitPullFetcher.data?.errors]); + + useEffect(() => { + const errors = [...(gitCheckoutFetcher.data?.errors ?? [])]; + if (errors.length > 0) { + showAlert({ + title: 'Checkout Failed', + message: errors.join('\n'), + }); + } + }, [gitCheckoutFetcher.data?.errors]); + + async function handlePush({ force }: { force: boolean }) { + gitPushFetcher.submit( + { + force: `${force}`, + }, + { + action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/git/push`, + method: 'post', + } + ); + } + + let iconClassName = 'fa-brands fa-git-alt'; + const providerName = getOauth2FormatName(gitRepository?.credentials); + if (providerName === 'github') { + iconClassName = 'fa fa-github'; + } + if (providerName === 'gitlab') { + iconClassName = 'fa fa-gitlab'; + } + + const isLoading = + gitRepoDataFetcher.state === 'loading' || + gitFetchFetcher.state === 'loading' || + gitCheckoutFetcher.state === 'loading' || + gitPushFetcher.state === 'loading' || + gitPullFetcher.state === 'loading'; + + const isSynced = Boolean(gitRepository?.uri && gitRepoDataFetcher.data && !('errors' in gitRepoDataFetcher.data)); + + const { branches, branch: currentBranch } = + gitRepoDataFetcher.data && 'branches' in gitRepoDataFetcher.data + ? gitRepoDataFetcher.data + : { branches: [], branch: '' }; + + let dropdown: React.ReactNode = null; + const { revalidate } = useRevalidator(); + + const currentBranchActions = [ + { + id: 1, + icon: 'check', + label: 'Commit', + onClick: () => setIsGitStagingModalOpen(true), + }, + { + id: 2, + stayOpenAfterClick: true, + icon: loadingPull ? 'refresh fa-spin' : 'cloud-download', + label: 'Pull', + onClick: async () => { + gitPullFetcher.submit( + {}, + { + action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/git/pull`, + method: 'post', + } + ); + }, + }, + { + id: 3, + stayOpenAfterClick: true, + icon: loadingPush ? 'refresh fa-spin' : 'cloud-upload', + label: 'Push', + onClick: () => handlePush({ force: false }), + }, + { + id: 4, + icon: 'clock-o', + label: History, + onClick: () => setIsGitLogModalOpen(true), + }, + { + id: 5, + stayOpenAfterClick: true, + icon: loadingFetch ? 'refresh fa-spin' : 'refresh', + label: 'Fetch', + onClick: () => { + gitFetchFetcher.submit( + {}, + { + action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/git/fetch`, + method: 'post', + } + ); + }, + }, + ]; + + useInterval(() => { + gitFetchFetcher.submit( + {}, + { + action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/git/fetch`, + method: 'post', + } + ); + }, 1000 * 60 * 5); + + const status = gitStatusFetcher.data?.status; + + const commitToolTipMsg = status?.localChanges ? 'Local changes made' : 'No local changes made'; + + if (isSynced) { + dropdown = ( +
+ +
+ {iconClassName && ( + + )} +
{currentBranch}
+ +
+ + + +
+
+ + + } + > + + {item => ( + + + + )} + + + Git Sync + + Sync and collaborate with Git{' '} + + +
+ Documentation +
+ +
+ + } + > + + { + setIsGitRepoSettingsModalOpen(true); + }} + /> + + + + {currentBranch && ( + { + setIsGitBranchesModalOpen(true); + }} + /> + )} + +
+ + ({ branch: b })) : []} + > + {({ branch }) => { + const isCurrentBranch = branch === currentBranch; + + return ( + + { + gitCheckoutFetcher.submit( + { + branch, + }, + { + action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/git/branch/checkout`, + method: 'post', + } + ); + }} + /> + + ); + }} + + + + {({ id, ...action }) => ( + + + + )} + +
+
+ ); + } else { + dropdown = ( +
+ +
+ {iconClassName && ( + + )} + Git Sync +
+ + + } + > + + {item => ( + + + + )} + + + Git Sync + + Sync and collaborate with Git{' '} + + +
+ Documentation +
+ +
+ + } + > + + { + setIsGitRepoSettingsModalOpen(true); + }} + /> + +
+
+
+ ); + } + + return ( + + {dropdown} + {isGitRepoSettingsModalOpen && ( + setIsGitRepoSettingsModalOpen(false)} + /> + )} + {isGitBranchesModalOpen && ( + setIsGitBranchesModalOpen(false)} + /> + )} + {isGitLogModalOpen && ( + setIsGitLogModalOpen(false)} + /> + )} + {isGitStagingModalOpen && ( + setIsGitStagingModalOpen(false)} /> + )} + + ); +}; diff --git a/packages/insomnia/src/ui/components/dropdowns/workspace-sync-dropdown.tsx b/packages/insomnia/src/ui/components/dropdowns/workspace-sync-dropdown.tsx new file mode 100644 index 000000000..e695a5f5d --- /dev/null +++ b/packages/insomnia/src/ui/components/dropdowns/workspace-sync-dropdown.tsx @@ -0,0 +1,95 @@ +import { FC, useEffect, useRef, useState } from 'react'; +import React from 'react'; +import { useRouteLoaderData } from 'react-router-dom'; + +import { generateId } from '../../../common/misc'; +import { isRemoteProject } from '../../../models/project'; +import FileSystemDriver from '../../../sync/store/drivers/file-system-driver'; +import { MergeConflict } from '../../../sync/types'; +import { getVCS, initVCS, VCS } from '../../../sync/vcs/vcs'; +import { WorkspaceLoaderData } from '../../routes/workspace'; +import { showModal } from '../modals'; +import { SyncMergeModal } from '../modals/sync-merge-modal'; +import { GitSyncDropdown } from './git-sync-dropdown'; +// import { SyncDropdown } from './sync-dropdown'; + +export function useVCS({ + workspaceId, +}: { + workspaceId?: string; +}) { + const [vcs, setVCS] = useState(null); + const updateVCSLock = useRef(false); + + // Update VCS when the active workspace changes + useEffect(() => { + const lock = generateId(); + updateVCSLock.current = lock; + + // Set vcs to null while we update it + setVCS(null); + + async function updateVCS() { + let vcsInstance = getVCS(); + if (!vcsInstance) { + const driver = FileSystemDriver.create(process.env['INSOMNIA_DATA_PATH'] || window.app.getPath('userData')); + + vcsInstance = await initVCS(driver, async conflicts => { + return new Promise(resolve => { + showModal(SyncMergeModal, { + conflicts, + handleDone: (conflicts?: MergeConflict[]) => resolve(conflicts || []), + }); + }); + }); + } + + if (workspaceId) { + await vcsInstance.switchProject(workspaceId); + } else { + await vcsInstance.clearBackendProject(); + } + + // Prevent a potential race-condition when _updateVCS() gets called for different workspaces in rapid succession + if (updateVCSLock.current === lock) { + setVCS(vcsInstance); + } + } + + updateVCS(); + }, [workspaceId]); + + return vcs; +} + +export const WorkspaceSyncDropdown: FC = () => { + const { + activeProject, + activeWorkspace, + gitRepository, + activeWorkspaceMeta, + } = useRouteLoaderData( + ':workspaceId' + ) as WorkspaceLoaderData; + + // const vcs = useVCS({ + // workspaceId: activeWorkspace?._id, + // }); + + // if (isRemoteProject(activeProject) && vcs && !activeWorkspaceMeta?.gitRepositoryId) { + // return ( + // + // ); + // } + + // if (activeWorkspaceMeta?.gitRepositoryId || !isRemoteProject(activeProject)) { + return ; + // } + + return null; +}; diff --git a/packages/insomnia/src/ui/components/modals/git-repository-settings-modal/git-repo-clone-modal.tsx b/packages/insomnia/src/ui/components/modals/git-repository-settings-modal/git-repo-clone-modal.tsx index f6dd16de6..38983468b 100644 --- a/packages/insomnia/src/ui/components/modals/git-repository-settings-modal/git-repo-clone-modal.tsx +++ b/packages/insomnia/src/ui/components/modals/git-repository-settings-modal/git-repo-clone-modal.tsx @@ -90,20 +90,7 @@ export const GitRepositoryCloneModal = (props: ModalProps) => { selectedKey={selectedTab} onSelectionChange={(key: Key) => setTab(key as OauthProviderName)} > - GitHub}> - - - - - GitLab}> - - - - + Git}> ('github'); + const [selectedTab, setTab] = useState('custom'); useEffect(() => { modalRef.current?.show(); @@ -84,12 +84,8 @@ export const GitRepositorySettingsModal = (props: ModalProps & { - Repository Settings{' '} - - Sync and collaborate with Git -
- Documentation {} -
+ Git Settings +
@@ -99,22 +95,6 @@ export const GitRepositorySettingsModal = (props: ModalProps & { selectedKey={selectedTab} onSelectionChange={(key: Key) => setTab(key as OauthProviderName)} > - GitHub}> - - - - - GitLab}> - - - - Git}> = ({ } }, [errors]); + const [hasDone, setHasDone] = useState(false) + return ( @@ -85,9 +87,22 @@ export const GitStagingModal: FC = ({ { + e.preventDefault(); + if (formRef.current) { + const data = new FormData(formRef.current); + data.append('changeType', 'modified'); + const res = await gitCommitFetcher.submit(data, { + action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/git/commit`, + method: 'post', + }); + setHasDone(true) + + } + }} > {hasChanges ? ( <> @@ -318,7 +333,7 @@ export const GitStagingModal: FC = ({
{isLoadingGitChanges ? <> - Loading changes... : 'No changes to commit.'} + Loading changes... : errors && errors?.length > 0 ? "network error.." : hasDone ? "Commited. Ready to push" : 'No new changes to commit.'}
)}
diff --git a/packages/insomnia/src/ui/components/modals/workspace-settings-modal.tsx b/packages/insomnia/src/ui/components/modals/workspace-settings-modal.tsx index a04da1a7e..9fcbb96ef 100644 --- a/packages/insomnia/src/ui/components/modals/workspace-settings-modal.tsx +++ b/packages/insomnia/src/ui/components/modals/workspace-settings-modal.tsx @@ -502,7 +502,7 @@ export const WorkspaceSettingsModal = ({ workspace, workspaceMeta, clientCertifi )}
- + {/*
-
+
*/}
: null}
diff --git a/packages/insomnia/src/ui/components/panes/request-pane.tsx b/packages/insomnia/src/ui/components/panes/request-pane.tsx index 7a0121e52..df3e9b60a 100644 --- a/packages/insomnia/src/ui/components/panes/request-pane.tsx +++ b/packages/insomnia/src/ui/components/panes/request-pane.tsx @@ -1,5 +1,5 @@ import React, { FC, useState } from 'react'; -import { useParams, useRouteLoaderData } from 'react-router-dom'; +import { useFetcher, useParams, useRouteLoaderData } from 'react-router-dom'; import styled from 'styled-components'; import { getContentTypeFromHeaders } from '../../../common/constants'; @@ -31,6 +31,7 @@ import { RequestUrlBar } from '../request-url-bar'; import { Pane, PaneHeader } from './pane'; import { PlaceholderRequestPane } from './placeholder-request-pane'; import { RequestSegmentEditor } from '../editors/request-segment-editor'; +import { GitRepoLoaderData } from '../../routes/git-actions'; const HeaderContainer = styled.div({ display: 'flex', flexDirection: 'column', @@ -102,6 +103,26 @@ export const RequestPane: FC = ({ } }; const gitVersion = useGitVCSVersion(); + + // const { + // activeProject, + // activeWorkspace, + // gitRepository, + // activeWorkspaceMeta, + // } = useRouteLoaderData( + // ':workspaceId' + // ) as WorkspaceLoaderData; + + // const gitRepoDataFetcher = useFetcher(); + // alert(gitVersion) + // const { branches, branch: currentBranch } = + // gitRepoDataFetcher.data && 'branches' in gitRepoDataFetcher.data + // ? gitRepoDataFetcher.data + // : { branches: [], branch: '' }; + + console.log("gitVersion ->", gitVersion); + + const activeRequestSyncVersion = useActiveRequestSyncVCSVersion(); const { activeEnvironment } = useRouteLoaderData( diff --git a/packages/insomnia/src/ui/hooks/use-vcs-version.ts b/packages/insomnia/src/ui/hooks/use-vcs-version.ts index 1e17c11b1..a358cf91e 100644 --- a/packages/insomnia/src/ui/hooks/use-vcs-version.ts +++ b/packages/insomnia/src/ui/hooks/use-vcs-version.ts @@ -13,6 +13,7 @@ export function useActiveRequestSyncVCSVersion() { useEffect(() => { const isRequestUpdatedFromSync = (changes: ChangeBufferEvent[]) => changes.find(([, doc, fromSync]) => requestId === doc._id && fromSync); + database.onChange(changes => isRequestUpdatedFromSync(changes) && setVersion(v => v + 1)); }, [requestId]); @@ -40,5 +41,6 @@ export function useGitVCSVersion() { const { activeWorkspaceMeta, } = useRouteLoaderData(':workspaceId') as WorkspaceLoaderData; - return ((activeWorkspaceMeta?.cachedGitLastCommitTime + '') + activeWorkspaceMeta?.cachedGitRepositoryBranch) + ''; + return activeWorkspaceMeta?.cachedGitLastCommitTime + } diff --git a/packages/insomnia/src/ui/routes/debug.tsx b/packages/insomnia/src/ui/routes/debug.tsx index bfb4c7f0d..5167c6472 100644 --- a/packages/insomnia/src/ui/routes/debug.tsx +++ b/packages/insomnia/src/ui/routes/debug.tsx @@ -87,6 +87,7 @@ import { } from './request'; import { RootLoaderData } from './root'; import { Child, WorkspaceLoaderData } from './workspace'; +import { WorkspaceSyncDropdown } from '../components/dropdowns/workspace-sync-dropdown'; export interface GrpcMessage { id: string; @@ -1003,6 +1004,9 @@ export const Debug: FC = () => { + + + {isEnvironmentModalOpen && ( setEnvironmentModalOpen(false)} diff --git a/packages/insomnia/src/ui/routes/design.tsx b/packages/insomnia/src/ui/routes/design.tsx index 58bbe666d..ca766e9f3 100644 --- a/packages/insomnia/src/ui/routes/design.tsx +++ b/packages/insomnia/src/ui/routes/design.tsx @@ -34,6 +34,7 @@ import { useActiveApiSpecSyncVCSVersion, useGitVCSVersion, } from '../hooks/use-vcs-version'; +import { WorkspaceSyncDropdown } from '../components/dropdowns/workspace-sync-dropdown'; const EmptySpaceHelper = styled.div({ display: 'flex', alignItems: 'flex-start', @@ -260,7 +261,7 @@ const Design: FC = () => { gridRowStart: 6, }} > - no sync desu + ) : ( @@ -271,7 +272,7 @@ const Design: FC = () => { gridRowStart: 6, }} > - no sync desu + ) diff --git a/packages/insomnia/src/ui/routes/git-actions.tsx b/packages/insomnia/src/ui/routes/git-actions.tsx index 249b1d9ae..4f8cf9dc8 100644 --- a/packages/insomnia/src/ui/routes/git-actions.tsx +++ b/packages/insomnia/src/ui/routes/git-actions.tsx @@ -1,5 +1,5 @@ import { fromUrl } from 'hosted-git-info'; -import { Errors } from 'isomorphic-git'; +import { Errors, clone } from 'isomorphic-git'; import path from 'path'; import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom'; import YAML from 'yaml'; @@ -36,6 +36,7 @@ import { getOauth2FormatName, } from '../../sync/git/utils'; import { guard } from '../../utils/guard'; +import electron from 'electron'; // Loaders export type GitRepoLoaderData = @@ -976,12 +977,12 @@ export const pushToGitRemoteAction: ActionFunction = async ({ if (err instanceof Errors.PushRejectedError) { return { - errors: [`Push Rejected, ${errorMessage}`], + errors: [`Push Rejected, ${errorMessage}` + `\n recommendation: use git inside terminal to resolve this.`], }; } return { - errors: [`Error Pushing Repository, ${errorMessage}`], + errors: [`Error Pushing Repository, ${errorMessage}` + `\n recommendation: use git inside terminal to resolve this.`], }; } @@ -1022,10 +1023,14 @@ export const pullFromGitRemoteAction: ActionFunction = async ({ depth: 1, credentials: gitRepository?.credentials, }); + } catch (e) { console.warn('Error fetching from remote', e); } + + + try { await GitVCS.pull(gitRepository.credentials); @@ -1040,6 +1045,19 @@ export const pullFromGitRemoteAction: ActionFunction = async ({ }; } + if (workspaceMeta) { + const log = (await GitVCS.log({ depth: 1 })) || []; + + const author = log[0] ? log[0].commit.author : null; + const cachedGitLastCommitTime = author ? author.timestamp * 1000 : null; + console.log("gitV cachedGitLastCommitTime", cachedGitLastCommitTime); + + await models.workspaceMeta.update(workspaceMeta, { + cachedGitLastCommitTime, + cachedGitLastAuthor: author?.name || null, + }); + } + await database.flushChanges(bufferId); return {}; diff --git a/packages/insomnia/src/ui/routes/unit-test.tsx b/packages/insomnia/src/ui/routes/unit-test.tsx index e076016ca..7ff51f96f 100644 --- a/packages/insomnia/src/ui/routes/unit-test.tsx +++ b/packages/insomnia/src/ui/routes/unit-test.tsx @@ -22,6 +22,7 @@ import { SidebarFooter, SidebarLayout } from '../components/sidebar-layout'; import { Button } from '../components/themed-button'; import { TestRunStatus } from './test-results'; import TestSuiteRoute from './test-suite'; +import { WorkspaceSyncDropdown } from '../components/dropdowns/workspace-sync-dropdown'; interface LoaderData { unitTestSuites: UnitTestSuite[];