diff --git a/packages/insomnia/src/models/git-repository.ts b/packages/insomnia/src/models/git-repository.ts index 6e0a89da0..5b1e72112 100644 --- a/packages/insomnia/src/models/git-repository.ts +++ b/packages/insomnia/src/models/git-repository.ts @@ -2,6 +2,8 @@ import { database as db } from '../common/database'; import type { GitCredentials } from '../sync/git/git-vcs'; import type { BaseModel } from './index'; +export type OauthProviderName = 'gitlab' | 'github' | 'custom'; + export type GitRepository = BaseModel & BaseGitRepository; export const name = 'Git Repository'; diff --git a/packages/insomnia/src/sync/git/utils.ts b/packages/insomnia/src/sync/git/utils.ts index 1a20e01fb..3ade88d5d 100644 --- a/packages/insomnia/src/sync/git/utils.ts +++ b/packages/insomnia/src/sync/git/utils.ts @@ -1,5 +1,6 @@ import { AuthCallback, AuthFailureCallback, AuthSuccessCallback, GitAuth, MessageCallback } from 'isomorphic-git'; +import { OauthProviderName } from '../../models/git-repository'; import type { GitCredentials } from './git-vcs'; import { getAccessToken as getGitHubAccessToken } from './github-oauth-provider'; import { getAccessToken as getGitlabAccessToken, refreshToken as refreshGitlabToken } from './gitlab-oauth-provider'; @@ -95,6 +96,14 @@ const onAuth = (credentials?: GitCredentials): AuthCallback => (): GitAuth => { }; }; +export const getOauth2FormatName = (credentials?: GitCredentials | null): OauthProviderName | undefined => { + if (credentials && 'oauth2format' in credentials) { + return credentials.oauth2format; + } + + return; +}; + export const gitCallbacks = (credentials?: GitCredentials | null) => ({ onMessage, onAuthFailure: onAuthFailure(credentials ?? undefined), diff --git a/packages/insomnia/src/ui/components/dropdowns/git-sync-dropdown.tsx b/packages/insomnia/src/ui/components/dropdowns/git-sync-dropdown.tsx index 31828a71c..adf8b6296 100644 --- a/packages/insomnia/src/ui/components/dropdowns/git-sync-dropdown.tsx +++ b/packages/insomnia/src/ui/components/dropdowns/git-sync-dropdown.tsx @@ -14,6 +14,7 @@ import type { GitRepository } from '../../../models/git-repository'; import type { Workspace } from '../../../models/workspace'; import type { GitLogEntry, GitVCS } from '../../../sync/git/git-vcs'; import { MemClient } from '../../../sync/git/mem-client'; +import { getOauth2FormatName } from '../../../sync/git/utils'; import { initialize as initializeEntities } from '../../redux/modules/entities'; import type { SetupGitRepositoryCallback, @@ -126,10 +127,10 @@ class GitSyncDropdown extends PureComponent { } const bufferId = await db.bufferChanges(); - + const providerName = getOauth2FormatName(gitRepository.credentials); try { await vcs.pull(gitRepository.credentials); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', 'pull')); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', 'pull'), providerName }); } catch (err) { showError({ title: 'Error Pulling Repository', @@ -184,10 +185,10 @@ class GitSyncDropdown extends PureComponent { } const bufferId = await db.bufferChanges(); - + const providerName = getOauth2FormatName(gitRepository.credentials); try { await vcs.push(gitRepository.credentials, force); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', force ? 'force_push' : 'push')); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', force ? 'force_push' : 'push'), providerName }); } catch (err) { if (err.code === 'PushRejectedError') { this._dropdown?.hide(); @@ -205,7 +206,7 @@ class GitSyncDropdown extends PureComponent { title: 'Error Pushing Repository', error: err, }); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', force ? 'force_push' : 'push', err.message)); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', force ? 'force_push' : 'push', err.message), providerName }); } } @@ -235,8 +236,10 @@ class GitSyncDropdown extends PureComponent { } async _handleCommit() { + const { gitRepository } = this.props; showModal(GitStagingModal, { onCommit: this._refreshState, + gitRepository, }); } diff --git a/packages/insomnia/src/ui/components/modals/git-branches-modal.tsx b/packages/insomnia/src/ui/components/modals/git-branches-modal.tsx index d535ad57c..a4fdfc6ae 100644 --- a/packages/insomnia/src/ui/components/modals/git-branches-modal.tsx +++ b/packages/insomnia/src/ui/components/modals/git-branches-modal.tsx @@ -7,6 +7,7 @@ import { AUTOBIND_CFG } from '../../../common/constants'; import { database as db } from '../../../common/database'; import type { GitRepository } from '../../../models/git-repository'; import { GitVCS } from '../../../sync/git/git-vcs'; +import { getOauth2FormatName } from '../../../sync/git/utils'; import { initialize as initializeEntities } from '../../redux/modules/entities'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; @@ -111,10 +112,11 @@ export class GitBranchesModal extends PureComponent { async _handleCreate(e: React.SyntheticEvent) { e.preventDefault(); await this._errorHandler(async () => { - const { vcs } = this.props; + const { vcs, gitRepository } = this.props; const { newBranchName } = this.state; + const providerName = getOauth2FormatName(gitRepository.credentials); await vcs.checkout(newBranchName); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', 'create_branch')); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', 'create_branch'), providerName }); await this._refreshState({ newBranchName: '', }); @@ -123,19 +125,21 @@ export class GitBranchesModal extends PureComponent { async _handleMerge(branch: string) { await this._errorHandler(async () => { - const { vcs } = this.props; + const { vcs, gitRepository } = this.props; + const providerName = getOauth2FormatName(gitRepository.credentials); await vcs.merge(branch); // Apparently merge doesn't update the working dir so need to checkout too await this._handleCheckout(branch); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', 'merge_branch')); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', 'merge_branch'), providerName }); }); } async _handleDelete(branch: string) { await this._errorHandler(async () => { - const { vcs } = this.props; + const { vcs, gitRepository } = this.props; + const providerName = getOauth2FormatName(gitRepository.credentials); await vcs.deleteBranch(branch); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', 'delete_branch')); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', 'delete_branch'), providerName }); await this._refreshState(); }); } @@ -151,10 +155,11 @@ export class GitBranchesModal extends PureComponent { async _handleCheckout(branch: string) { await this._errorHandler(async () => { - const { vcs, handleInitializeEntities } = this.props; + const { vcs, gitRepository, handleInitializeEntities } = this.props; const bufferId = await db.bufferChanges(); + const providerName = getOauth2FormatName(gitRepository.credentials); await vcs.checkout(branch); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', 'checkout_branch')); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', 'checkout_branch'), providerName }); await db.flushChanges(bufferId, true); await handleInitializeEntities(); await this._refreshState(); diff --git a/packages/insomnia/src/ui/components/modals/git-repository-settings-modal/git-repository-settings-modal.tsx b/packages/insomnia/src/ui/components/modals/git-repository-settings-modal/git-repository-settings-modal.tsx index 7f3dfec76..639ce1f79 100644 --- a/packages/insomnia/src/ui/components/modals/git-repository-settings-modal/git-repository-settings-modal.tsx +++ b/packages/insomnia/src/ui/components/modals/git-repository-settings-modal/git-repository-settings-modal.tsx @@ -4,7 +4,7 @@ import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; import { AUTOBIND_CFG } from '../../../../common/constants'; import { docsGitSync } from '../../../../common/documentation'; -import type { GitRepository } from '../../../../models/git-repository'; +import type { GitRepository, OauthProviderName } from '../../../../models/git-repository'; import { deleteGitRepository } from '../../../../models/helpers/git-repository-operations'; import { Link } from '../../base/link'; import { Modal } from '../../base/modal'; @@ -88,7 +88,7 @@ interface Props { onReset: () => void; } -const oauth2Formats = ['github', 'gitlab', 'custom']; +const oauth2Formats: OauthProviderName[] = ['github', 'gitlab', 'custom']; const ModalForm = (props: Props) => { const { gitRepository, onSubmit, onReset } = props; @@ -102,7 +102,7 @@ const ModalForm = (props: Props) => { const initialTab = !gitRepository ? 'github' : oauth2format; - const [selectedTab, setTab] = useState(initialTab); + const [selectedTab, setTab] = useState(initialTab); const selectedTabIndex = oauth2Formats.indexOf(selectedTab); return ( diff --git a/packages/insomnia/src/ui/components/modals/git-staging-modal.tsx b/packages/insomnia/src/ui/components/modals/git-staging-modal.tsx index 3c8d8c4e2..0ce68434c 100644 --- a/packages/insomnia/src/ui/components/modals/git-staging-modal.tsx +++ b/packages/insomnia/src/ui/components/modals/git-staging-modal.tsx @@ -10,10 +10,12 @@ import { database as db } from '../../../common/database'; import { strings } from '../../../common/strings'; import * as models from '../../../models'; import { isApiSpec } from '../../../models/api-spec'; +import { GitRepository } from '../../../models/git-repository'; import type { Workspace } from '../../../models/workspace'; import { gitRollback } from '../../../sync/git/git-rollback'; import { GIT_INSOMNIA_DIR, GIT_INSOMNIA_DIR_NAME, GitVCS } from '../../../sync/git/git-vcs'; import parseGitPath from '../../../sync/git/parse-git-path'; +import { getOauth2FormatName } from '../../../sync/git/utils'; import { IndeterminateCheckbox } from '../base/indeterminate-checkbox'; import { Modal } from '../base/modal'; import { ModalBody } from '../base/modal-body'; @@ -34,6 +36,7 @@ interface Item { interface Props { workspace: Workspace; vcs: GitVCS; + gitRepository: GitRepository | null; } interface State { @@ -78,7 +81,7 @@ export class GitStagingModal extends PureComponent { } async _handleCommit() { - const { vcs } = this.props; + const { vcs, gitRepository } = this.props; const { items, message } = this.state; // Set the stage @@ -97,7 +100,8 @@ export class GitStagingModal extends PureComponent { } await vcs.commit(message); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', 'commit')); + const providerName = getOauth2FormatName(gitRepository?.credentials); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', 'commit'), providerName }); this.modal?.hide(); if (typeof this.onCommit === 'function') { @@ -122,7 +126,8 @@ export class GitStagingModal extends PureComponent { newItems[p].staged = doStage || forceAdd; } - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', doStage ? 'stage_all' : 'unstage_all')); + const providerName = getOauth2FormatName(this.props.gitRepository?.credentials); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', doStage ? 'stage_all' : 'unstage_all'), providerName }); this.setState({ items: newItems, }); @@ -137,7 +142,9 @@ export class GitStagingModal extends PureComponent { } newItems[gitPath].staged = !newItems[gitPath].staged; - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', newItems[gitPath].staged ? 'stage' : 'unstage')); + + const providerName = getOauth2FormatName(this.props.gitRepository?.credentials); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', newItems[gitPath].staged ? 'stage' : 'unstage'), providerName }); this.setState({ items: newItems, }); @@ -312,12 +319,16 @@ export class GitStagingModal extends PureComponent { async _handleRollbackSingle(item: Item) { await this._handleRollback([item]); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', 'rollback')); + + const providerName = getOauth2FormatName(this.props.gitRepository?.credentials); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', 'rollback'), providerName }); } async _handleRollbackAll(items: Item[]) { await this._handleRollback(items); - trackSegmentEvent(SegmentEvent.vcsAction, vcsSegmentEventProperties('git', 'rollback_all')); + + const providerName = getOauth2FormatName(this.props.gitRepository?.credentials); + trackSegmentEvent(SegmentEvent.vcsAction, { ...vcsSegmentEventProperties('git', 'rollback_all'), providerName }); } renderItem(item: Item) { diff --git a/packages/insomnia/src/ui/components/wrapper.tsx b/packages/insomnia/src/ui/components/wrapper.tsx index 251e2e8aa..c223cb4f6 100644 --- a/packages/insomnia/src/ui/components/wrapper.tsx +++ b/packages/insomnia/src/ui/components/wrapper.tsx @@ -585,7 +585,7 @@ export class Wrapper extends PureComponent { {activeWorkspace && gitVCS ? ( - + {activeGitRepository !== null && ( { + const providerName = getOauth2FormatName(gitRepository.credentials); return () => { - trackSegmentEvent(SegmentEvent.vcsSyncStart, vcsSegmentEventProperties('git', 'update')); + trackSegmentEvent(SegmentEvent.vcsSyncStart, { ...vcsSegmentEventProperties('git', 'update'), providerName }); showModal(GitRepositorySettingsModal, { gitRepository, onSubmitEdits: async gitRepoPatch => { await models.gitRepository.update(gitRepository, gitRepoPatch); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'update')); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'update'), providerName }); }, }); }; @@ -52,7 +53,9 @@ export const setupGitRepository: SetupGitRepositoryCallback = ({ createFsClient, trackSegmentEvent(SegmentEvent.vcsSyncStart, vcsSegmentEventProperties('git', 'setup')); showModal(GitRepositorySettingsModal, { gitRepository: null, - onSubmitEdits: async gitRepoPatch => { + onSubmitEdits: async (gitRepoPatch: GitRepository) => { + const providerName = getOauth2FormatName(gitRepoPatch.credentials); + dispatch(loadStart()); try { @@ -70,7 +73,7 @@ export const setupGitRepository: SetupGitRepositoryCallback = ({ createFsClient, message: err.message, error: err, }); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'setup', err.message)); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'setup', err.message), providerName }); return; } @@ -85,15 +88,15 @@ export const setupGitRepository: SetupGitRepositoryCallback = ({ createFsClient, message: 'This repository is already connected to Insomnia; try creating a clone from the dashboard instead.', }); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'setup', 'existing insomnia data')); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'setup', 'existing insomnia data'), providerName }); return; } } await createGitRepository(workspace._id, gitRepoPatch); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'setup')); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'setup'), providerName }); } catch (err) { - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'setup', err.message)); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'setup', err.message), providerName }); } finally { dispatch(loadStop()); } @@ -166,6 +169,7 @@ export const cloneGitRepository = ({ createFsClient }: { repoSettingsPatch.uri = translateSSHtoHTTP(repoSettingsPatch.uri); let fsClient = createFsClient(); + const providerName = getOauth2FormatName(repoSettingsPatch.credentials); try { await shallowClone({ fsClient, @@ -178,7 +182,7 @@ export const cloneGitRepository = ({ createFsClient }: { message: originalUriError.message, }); dispatch(loadStop()); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'clone', originalUriError.message)); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'clone', originalUriError.message), providerName }); return; } @@ -198,7 +202,7 @@ export const cloneGitRepository = ({ createFsClient }: { message: `Failed to clone with original url (${repoSettingsPatch.uri}): ${originalUriError.message};\n\nAlso failed to clone with \`.git\` suffix added (${dotGitUri}): ${dotGitError.message}`, }); dispatch(loadStop()); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'clone', dotGitError.message)); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'clone', dotGitError.message), providerName }); return; } } @@ -207,7 +211,7 @@ export const cloneGitRepository = ({ createFsClient }: { if (!(await containsInsomniaWorkspaceDir(fsClient))) { dispatch(noDocumentFound(repoSettingsPatch)); dispatch(loadStop()); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'clone', 'no directory found')); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'clone', 'no directory found'), providerName }); return; } @@ -217,14 +221,14 @@ export const cloneGitRepository = ({ createFsClient }: { if (workspaces.length === 0) { dispatch(noDocumentFound(repoSettingsPatch)); dispatch(loadStop()); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'clone', 'no workspaces found')); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'clone', 'no workspaces found'), providerName }); return; } if (workspaces.length > 1) { cloneProblem('Multiple workspaces found in repository; expected one.'); dispatch(loadStop()); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'clone', 'multiple workspaces found')); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'clone', 'multiple workspaces found'), providerName }); return; } @@ -243,7 +247,7 @@ export const cloneGitRepository = ({ createFsClient }: { , ); dispatch(loadStop()); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'clone', 'workspace already exists')); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'clone', 'workspace already exists'), providerName }); return; } @@ -286,7 +290,7 @@ export const cloneGitRepository = ({ createFsClient }: { // Flush DB changes await db.flushChanges(bufferId); dispatch(loadStop()); - trackSegmentEvent(SegmentEvent.vcsSyncComplete, vcsSegmentEventProperties('git', 'clone')); + trackSegmentEvent(SegmentEvent.vcsSyncComplete, { ...vcsSegmentEventProperties('git', 'clone'), providerName }); }, }); },